snprintf(errmsg, sizeof errmsg, "chmod %s, %s", to_name, strerror(errno));
snprintf(errmsg, sizeof errmsg, "%s: chmod %s, %s", funcname, to_name, strerror(errno));
install(Tcl_Interp *interp, const char *from_name, const char *to_name, u_long fset, u_int flags){	struct stat from_sb, temp_sb, to_sb;	struct timeval tvb[2];	int devnull, files_match, from_fd, serrno, target;	int tempcopy, temp_fd, to_fd;	char backup[MAXPATHLEN], *p, pathbuf[MAXPATHLEN], tempfile[MAXPATHLEN];	files_match = 0;	/* If try to install NULL file to a directory, fails. */	if (flags & DIRECTORY || strcmp(from_name, _PATH_DEVNULL)) {		if (stat(from_name, &from_sb)) {			char errmsg[255];			snprintf(errmsg, sizeof errmsg, "can't stat: %s, %s", from_name, strerror(errno));			Tcl_SetResult(interp, errmsg, TCL_VOLATILE);			return TCL_ERROR;		}		if (!S_ISREG(from_sb.st_mode)) {			char errmsg[255];			snprintf(errmsg, sizeof errmsg, "inappropriate file type: %s", from_name);			Tcl_SetResult(interp, errmsg, TCL_VOLATILE);			errno = EFTYPE;			return TCL_ERROR;		}		/* Build the target path. */		if (flags & DIRECTORY) {			(void)snprintf(pathbuf, sizeof(pathbuf), "%s/%s",			    to_name,			    (p = strrchr(from_name, '/')) ? ++p : from_name);			to_name = pathbuf;		}		devnull = 0;	} else {		devnull = 1;	}	target = stat(to_name, &to_sb) == 0;	/* Only install to regular files. */	if (target && !S_ISREG(to_sb.st_mode)) {		char errmsg[255];		snprintf(errmsg, sizeof errmsg, "%s: Can only install to regular files", to_name);		Tcl_SetResult(interp, errmsg, TCL_VOLATILE);		errno = EFTYPE;		return TCL_ERROR;	}	/* Only copy safe if the target exists. */	tempcopy = safecopy && target;	if (!devnull && (from_fd = open(from_name, O_RDONLY, 0)) < 0) {		char errmsg[255];		snprintf(errmsg, sizeof errmsg, "Unable to open: %s, %s", from_name, strerror(errno));		Tcl_SetResult(interp, errmsg, TCL_VOLATILE);		return TCL_ERROR;	}	/* If we don't strip, we can compare first. */	if (docompare && !dostrip && target) {		if ((to_fd = open(to_name, O_RDONLY, 0)) < 0) {			char errmsg[255];			snprintf(errmsg, sizeof errmsg, "Unable to open: %s, %s", to_name, strerror(errno));			Tcl_SetResult(interp, errmsg, TCL_VOLATILE);			return TCL_ERROR;		}		if (devnull)			files_match = to_sb.st_size == 0;		else			files_match = !(compare(from_fd, from_name,			    (size_t)from_sb.st_size, to_fd,			    to_name, (size_t)to_sb.st_size));		/* Close "to" file unless we match. */		if (!files_match)			(void)close(to_fd);	}	if (!files_match) {		if (tempcopy) {			to_fd = create_tempfile(to_name, tempfile,			    sizeof(tempfile));			if (to_fd < 0) {				char errmsg[255];				snprintf(errmsg, sizeof errmsg, "unable to open temporary file for: %s, %s", to_name, strerror(errno));				Tcl_SetResult(interp, errmsg, TCL_VOLATILE);				return TCL_ERROR;			}		} else {			if ((to_fd = create_newfile(interp, to_name, target, &to_sb)) < 0) {				char errmsg[255];				snprintf(errmsg, sizeof errmsg, "unable to create new file for: %s, %s", to_name, strerror(errno));				Tcl_SetResult(interp, errmsg, TCL_VOLATILE);				return TCL_ERROR;			}			if (verbose) {				char msg[255];				snprintf(msg, sizeof msg, "install: %s -> %s\n", from_name, to_name);				ui_info(interp, msg);			}		}		if (!devnull)			if (copy(interp, from_fd, from_name, to_fd,			     tempcopy ? tempfile : to_name, from_sb.st_size) != TCL_OK)				return TCL_ERROR;	}	if (dostrip) {		strip(tempcopy ? tempfile : to_name);		/*		 * 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(tempcopy ? tempfile : to_name, O_RDONLY, 0);		if (to_fd < 0) {			char errmsg[255];			snprintf(errmsg, sizeof errmsg, "error stripping %s, %s", to_name, strerror(errno));			Tcl_SetResult(interp, errmsg, TCL_VOLATILE);			return TCL_ERROR;		}	}	/*	 * Compare the stripped temp file with the target.	 */	if (docompare && dostrip && target) {		temp_fd = to_fd;		/* Re-open to_fd using the real target name. */		if ((to_fd = open(to_name, O_RDONLY, 0)) < 0) {			char errmsg[255];			snprintf(errmsg, sizeof errmsg, "cannot open strip target %s, %s", to_name, strerror(errno));			Tcl_SetResult(interp, errmsg, TCL_VOLATILE);			return TCL_ERROR;		}		if (fstat(temp_fd, &temp_sb)) {			char errmsg[255];			serrno = errno;			(void)unlink(tempfile);			errno = serrno;			snprintf(errmsg, sizeof errmsg, "can't stat %s, %s", tempfile, strerror(errno));			Tcl_SetResult(interp, errmsg, TCL_VOLATILE);			return TCL_ERROR;		}		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) {				tvb[0].tv_sec = to_sb.st_atime;				tvb[0].tv_usec = 0;				tvb[1].tv_sec = to_sb.st_mtime;				tvb[1].tv_usec = 0;				(void)utimes(tempfile, tvb);			} else {				files_match = 1;				(void)unlink(tempfile);			}			(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 (tempcopy && !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) {			if ((size_t)snprintf(backup, MAXPATHLEN, "%s%s", to_name,			    suffix) != strlen(to_name) + strlen(suffix)) {				char errmsg[255];				unlink(tempfile);				snprintf(errmsg, sizeof errmsg, "%s: backup filename too long", to_name);				Tcl_SetResult(interp, errmsg, TCL_VOLATILE);				return TCL_ERROR;			}			if (verbose) {				char msg[255];				snprintf(msg, sizeof msg, "install: %s -> %s\n", to_name, backup);				ui_info(interp, msg);			}			if (rename(to_name, backup) < 0) {				char errmsg[255];				serrno = errno;				unlink(tempfile);				errno = serrno;				snprintf(errmsg, sizeof errmsg,	"rename: %s to %s, %s",					 to_name, backup, strerror(errno));				Tcl_SetResult(interp, errmsg, TCL_VOLATILE);				return TCL_ERROR;			}		}		if (verbose) {			char msg[255];			snprintf(msg, sizeof msg, "install: %s -> %s\n", from_name, to_name);			ui_info(interp, msg);		}		if (rename(tempfile, to_name) < 0) {			char errmsg[255];			serrno = errno;			unlink(tempfile);			errno = serrno;			snprintf(errmsg, sizeof errmsg,				 "rename: %s to %s, %s", tempfile, to_name, strerror(errno));			Tcl_SetResult(interp, errmsg, TCL_VOLATILE);			return TCL_ERROR;		}		/* 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) {			char errmsg[255];			snprintf(errmsg, sizeof errmsg, "can't open %s, %s", to_name, strerror(errno));			Tcl_SetResult(interp, errmsg, TCL_VOLATILE);			return TCL_ERROR;		}	}	/*	 * Preserve the timestamp of the source file if necessary.	 */	if (dopreserve && !files_match && !devnull) {		tvb[0].tv_sec = from_sb.st_atime;		tvb[0].tv_usec = 0;		tvb[1].tv_sec = from_sb.st_mtime;		tvb[1].tv_usec = 0;		(void)utimes(to_name, tvb);	}	if (fstat(to_fd, &to_sb) == -1) {		char errmsg[255];		serrno = errno;		(void)unlink(to_name);		errno = serrno;		snprintf(errmsg, sizeof errmsg, "can't stat %s, %s", to_name, strerror(errno));		Tcl_SetResult(interp, errmsg, TCL_VOLATILE);		return TCL_ERROR;	}	/*	 * Set owner, group, mode for target; do the chown first,	 * chown may lose the setuid bits.	 */	if ((gid != (gid_t)-1 && gid != to_sb.st_gid) ||	    (uid != (uid_t)-1 && uid != to_sb.st_uid) ||	    (mode != (to_sb.st_mode & ALLPERMS))) {		/* Try to turn off the immutable bits. */		if (to_sb.st_flags & NOCHANGEBITS)			(void)fchflags(to_fd, to_sb.st_flags & ~NOCHANGEBITS);	}	if ((gid != (gid_t)-1 && gid != to_sb.st_gid) ||	    (uid != (uid_t)-1 && uid != to_sb.st_uid))		if (fchown(to_fd, uid, gid) == -1) {			char errmsg[255];			serrno = errno;			(void)unlink(to_name);			errno = serrno;			snprintf(errmsg, sizeof errmsg, "chown/chgrp %s, %s",				 to_name, strerror(errno));			Tcl_SetResult(interp, errmsg, TCL_VOLATILE);			return TCL_ERROR;		}	if (mode != (to_sb.st_mode & ALLPERMS))		if (fchmod(to_fd, mode)) {			char errmsg[255];			serrno = errno;			(void)unlink(to_name);			errno = serrno;			snprintf(errmsg, sizeof errmsg, "chmod %s, %s", to_name, strerror(errno));			Tcl_SetResult(interp, errmsg, TCL_VOLATILE);			return TCL_ERROR;		}	/*	 * If provided a set of flags, set them, otherwise, preserve the	 * flags, except for the dump flag.	 * NFS does not support flags.  Ignore EOPNOTSUPP flags if we're just	 * trying to turn off UF_NODUMP.  If we're trying to set real flags,	 * then warn if the the fs doesn't support it, otherwise fail.	 */	if (!devnull && (flags & SETFLAGS ||	    (from_sb.st_flags & ~UF_NODUMP) != to_sb.st_flags) &&	    fchflags(to_fd,	    flags & SETFLAGS ? fset : from_sb.st_flags & ~UF_NODUMP)) {		if (flags & SETFLAGS) {			if (errno != EOPNOTSUPP) {				char errmsg[255];				serrno = errno;				(void)unlink(to_name);				errno = serrno;				snprintf(errmsg, sizeof errmsg, "chflags %s, %s",					 to_name, strerror(errno));				Tcl_SetResult(interp, errmsg, TCL_VOLATILE);				return TCL_ERROR;			}		}	}	(void)close(to_fd);	if (!devnull)		(void)close(from_fd);	return TCL_OK;}