SCCS-vsn: usr.bin/xinstall/xinstall.c 5.25
SCCS-vsn: usr.bin/xinstall/install.1 6.12
.\"
.\" %sccs.include.redist.roff%
.\"
.\"
.\" %sccs.include.redist.roff%
.\"
-.\" @(#)install.1 6.11 (Berkeley) %G%
+.\" @(#)install.1 6.12 (Berkeley) %G%
.Bl -tag -width Ds
.It Fl m
Specify an alternate mode.
.Bl -tag -width Ds
.It Fl m
Specify an alternate mode.
-The default mode is set to 755.
+The default mode is set to 755 (rwxr-xr-x).
The specified mode may be either an octal or symbolic value; see
.Xr chmod 1
for a description of possible mode values.
The specified mode may be either an octal or symbolic value; see
.Xr chmod 1
for a description of possible mode values.
number of systems and binary types.
.El
.Pp
number of systems and binary types.
.El
.Pp
-.Nm Install
-refuses to move a file onto itself.
+The
+.Nm install
+utility attempts to prevent moving a file onto itself.
+.Pp
+The
+.Nm install
+utility always attempts to preserve the file flags.
.Pp
Installing
.Pa /dev/null
.Pp
Installing
.Pa /dev/null
Upon successful completion a value of 0 is returned.
Otherwise, a value of 1 is returned.
.Sh SEE ALSO
Upon successful completion a value of 0 is returned.
Otherwise, a value of 1 is returned.
.Sh SEE ALSO
.Xr chgrp 1 ,
.Xr chmod 1 ,
.Xr cp 1 ,
.Xr mv 1 ,
.Xr strip 1 ,
.Xr chgrp 1 ,
.Xr chmod 1 ,
.Xr cp 1 ,
.Xr mv 1 ,
.Xr strip 1 ,
.Xr chown 8
.Sh HISTORY
The
.Xr chown 8
.Sh HISTORY
The
#endif /* not lint */
#ifndef lint
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)xinstall.c 5.24 (Berkeley) %G%";
+static char sccsid[] = "@(#)xinstall.c 5.25 (Berkeley) %G%";
#endif /* not lint */
#include <sys/param.h>
#endif /* not lint */
#include <sys/param.h>
#include <grp.h>
#include <pwd.h>
#include <grp.h>
#include <pwd.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <stdio.h>
#include <ctype.h>
#include <paths.h>
#include "pathnames.h"
#include <paths.h>
#include "pathnames.h"
-static struct passwd *pp;
-static struct group *gp;
-static int docopy, dostrip, mode = 0755;
-static char *group, *owner, pathbuf[MAXPATHLEN];
+struct passwd *pp;
+struct group *gp;
+int docopy, dostrip;
+int mode = S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
+char *group, *owner, pathbuf[MAXPATHLEN];
+
+void copy __P((int, char *, int, char *));
+void err __P((const char *, ...));
+void install __P((char *, char *, int));
+void strip __P((char *));
+void usage __P((void));
main(argc, argv)
int argc;
main(argc, argv)
int argc;
- extern char *optarg;
- extern int optind;
struct stat from_sb, to_sb;
struct stat from_sb, to_sb;
- mode_t *set, *setmode();
int ch, no_target;
char *to_name;
int ch, no_target;
char *to_name;
group = optarg;
break;
case 'm':
group = optarg;
break;
case 'm':
- if (!(set = setmode(optarg))) {
- (void)fprintf(stderr,
- "install: invalid file mode.\n");
- exit(1);
- }
+ if (!(set = setmode(optarg)))
+ err("%s: invalid file mode\n", optarg);
mode = getmode(set, 0);
break;
case 'o':
mode = getmode(set, 0);
break;
case 'o':
usage();
/* get group and owner id's */
usage();
/* get group and owner id's */
- if (group && !(gp = getgrnam(group))) {
- fprintf(stderr, "install: unknown group %s.\n", group);
- exit(1);
- }
- if (owner && !(pp = getpwnam(owner))) {
- fprintf(stderr, "install: unknown user %s.\n", owner);
- exit(1);
- }
+ if (group && !(gp = getgrnam(group)))
+ err("unknown group %s\n", group);
+ if (owner && !(pp = getpwnam(owner)))
+ err("unknown user %s\n", owner);
no_target = stat(to_name = argv[argc - 1], &to_sb);
if (!no_target && (to_sb.st_mode & S_IFMT) == S_IFDIR) {
no_target = stat(to_name = argv[argc - 1], &to_sb);
if (!no_target && (to_sb.st_mode & S_IFMT) == S_IFDIR) {
usage();
if (!no_target) {
usage();
if (!no_target) {
- if (stat(*argv, &from_sb)) {
- fprintf(stderr, "install: can't find %s.\n", *argv);
- exit(1);
- }
- if ((to_sb.st_mode & S_IFMT) != S_IFREG) {
- fprintf(stderr, "install: %s isn't a regular file.\n", to_name);
- exit(1);
- }
- if (to_sb.st_dev == from_sb.st_dev && to_sb.st_ino == from_sb.st_ino) {
- fprintf(stderr, "install: %s and %s are the same file.\n", *argv, to_name);
- exit(1);
- }
+ if (stat(*argv, &from_sb))
+ err("%s: %s\n", *argv, strerror(errno));
+ if (!S_ISREG(to_sb.st_mode))
+ err("%s: %s\n", to_name, strerror(EFTYPE));
+ if (to_sb.st_dev == from_sb.st_dev &&
+ to_sb.st_ino == from_sb.st_ino)
+ err("%s and %s are the same file\n", *argv, to_name);
/* unlink now... avoid ETXTBSY errors later */
(void)unlink(to_name);
}
/* unlink now... avoid ETXTBSY errors later */
(void)unlink(to_name);
}
* install --
* build a path name and install the file
*/
* install --
* build a path name and install the file
*/
install(from_name, to_name, isdir)
char *from_name, *to_name;
int isdir;
{
struct stat from_sb;
install(from_name, to_name, isdir)
char *from_name, *to_name;
int isdir;
{
struct stat from_sb;
- int devnull, from_fd, to_fd;
- char *C, *rindex();
+ int devnull, from_fd, to_fd, serrno;
+ char *p;
- /* if try to install NULL file to a directory, fails */
+ /* If try to install NULL file to a directory, fails. */
if (isdir || strcmp(from_name, _PATH_DEVNULL)) {
if (isdir || strcmp(from_name, _PATH_DEVNULL)) {
- if (stat(from_name, &from_sb)) {
- fprintf(stderr, "install: can't find %s.\n", from_name);
- exit(1);
- }
- if ((from_sb.st_mode & S_IFMT) != S_IFREG) {
- fprintf(stderr, "install: %s isn't a regular file.\n", from_name);
- exit(1);
- }
- /* build the target path */
+ if (stat(from_name, &from_sb))
+ err("%s: %s\n", from_name, strerror(errno));
+ if (!S_ISREG(from_sb.st_mode))
+ err("%s: %s\n", from_name, strerror(EFTYPE));
+ /* Build the target path. */
- (void)sprintf(pathbuf, "%s/%s", to_name, (C = rindex(from_name, '/')) ? ++C : from_name);
+ (void)snprintf(pathbuf, sizeof(pathbuf), "%s/%s",
+ to_name,
+ (p = rindex(from_name, '/')) ? ++p : from_name);
to_name = pathbuf;
}
devnull = 0;
} else
devnull = 1;
to_name = pathbuf;
}
devnull = 0;
} else
devnull = 1;
- /* unlink now... avoid ETXTBSY errors later */
+ /* Unlink now... avoid ETXTBSY errors later. */
- /* create target */
- if ((to_fd = open(to_name, O_CREAT|O_WRONLY|O_TRUNC, 0600)) < 0) {
- error(to_name);
- exit(1);
- }
+ /* Create target. */
+ if ((to_fd = open(to_name, O_CREAT|O_WRONLY|O_TRUNC, 0600)) < 0)
+ err("%s: %s", to_name, strerror(errno));
if (!devnull) {
if ((from_fd = open(from_name, O_RDONLY, 0)) < 0) {
(void)unlink(to_name);
if (!devnull) {
if ((from_fd = open(from_name, O_RDONLY, 0)) < 0) {
(void)unlink(to_name);
- error(from_name);
- exit(1);
+ err("%s: %s", from_name, strerror(errno));
}
copy(from_fd, from_name, to_fd, to_name);
(void)close(from_fd);
}
copy(from_fd, from_name, to_fd, to_name);
(void)close(from_fd);
if (dostrip)
strip(to_name);
/*
if (dostrip)
strip(to_name);
/*
- * set owner, group, mode for target; do the chown first,
+ * Set owner, group, mode for target; do the chown first,
* chown may lose the setuid bits.
*/
if ((group || owner) &&
fchown(to_fd, owner ? pp->pw_uid : -1, group ? gp->gr_gid : -1) ||
fchmod(to_fd, mode)) {
* chown may lose the setuid bits.
*/
if ((group || owner) &&
fchown(to_fd, owner ? pp->pw_uid : -1, group ? gp->gr_gid : -1) ||
fchmod(to_fd, mode)) {
- error(to_name);
- bad(to_name);
+ serrno = errno;
+ (void)unlink(to_name);
+ err("%s: %s", to_name, strerror(serrno));
- (void)close(to_fd);
- if (!docopy && !devnull && unlink(from_name)) {
- error(from_name);
- exit(1);
+
+ /* Always preserve the flags. */
+ if (fchflags(to_fd, from_sb.st_flags)) {
+ serrno = errno;
+ (void)unlink(to_name);
+ err("%s: %s", to_name, strerror(serrno));
+
+ (void)close(to_fd);
+ if (!docopy && !devnull && unlink(from_name))
+ err("%s: %s", from_name, strerror(errno));
}
/*
* copy --
* copy from one file to another
*/
}
/*
* copy --
* copy from one file to another
*/
copy(from_fd, from_name, to_fd, to_name)
register int from_fd, to_fd;
char *from_name, *to_name;
{
copy(from_fd, from_name, to_fd, to_name)
register int from_fd, to_fd;
char *from_name, *to_name;
{
+ register int nr, nw;
+ int serrno;
- while ((n = read(from_fd, buf, sizeof(buf))) > 0)
- if (write(to_fd, buf, n) != n) {
- error(to_name);
- bad(to_name);
+ while ((nr = read(from_fd, buf, sizeof(buf))) > 0)
+ if ((nw = write(to_fd, buf, nr)) != nr) {
+ serrno = errno;
+ (void)unlink(to_name);
+ err("%s: %s", to_name, strerror(nw > 0 ? EIO : serrno));
- if (n == -1) {
- error(from_name);
- bad(to_name);
+ if (nr != 0) {
+ serrno = errno;
+ (void)unlink(to_name);
+ err("%s: %s", from_name, strerror(serrno));
* strip --
* use strip(1) to strip the target file
*/
* strip --
* use strip(1) to strip the target file
*/
strip(to_name)
char *to_name;
{
strip(to_name)
char *to_name;
{
switch (vfork()) {
case -1:
switch (vfork()) {
case -1:
- error("fork");
- bad(to_name);
+ serrno = errno;
+ (void)unlink(to_name);
+ err("forks: %s", strerror(errno));
- execl(_PATH_STRIP, "strip", to_name, (char *)NULL);
- error(_PATH_STRIP);
- _exit(1);
+ execl(_PATH_STRIP, "strip", to_name, NULL);
+ err("%s: %s", _PATH_STRIP, strerror(errno));
default:
if (wait(&status) == -1 || status)
default:
if (wait(&status) == -1 || status)
-/*
- * error --
- * print out an error message
- */
-error(s)
- char *s;
-{
- extern int errno;
- char *strerror();
-
- (void)fprintf(stderr, "install: %s: %s\n", s, strerror(errno));
-}
-
-/*
- * bad --
- * remove created target and die
- */
-bad(fname)
- char *fname;
-{
- (void)unlink(fname);
- exit(1);
-}
-
/*
* usage --
* print a usage message and die
*/
/*
* usage --
* print a usage message and die
*/
usage()
{
(void)fprintf(stderr,
"usage: install [-cs] [-g group] [-m mode] [-o owner] file1 file2;\n\tor file1 ... fileN directory\n");
exit(1);
}
usage()
{
(void)fprintf(stderr,
"usage: install [-cs] [-g group] [-m mode] [-o owner] file1 file2;\n\tor file1 ... fileN directory\n");
exit(1);
}
+
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+void
+#if __STDC__
+err(const char *fmt, ...)
+#else
+err(fmt, va_alist)
+ char *fmt;
+ va_dcl
+#endif
+{
+ va_list ap;
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ (void)fprintf(stderr, "install: ");
+ (void)vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ (void)fprintf(stderr, "\n");
+ exit(1);
+ /* NOTREACHED */
+}