Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 20 Apr 2001 19:10:08 +0300
From:      Ruslan Ermilov <ru@FreeBSD.org>
To:        Bruce Evans <bde@FreeBSD.org>
Cc:        current@FreeBSD.org, hackers@FreeBSD.org
Subject:   [CFR] OpenBSD install(1) fixes: atomic install, etc.
Message-ID:  <20010420191008.A51313@sunbay.com>

next in thread | raw e-mail | index | archive | help

--tThc/1wpZn/ma/RB
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Hi!

The attached patch incorporates most of OpenBSD fixes to install(1).
It does not include manpage update.  Most significant changes are:

o All TODOs are acted upon.

o New flags: -b and -B

: -b    Backup any existing files before overwriting them by
:       renaming them to file.old.  See -B for specifying a
:       different backup suffix.
: 
: -B suffix
:       Use suffix as the backup suffix if -b is given.

o New flag: -S (atomic install)

: -S    Safe copy.  Normally, install unlinks an existing target before
:       installing the new file.  With the -S flag a temporary file is
:       used and then renamed to be the target.  The reason this is safer
:       is that if the copy or rename fails, the existing target is left
:       untouched.

o The -c flag is now the default, and only provided for backwards
  compatibility.  We now never remove the original file.

o Flags -v and -D were withdrawn.

o strip(1) failure is not considered fatal.

Please review.


Thanks,
-- 
Ruslan Ermilov		Oracle Developer/DBA,
ru@sunbay.com		Sunbay Software AG,
ru@FreeBSD.org		FreeBSD committer,
+380.652.512.251	Simferopol, Ukraine

http://www.FreeBSD.org	The Power To Serve
http://www.oracle.com	Enabling The Information Age

--tThc/1wpZn/ma/RB
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename=p

Index: xinstall.c
===================================================================
RCS file: /home/ncvs/src/usr.bin/xinstall/xinstall.c,v
retrieving revision 1.40
diff -u -p -r1.40 xinstall.c
--- xinstall.c	2000/10/08 09:17:56	1.40
+++ xinstall.c	2001/04/20 15:42:20
@@ -45,21 +45,6 @@ static const char rcsid[] =
   "$FreeBSD: src/usr.bin/xinstall/xinstall.c,v 1.40 2000/10/08 09:17:56 bde Exp $";
 #endif /* not lint */
 
-/*-
- * Todo:
- * o for -C, compare original files except in -s case.
- * o for -C, don't change anything if nothing needs be changed.  In
- *   particular, don't toggle the immutable flags just to allow null
- *   attribute changes and don't clear the dump flag.  (I think inode
- *   ctimes are not updated for null attribute changes, but this is a
- *   bug.)
- * o independent of -C, if a copy must be made, then copy to a tmpfile,
- *   set all attributes except the immutable flags, then rename, then
- *   set the immutable flags.  It's annoying that the immutable flags
- *   defeat the atomicicity of rename - it seems that there must be
- *   a window where the target is not immutable.
- */
-
 #include <sys/param.h>
 #include <sys/wait.h>
 #include <sys/mman.h>
@@ -82,45 +67,29 @@ static const char rcsid[] =
 
 #include "pathnames.h"
 
-/* Bootstrap aid - this doesn't exist in most older releases */
-#ifndef MAP_FAILED
-#define MAP_FAILED ((void *)-1)	/* from <sys/mman.h> */
-#endif
-
-int debug, docompare, docopy, dodir, dopreserve, dostrip, nommap, verbose;
-int mode = S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
-char *group, *owner, pathbuf[MAXPATHLEN];
-char pathbuf2[MAXPATHLEN];
-
 #define	DIRECTORY	0x01		/* Tell install it's a directory. */
 #define	SETFLAGS	0x02		/* Tell install to set flags. */
 #define	NOCHANGEBITS	(UF_IMMUTABLE | UF_APPEND | SF_IMMUTABLE | SF_APPEND)
+#define	BACKUP_SUFFIX	".old"
 
+struct passwd *pp;
+struct group *gp;
+int dobackup, docompare, dodir, dopreserve, dostrip, nommap, safecopy;
+int mode = S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
+char pathbuf[MAXPATHLEN], tempfile[MAXPATHLEN];
+char *suffix = BACKUP_SUFFIX;
+uid_t uid;
+gid_t gid;
+
 void	copy __P((int, char *, int, char *, off_t));
-int	compare __P((int, const char *, int, const char *, 
-		     const struct stat *, const struct stat *));
+int	compare __P((int, const char *, size_t, int, const char *, size_t));
+int	create_newfile __P((char *, struct stat *));
+int	create_tempfile __P((char *, char *, size_t));
 void	install __P((char *, char *, u_long, u_int));
 void	install_dir __P((char *));
 void	strip __P((char *));
-void	usage __P((void));
 int	trymmap __P((int));
-
-#define ALLOW_NUMERIC_IDS 1
-#ifdef ALLOW_NUMERIC_IDS
-
-uid_t   uid = -1;
-gid_t   gid = -1;
-
-uid_t	resolve_uid __P((char *));
-gid_t	resolve_gid __P((char *));
-u_long	numeric_id __P((char *, char *));
-
-#else
-
-struct passwd *pp;
-struct group *gp;
-
-#endif /* ALLOW_NUMERIC_IDS */
+void	usage __P((void));
 
 int
 main(argc, argv)
@@ -132,20 +101,23 @@ main(argc, argv)
 	u_long fset;
 	u_int iflags;
 	int ch, no_target;
-	char *flags, *to_name;
+	char *flags, *to_name, *group = NULL, *owner = NULL;
 
 	iflags = 0;
-	while ((ch = getopt(argc, argv, "CcdDf:g:m:Mo:psv")) != -1)
+	while ((ch = getopt(argc, argv, "BbCcdf:g:Mm:o:pSs")) != -1)
 		switch((char)ch) {
+		case 'B':
+			suffix = optarg;
+			/* FALLTHROUGH */
+		case 'b':
+			dobackup = 1;
+			break;
 		case 'C':
-			docompare = docopy = 1;
+			docompare = 1;
 			break;
 		case 'c':
-			docopy = 1;
+			/* For backwards compatibility. */
 			break;
-		case 'D':
-			debug++;
-			break;
 		case 'd':
 			dodir = 1;
 			break;
@@ -158,6 +130,9 @@ main(argc, argv)
 		case 'g':
 			group = optarg;
 			break;
+		case 'M':
+			nommap = 1;
+			break;
 		case 'm':
 			if (!(set = setmode(optarg)))
 				errx(EX_USAGE, "invalid file mode: %s",
@@ -165,21 +140,18 @@ main(argc, argv)
 			mode = getmode(set, 0);
 			free(set);
 			break;
-		case 'M':
-			nommap = 1;
-			break;
 		case 'o':
 			owner = optarg;
 			break;
 		case 'p':
-			docompare = docopy = dopreserve = 1;
+			docompare = dopreserve = 1;
+			break;
+		case 'S':
+			safecopy = 1;
 			break;
 		case 's':
 			dostrip = 1;
 			break;
-		case 'v':
-			verbose = 1;
-			break;
 		case '?':
 		default:
 			usage();
@@ -188,29 +160,24 @@ main(argc, argv)
 	argv += optind;
 
 	/* some options make no sense when creating directories */
-	if (dostrip && dodir)
+	if ((safecopy || docompare || dostrip) && dodir)
 		usage();
 
 	/* must have at least two arguments, except when creating directories */
 	if (argc < 2 && !dodir)
 		usage();
-
-#ifdef ALLOW_NUMERIC_IDS
 
-	if (owner)
-		uid = resolve_uid(owner);
-	if (group)
-		gid = resolve_gid(group);
+	/* need to make a temp copy so we can compare stripped version */
+	if (docompare && dostrip)
+		safecopy = 1;
 
-#else
-
 	/* get group and owner id's */
-	if (owner && !(pp = getpwnam(owner)))
-		errx(EX_NOUSER, "unknown user %s", owner);
-	if (group && !(gp = getgrnam(group)))
+	if (group && !(gp = getgrnam(group)) && !isdigit(*group))
 		errx(EX_NOUSER, "unknown group %s", group);
-
-#endif /* ALLOW_NUMERIC_IDS */
+	gid = (group) ? ((gp) ? gp->gr_gid : (gid_t)strtoul(group, NULL, 10)) : (gid_t)-1;
+	if (owner && !(pp = getpwnam(owner)) && !isdigit(*owner))
+		errx(EX_NOUSER, "unknown user %s", owner);
+	uid = (owner) ? ((pp) ? pp->pw_uid : (uid_t)strtoul(owner, NULL, 10)) : (uid_t)-1;
 
 	if (dodir) {
 		for (; *argv != NULL; ++argv)
@@ -220,7 +187,7 @@ main(argc, argv)
 	}
 
 	no_target = stat(to_name = argv[argc - 1], &to_sb);
-	if (!no_target && (to_sb.st_mode & S_IFMT) == S_IFDIR) {
+	if (!no_target && S_ISDIR(to_sb.st_mode)) {
 		for (; *argv != to_name; ++argv)
 			install(*argv, to_name, fset, iflags | DIRECTORY);
 		exit(EX_OK);
@@ -242,72 +209,12 @@ main(argc, argv)
 		    to_sb.st_ino == from_sb.st_ino)
 			errx(EX_USAGE, 
 			    "%s and %s are the same file", *argv, to_name);
-/*
- * XXX - It's not at all clear why this code was here, since it completely
- * duplicates code install().  The version in install() handles the -C flag
- * correctly, so we'll just disable this for now.
- */
-#if 0
-		/*
-		 * Unlink now... avoid ETXTBSY errors later.  Try and turn
-		 * off the append/immutable bits -- if we fail, go ahead,
-		 * it might work.
-		 */
-		if (to_sb.st_flags & NOCHANGEBITS)
-			(void)chflags(to_name,
-			    to_sb.st_flags & ~(NOCHANGEBITS));
-		(void)unlink(to_name);
-#endif
 	}
 	install(*argv, to_name, fset, iflags);
 	exit(EX_OK);
 	/* NOTREACHED */
 }
 
-#ifdef ALLOW_NUMERIC_IDS
-
-uid_t
-resolve_uid(s)
-	char *s;
-{
-	struct passwd *pw;
-
-	return ((pw = getpwnam(s)) == NULL) ?
-		(uid_t) numeric_id(s, "user") : pw->pw_uid;
-}
-
-gid_t
-resolve_gid(s)
-	char *s;
-{
-	struct group *gr;
-
-	return ((gr = getgrnam(s)) == NULL) ?
-		(gid_t) numeric_id(s, "group") : gr->gr_gid;
-}
-
-u_long
-numeric_id(name, type)
-	char *name, *type;
-{
-	u_long val;
-	char *ep;
-
-	/*
-	 * XXX
-	 * We know that uid_t's and gid_t's are unsigned longs.
-	 */
-	errno = 0;
-	val = strtoul(name, &ep, 10);
-	if (errno)
-		err(EX_NOUSER, "%s", name);
-	if (*ep != '\0')
-		errx(EX_NOUSER, "unknown %s %s", type, name);
-	return (val);
-}
-
-#endif /* ALLOW_NUMERIC_IDS */
-
 /*
  * install --
  *	build a path name and install the file
@@ -319,12 +226,15 @@ install(from_name, to_name, fset, flags)
 	u_int flags;
 {
 	struct stat from_sb, to_sb;
-	int devnull, from_fd, to_fd, serrno;
-	char *p, *old_to_name = 0;
+	struct utimbuf utb;
+	int devnull, from_fd, to_fd, serrno, files_match = 0;
+	char *p;
 
-	if (debug >= 2 && !docompare)
-		fprintf(stderr, "install: invoked without -C for %s to %s\n",
-			from_name, to_name);
+#ifdef __GNUC__				/* XXX: to shut up gcc warnings */
+        (void)&from_fd;
+#endif
+
+	(void)memset((void *)&from_sb, 0, sizeof(from_sb));
 
 	/* If try to install NULL file to a directory, fails. */
 	if (flags & DIRECTORY || strcmp(from_name, _PATH_DEVNULL)) {
@@ -343,143 +253,155 @@ install(from_name, to_name, fset, flags)
 		}
 		devnull = 0;
 	} else {
-		from_sb.st_flags = 0;	/* XXX */
 		devnull = 1;
 	}
 
-	if (docompare) {
-		old_to_name = to_name;
-		/*
-		 * Make a new temporary file in the same file system
-		 * (actually, in in the same directory) as the target so
-		 * that the temporary file can be renamed to the target.
-		 */
-		snprintf(pathbuf2, sizeof pathbuf2, "%s", to_name);
-		p = strrchr(pathbuf2, '/');
-		p = (p == NULL ? pathbuf2 : p + 1);
-		snprintf(p, &pathbuf2[sizeof pathbuf2] - p, "INS@XXXX");
-		to_fd = mkstemp(pathbuf2);
+	if (stat(to_name, &to_sb) == 0) {
+		/* Only compare against regular files. */
+		if (docompare && !S_ISREG(to_sb.st_mode)) {
+			docompare = 0;
+			errno = EFTYPE;
+			warn("%s", to_name);
+		}
+	} else if (docompare) {
+		/* File does not exist so silently ignore compare flag. */
+		docompare = 0;
+	}
+
+	if (safecopy) {
+		to_fd = create_tempfile(to_name, tempfile, sizeof(tempfile));
 		if (to_fd < 0)
-			/* XXX should fall back to not comparing. */
-			err(EX_OSERR, "mkstemp: %s for %s", pathbuf2, to_name);
-		to_name = pathbuf2;
+			err(EX_OSERR, "%s", tempfile);
+	} else if (docompare && !dostrip) {
+		if ((to_fd = open(to_name, O_RDONLY, 0)) < 0)
+			err(EX_OSERR, "%s", to_name);
 	} else {
-		/*
-		 * Unlink now... avoid errors later.  Try to turn off the
-		 * append/immutable bits -- if we fail, go ahead, it might
-		 * work.
-		 */
-		if (stat(to_name, &to_sb) == 0 && to_sb.st_flags & NOCHANGEBITS)
-			(void)chflags(to_name, to_sb.st_flags & ~NOCHANGEBITS);
-		unlink(to_name);
-
-		/* Create target. */
-		to_fd = open(to_name,
-			     O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR);
-		if (to_fd < 0)
+		if ((to_fd = create_newfile(to_name, &to_sb)) < 0)
 			err(EX_OSERR, "%s", to_name);
 	}
 
 	if (!devnull) {
 		if ((from_fd = open(from_name, O_RDONLY, 0)) < 0) {
 			serrno = errno;
-			(void)unlink(to_name);
+			(void)unlink(safecopy ? tempfile : to_name);
 			errno = serrno;
 			err(EX_OSERR, "%s", from_name);
 		}
-		copy(from_fd, from_name, to_fd, to_name, from_sb.st_size);
-		(void)close(from_fd);
+
+		if (docompare && !safecopy) {
+			files_match = !(compare(from_fd, from_name,
+					(size_t)from_sb.st_size, to_fd,
+					to_name, (size_t)to_sb.st_size));
+
+			/* Truncate "to" file for copy unless we match */
+			if (!files_match) {
+				(void)close(to_fd);
+				if ((to_fd = create_newfile(to_name, &to_sb)) < 0)
+					err(EX_OSERR, "%s", to_name);
+			}
+		}
+		if (!files_match)
+			copy(from_fd, from_name, to_fd,
+			     safecopy ? tempfile : to_name, from_sb.st_size);
 	}
 
 	if (dostrip) {
-		(void)close(to_fd);
+		strip(safecopy ? tempfile : to_name);
 
-		strip(to_name);
-
-		/* Reopen target. */
-		to_fd = open(to_name, O_RDWR, 0);
+		/*
+		 * Re-open our fd on the target, in case we used a strip
+		 * that does not work in-place -- like GNU binutils strip.
+		 */
+		close(to_fd);
+		to_fd = open(safecopy ? tempfile : to_name, O_RDONLY, 0);
 		if (to_fd < 0)
-			err(EX_OSERR, "%s", to_name);
+			err(EX_OSERR, "stripping %s", to_name);
 	}
 
 	/*
-	 * Unfortunately, because we strip the installed file and not the
-	 * original one, it is impossible to do the comparison without
-	 * first laboriously copying things over and then comparing.
-	 * It may be possible to better optimize the !dostrip case, however.
-	 * For further study.
+	 * Compare the (possibly stripped) temp file to the target.
 	 */
-	if (docompare) {
-		struct stat old_sb, new_sb, timestamp_sb;
-		int old_fd;
-		struct utimbuf utb;
-
-		old_fd = open(old_to_name, O_RDONLY, 0);
-		if (old_fd < 0 && errno == ENOENT)
-			goto different;
-		if (old_fd < 0)
-			err(EX_OSERR, "%s", old_to_name);
-		fstat(old_fd, &old_sb);
-		if (old_sb.st_flags & NOCHANGEBITS)
-			(void)fchflags(old_fd, old_sb.st_flags & ~NOCHANGEBITS);
-		fstat(to_fd, &new_sb);
-		if (compare(old_fd, old_to_name, to_fd, to_name, &old_sb,
-			    &new_sb)) {
-different:
-			if (debug != 0)
-				fprintf(stderr,
-					"install: renaming for %s: %s to %s\n",
-					from_name, to_name, old_to_name);
-			if (verbose != 0)
-				printf("install: %s -> %s\n",
-					from_name, old_to_name);
-			if (dopreserve && stat(from_name, &timestamp_sb) == 0) {
-				utb.actime = timestamp_sb.st_atime;
-				utb.modtime = timestamp_sb.st_mtime;
-				(void)utime(to_name, &utb);
+	if (safecopy && docompare) {
+		int temp_fd = to_fd;
+		struct stat temp_sb;
+
+		/* Re-open to_fd using the real target name. */
+		if ((to_fd = open(to_name, O_RDONLY, 0)) < 0)
+			err(EX_OSERR, "%s", to_name);
+
+		if (fstat(temp_fd, &temp_sb)) {
+			serrno = errno;
+			(void)unlink(tempfile);
+			errno = serrno;
+			err(EX_OSERR, "%s", tempfile);
+		}
+
+		if (compare(temp_fd, tempfile, (size_t)temp_sb.st_size, to_fd,
+			    to_name, (size_t)to_sb.st_size) == 0) {
+			/*
+			 * If target has more than one link we need to
+			 * replace it in order to snap the extra links.
+			 * Need to preserve target file times, though.
+			 */
+			if (to_sb.st_nlink != 1) {
+				utb.actime = to_sb.st_atime;
+				utb.modtime = to_sb.st_mtime;
+				(void)utime(tempfile, &utb);
+			} else {
+				files_match = 1;
+				(void)unlink(tempfile);
 			}
-moveit:
-			if (rename(to_name, old_to_name) < 0) {
+			(void) close(temp_fd);
+		}
+	}
+
+	/*
+	 * Move the new file into place if doing a safe copy
+	 * and the files are different (or just not compared).
+	 */
+	if (safecopy && !files_match) {
+		/* Try to turn off the immutable bits. */
+		if (to_sb.st_flags & (NOCHANGEBITS))
+			(void)chflags(to_name, to_sb.st_flags & ~(NOCHANGEBITS));
+		if (dobackup) {
+			char backup[MAXPATHLEN];
+			(void)snprintf(backup, MAXPATHLEN, "%s%s", to_name,
+			    suffix);
+			if (rename(to_name, backup) < 0) {
 				serrno = errno;
-				unlink(to_name);
-				unlink(old_to_name);
-				errno = serrno;
-				err(EX_OSERR, "rename: %s to %s", to_name,
-				    old_to_name);
-			}
-			close(old_fd);
-		} else {
-			if (old_sb.st_nlink != 1) {
-				/*
-				 * Replace the target, although it hasn't
-				 * changed, to snap the extra links.  But
-				 * preserve the target file times.
-				 */
-				if (fstat(old_fd, &timestamp_sb) == 0) {
-					utb.actime = timestamp_sb.st_atime;
-					utb.modtime = timestamp_sb.st_mtime;
-					(void)utime(to_name, &utb);
-				}
-				goto moveit;
+				unlink(tempfile);
+				errx(EX_OSERR, "rename: %s to %s: %s", to_name,
+				     backup, strerror(serrno));
 			}
-			if (unlink(to_name) < 0)
-				err(EX_OSERR, "unlink: %s", to_name);
-			close(to_fd);
-			to_fd = old_fd;
+		}
+		if (rename(tempfile, to_name) < 0) {
+			serrno = errno;
+			unlink(tempfile);
+			errno = serrno;
+			err(EX_OSERR, "rename: %s to %s",
+			    tempfile, to_name);
 		}
-		to_name = old_to_name;
+
+		/* Re-open to_fd so we aren't hosed by the rename(2). */
+		(void) close(to_fd);
+		if ((to_fd = open(to_name, O_RDONLY, 0)) < 0)
+			err(EX_OSERR, "%s", to_name);
 	}
 
 	/*
+	 * Preserve the timestamp of the source file if necesary.
+	 */
+	if (dopreserve && !files_match) {
+		utb.actime = from_sb.st_atime;
+		utb.modtime = from_sb.st_mtime;
+		(void)utime(to_name, &utb);
+	}
+
+	/*
 	 * Set owner, group, mode for target; do the chown first,
 	 * chown may lose the setuid bits.
 	 */
-	if ((group || owner) &&
-#ifdef ALLOW_NUMERIC_IDS
-	    fchown(to_fd, owner ? uid : -1, group ? gid : -1)) {
-#else
-	    fchown(to_fd, owner ? pp->pw_uid : -1, group ? gp->gr_gid : -1)) {
-#endif
+	if ((gid != (gid_t)-1 || uid != (uid_t)-1) && fchown(to_fd, uid, gid)) {
 		serrno = errno;
 		(void)unlink(to_name);
 		errno = serrno;
@@ -514,8 +436,8 @@ moveit:
 	}
 
 	(void)close(to_fd);
-	if (!docopy && !devnull && unlink(from_name))
-		err(EX_OSERR, "%s", from_name);
+	if (!devnull)
+		(void)close(from_fd);
 }
 
 /*
@@ -523,35 +445,32 @@ moveit:
  *	compare two files; non-zero means files differ
  */
 int
-compare(int from_fd, const char *from_name, int to_fd, const char *to_name,
-	const struct stat *from_sb, const struct stat *to_sb)
+compare(int from_fd, const char *from_name, size_t from_len,
+	int to_fd, const char *to_name, size_t to_len)
 {
 	char *p, *q;
 	int rv;
-	size_t tsize;
 	int done_compare;
 
 	rv = 0;
-	if (from_sb->st_size != to_sb->st_size)
+	if (from_len != to_len)
 		return 1;
-
-	tsize = (size_t)from_sb->st_size;
 
-	if (tsize <= 8 * 1024 * 1024) {
+	if (from_len <= 8 * 1024 * 1024) {
 		done_compare = 0;
 		if (trymmap(from_fd) && trymmap(to_fd)) {
-			p = mmap(NULL, tsize, PROT_READ, MAP_SHARED, from_fd, (off_t)0);
+			p = mmap(NULL, from_len, PROT_READ, MAP_SHARED, from_fd, (off_t)0);
 			if (p == (char *)MAP_FAILED)
 				goto out;
-			q = mmap(NULL, tsize, PROT_READ, MAP_SHARED, to_fd, (off_t)0);
+			q = mmap(NULL, from_len, PROT_READ, MAP_SHARED, to_fd, (off_t)0);
 			if (q == (char *)MAP_FAILED) {
-				munmap(p, tsize);
+				munmap(p, from_len);
 				goto out;
 			}
 
-			rv = memcmp(p, q, tsize);
-			munmap(p, tsize);
-			munmap(q, tsize);
+			rv = memcmp(p, q, from_len);
+			munmap(p, from_len);
+			munmap(q, from_len);
 			done_compare = 1;
 		}
 	out:
@@ -586,6 +505,59 @@ compare(int from_fd, const char *from_na
 }
 
 /*
+ * create_tempfile --
+ *	create a temporary file based on path and open it
+ */
+int
+create_tempfile(path, temp, tsize)
+	char *path;
+	char *temp;
+	size_t tsize;
+{
+	char *p;
+
+	(void)strncpy(temp, path, tsize);
+	temp[tsize - 1] = '\0';
+	if ((p = strrchr(temp, '/')) != NULL)
+		p++;
+	else
+		p = temp;
+	(void)strncpy(p, "INS@XXXXXX", &temp[tsize - 1] - p);
+	temp[tsize - 1] = '\0';
+
+	return (mkstemp(temp));
+}
+
+/*
+ * create_newfile --
+ *	create a new file, overwriting an existing one if necessary
+ */
+int
+create_newfile(path, sbp)
+        char *path;
+	struct stat *sbp;
+{
+	char backup[MAXPATHLEN];
+
+	/*
+	 * Unlink now... avoid ETXTBSY errors later.  Try to turn
+	 * off the append/immutable bits -- if we fail, go ahead,
+	 * it might work.
+	 */
+	if (sbp->st_flags & NOCHANGEBITS)
+		(void)chflags(path, sbp->st_flags & ~NOCHANGEBITS);
+
+	if (dobackup) {
+		(void)snprintf(backup, MAXPATHLEN, "%s%s", path, suffix);
+		if (rename(path, backup) < 0)
+			err(EX_OSERR, "rename: %s to %s", path, backup);
+	} else
+		(void)unlink(path);
+
+	return(open(path, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR));
+}
+
+/*
  * copy --
  *	copy from one file to another
  */
@@ -600,16 +572,21 @@ copy(from_fd, from_name, to_fd, to_name,
 	char *p, buf[MAXBSIZE];
 	int done_copy;
 
+	/* Rewind file descriptors. */
+	if (lseek(from_fd, (off_t)0, SEEK_SET) == (off_t)-1)
+		err(EX_OSERR, "lseek: %s", from_name);
+	if (lseek(to_fd, (off_t)0, SEEK_SET) == (off_t)-1)
+		err(EX_OSERR, "lseek: %s", to_name);
+
 	/*
 	 * Mmap and write if less than 8M (the limit is so we don't totally
 	 * trash memory on big files.  This is really a minor hack, but it
 	 * wins some CPU back.
 	 */
 	done_copy = 0;
-	if (size <= 8 * 1048576 && trymmap(from_fd)) {
-		if ((p = mmap(NULL, (size_t)size, PROT_READ,
-				MAP_SHARED, from_fd, (off_t)0)) == (char *)MAP_FAILED)
-			goto out;
+	if (size <= 8 * 1048576 && trymmap(from_fd) &&
+	    (p = mmap(NULL, (size_t)size, PROT_READ, MAP_SHARED,
+		    from_fd, (off_t)0)) != (char *)MAP_FAILED) {
 		if ((nw = write(to_fd, p, size)) != size) {
 			serrno = errno;
 			(void)unlink(to_name);
@@ -617,7 +594,6 @@ copy(from_fd, from_name, to_fd, to_name,
 			err(EX_OSERR, "%s", to_name);
 		}
 		done_copy = 1;
-	out:
 	}
 	if (!done_copy) {
 		while ((nr = read(from_fd, buf, sizeof(buf))) > 0)
@@ -656,7 +632,7 @@ strip(to_name)
 		execlp("strip", "strip", to_name, NULL);
 		err(EX_OSERR, "exec(strip)");
 	default:
-		if (wait(&status) == -1 || status) {
+		if (wait(&status) == -1 || !WIFEXITED(status)) {
 			(void)unlink(to_name);
 			exit(EX_SOFTWARE);
 			/* NOTREACHED */
@@ -704,11 +680,12 @@ install_dir(path)
 void
 usage()
 {
-	(void)fprintf(stderr,"\
-usage: install [-CcDpsv] [-f flags] [-g group] [-m mode] [-o owner] file1 file2\n\
-       install [-CcDpsv] [-f flags] [-g group] [-m mode] [-o owner] file1 ...\n\
-             fileN directory\n\
-       install -d [-v] [-g group] [-m mode] [-o owner] directory ...\n");
+	(void)fprintf(stderr, "\
+usage: install [-bCcpSs] [-B suffix] [-f flags] [-g group] [-m mode] [-o owner]\n\
+               file1 file2\n\
+       install [-bCcpSs] [-B suffix] [-f flags] [-g group] [-m mode] [-o owner]\n\
+               file1 ... fileN directory\n\
+       install -d [-g group] [-m mode] [-o owner] directory ...\n");
 	exit(EX_USAGE);
 	/* NOTREACHED */
 }

--tThc/1wpZn/ma/RB--

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-current" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20010420191008.A51313>