17bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes/* $NetBSD: mv.c,v 1.43 2011/08/29 14:46:54 joerg Exp $ */
27bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
37bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes/*
47bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * Copyright (c) 1989, 1993, 1994
57bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes *	The Regents of the University of California.  All rights reserved.
67bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes *
77bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * This code is derived from software contributed to Berkeley by
87bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * Ken Smith of The State University of New York at Buffalo.
97bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes *
107bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * Redistribution and use in source and binary forms, with or without
117bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * modification, are permitted provided that the following conditions
127bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * are met:
137bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * 1. Redistributions of source code must retain the above copyright
147bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes *    notice, this list of conditions and the following disclaimer.
157bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * 2. Redistributions in binary form must reproduce the above copyright
167bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes *    notice, this list of conditions and the following disclaimer in the
177bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes *    documentation and/or other materials provided with the distribution.
187bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * 3. Neither the name of the University nor the names of its contributors
197bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes *    may be used to endorse or promote products derived from this software
207bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes *    without specific prior written permission.
217bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes *
227bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
237bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
247bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
257bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
267bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
277bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
287bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
297bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
307bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
317bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
327bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes * SUCH DAMAGE.
337bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes */
347bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
357bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#include <sys/cdefs.h>
367bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#ifndef lint
377bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes__COPYRIGHT("@(#) Copyright (c) 1989, 1993, 1994\
387bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes The Regents of the University of California.  All rights reserved.");
397bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#endif /* not lint */
407bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
417bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#ifndef lint
427bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#if 0
437bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesstatic char sccsid[] = "@(#)mv.c	8.2 (Berkeley) 4/2/94";
447bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#else
457bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes__RCSID("$NetBSD: mv.c,v 1.43 2011/08/29 14:46:54 joerg Exp $");
467bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#endif
477bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#endif /* not lint */
487bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
497bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#include <sys/param.h>
507bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#include <sys/time.h>
517bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#include <sys/wait.h>
527bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#include <sys/stat.h>
537bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#include <sys/extattr.h>
547bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
557bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#include <err.h>
567bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#include <errno.h>
577bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#include <fcntl.h>
587bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#include <grp.h>
597bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#include <locale.h>
607bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#include <pwd.h>
617bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#include <stdio.h>
627bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#include <stdlib.h>
637bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#include <string.h>
647bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#include <unistd.h>
657bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
667bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#include "pathnames.h"
677bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
687bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesstatic int fflg, iflg, vflg;
697bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesstatic int stdin_ok;
707bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
717bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesstatic int	copy(char *, char *);
727bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesstatic int	do_move(char *, char *);
737bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesstatic int	fastcopy(char *, char *, struct stat *);
747bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes__dead static void	usage(void);
757bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
767bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesint
777bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesmain(int argc, char *argv[])
787bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes{
797bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	int ch, len, rval;
807bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	char *p, *endp;
817bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	struct stat sb;
827bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	char path[MAXPATHLEN + 1];
837bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	size_t baselen;
847bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
857bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	setprogname(argv[0]);
867bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	(void)setlocale(LC_ALL, "");
877bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
887bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	while ((ch = getopt(argc, argv, "ifv")) != -1)
897bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		switch (ch) {
907bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		case 'i':
917bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			fflg = 0;
927bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			iflg = 1;
937bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			break;
947bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		case 'f':
957bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			iflg = 0;
967bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			fflg = 1;
977bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			break;
987bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		case 'v':
997bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			vflg = 1;
1007bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			break;
1017bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		default:
1027bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			usage();
1037bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		}
1047bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	argc -= optind;
1057bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	argv += optind;
1067bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
1077bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (argc < 2)
1087bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		usage();
1097bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
1107bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	stdin_ok = isatty(STDIN_FILENO);
1117bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
1127bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	/*
1137bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 * If the stat on the target fails or the target isn't a directory,
1147bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 * try the move.  More than 2 arguments is an error in this case.
1157bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 */
1167bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (stat(argv[argc - 1], &sb) || !S_ISDIR(sb.st_mode)) {
1177bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		if (argc > 2)
1187bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			usage();
1197bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		exit(do_move(argv[0], argv[1]));
1207bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	}
1217bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
1227bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	/* It's a directory, move each file into it. */
1237bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	baselen = strlcpy(path, argv[argc - 1], sizeof(path));
1247bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (baselen >= sizeof(path))
1257bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		errx(1, "%s: destination pathname too long", argv[argc - 1]);
1267bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	endp = &path[baselen];
1277bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (!baselen || *(endp - 1) != '/') {
1287bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		*endp++ = '/';
1297bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		++baselen;
1307bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	}
1317bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	for (rval = 0; --argc; ++argv) {
1327bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		p = *argv + strlen(*argv) - 1;
1337bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		while (*p == '/' && p != *argv)
1347bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			*p-- = '\0';
1357bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		if ((p = strrchr(*argv, '/')) == NULL)
1367bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			p = *argv;
1377bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		else
1387bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			++p;
1397bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
1407bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		if ((baselen + (len = strlen(p))) >= MAXPATHLEN) {
1417bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			warnx("%s: destination pathname too long", *argv);
1427bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			rval = 1;
1437bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		} else {
1447bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			memmove(endp, p, len + 1);
1457bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			if (do_move(*argv, path))
1467bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes				rval = 1;
1477bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		}
1487bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	}
1497bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	exit(rval);
1507bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	/* NOTREACHED */
1517bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes}
1527bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
1537bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesstatic int
1547bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesdo_move(char *from, char *to)
1557bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes{
1567bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	struct stat sb;
1577bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	char modep[15];
1587bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
1597bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	/*
1607bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 * (1)	If the destination path exists, the -f option is not specified
1617bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 *	and either of the following conditions are true:
1627bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 *
1637bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 *	(a) The permissions of the destination path do not permit
1647bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 *	    writing and the standard input is a terminal.
1657bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 *	(b) The -i option is specified.
1667bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 *
1677bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 *	the mv utility shall write a prompt to standard error and
1687bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 *	read a line from standard input.  If the response is not
1697bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 *	affirmative, mv shall do nothing more with the current
1707bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 *	source file...
1717bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 */
1727bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (!fflg && !access(to, F_OK)) {
1737bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		int ask = 1;
1747bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		int ch;
1757bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
1767bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		if (iflg) {
1777bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			if (access(from, F_OK)) {
1787bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes				warn("rename %s", from);
1797bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes				return (1);
1807bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			}
1817bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			(void)fprintf(stderr, "overwrite %s? ", to);
1827bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		} else if (stdin_ok && access(to, W_OK) && !stat(to, &sb)) {
1837bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			if (access(from, F_OK)) {
1847bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes				warn("rename %s", from);
1857bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes				return (1);
1867bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			}
1877bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			strmode(sb.st_mode, modep);
1887bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			(void)fprintf(stderr, "override %s%s%s/%s for %s? ",
1897bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			    modep + 1, modep[9] == ' ' ? "" : " ",
1907bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			    user_from_uid(sb.st_uid, 0),
1917bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			    group_from_gid(sb.st_gid, 0), to);
1927bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		} else
1937bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			ask = 0;
1947bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		if (ask) {
1957bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			if ((ch = getchar()) != EOF && ch != '\n') {
1967bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes				int ch2;
1977bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes				while ((ch2 = getchar()) != EOF && ch2 != '\n')
1987bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes					continue;
1997bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			}
2007bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			if (ch != 'y' && ch != 'Y')
2017bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes				return (0);
2027bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		}
2037bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	}
2047bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
2057bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	/*
2067bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 * (2)	If rename() succeeds, mv shall do nothing more with the
2077bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 *	current source file.  If it fails for any other reason than
2087bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 *	EXDEV, mv shall write a diagnostic message to the standard
2097bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 *	error and do nothing more with the current source file.
2107bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 *
2117bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 * (3)	If the destination path exists, and it is a file of type
2127bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 *	directory and source_file is not a file of type directory,
2137bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 *	or it is a file not of type directory, and source file is
2147bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 *	a file of type directory, mv shall write a diagnostic
2157bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 *	message to standard error, and do nothing more with the
2167bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 *	current source file...
2177bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 */
2187bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (!rename(from, to)) {
2197bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		if (vflg)
2207bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			printf("%s -> %s\n", from, to);
2217bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		return (0);
2227bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	}
2237bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
2247bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (errno != EXDEV) {
2257bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		warn("rename %s to %s", from, to);
2267bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		return (1);
2277bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	}
2287bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
2297bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	/*
2307bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 * (4)	If the destination path exists, mv shall attempt to remove it.
2317bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 *	If this fails for any reason, mv shall write a diagnostic
2327bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 *	message to the standard error and do nothing more with the
2337bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 *	current source file...
2347bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 */
2357bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (!lstat(to, &sb)) {
2367bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		if ((S_ISDIR(sb.st_mode)) ? rmdir(to) : unlink(to)) {
2377bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			warn("can't remove %s", to);
2387bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			return (1);
2397bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		}
2407bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	}
2417bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
2427bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	/*
2437bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 * (5)	The file hierarchy rooted in source_file shall be duplicated
2447bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 *	as a file hierarchy rooted in the destination path...
2457bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	 */
2467bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (lstat(from, &sb)) {
2477bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		warn("%s", from);
2487bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		return (1);
2497bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	}
2507bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
2517bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	return (S_ISREG(sb.st_mode) ?
2527bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	    fastcopy(from, to, &sb) : copy(from, to));
2537bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes}
2547bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
2557bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesstatic int
2567bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesfastcopy(char *from, char *to, struct stat *sbp)
2577bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes{
2587bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	struct timeval tval[2];
2597bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	static blksize_t blen;
2607bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	static char *bp;
2617bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	int nread, from_fd, to_fd;
2627bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
2637bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if ((from_fd = open(from, O_RDONLY, 0)) < 0) {
2647bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		warn("%s", from);
2657bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		return (1);
2667bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	}
2677bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if ((to_fd =
2687bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	    open(to, O_CREAT | O_TRUNC | O_WRONLY, sbp->st_mode)) < 0) {
2697bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		warn("%s", to);
2707bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		(void)close(from_fd);
2717bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		return (1);
2727bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	}
2737bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (!blen && !(bp = malloc(blen = sbp->st_blksize))) {
2747bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		warn(NULL);
2757bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		blen = 0;
2767bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		(void)close(from_fd);
2777bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		(void)close(to_fd);
2787bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		return (1);
2797bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	}
2807bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	while ((nread = read(from_fd, bp, blen)) > 0)
2817bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		if (write(to_fd, bp, nread) != nread) {
2827bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			warn("%s", to);
2837bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			goto err;
2847bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		}
2857bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (nread < 0) {
2867bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		warn("%s", from);
2877bb5660647d0106f96b000c25f5690a45734c38cElliott Hugheserr:		if (unlink(to))
2887bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			warn("%s: remove", to);
2897bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		(void)close(from_fd);
2907bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		(void)close(to_fd);
2917bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		return (1);
2927bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	}
2937bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
2947bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#ifndef __ANDROID__
2957bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (fcpxattr(from_fd, to_fd) == -1)
2967bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		warn("%s: error copying extended attributes", to);
2977bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#endif
2987bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
2997bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	(void)close(from_fd);
3007bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#ifdef BSD4_4
3017bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	TIMESPEC_TO_TIMEVAL(&tval[0], &sbp->st_atimespec);
3027bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	TIMESPEC_TO_TIMEVAL(&tval[1], &sbp->st_mtimespec);
3037bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#else
3047bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	tval[0].tv_sec = sbp->st_atime;
3057bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	tval[1].tv_sec = sbp->st_mtime;
3067bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	tval[0].tv_usec = 0;
3077bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	tval[1].tv_usec = 0;
3087bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#endif
3097bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#ifdef __SVR4
3107bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (utimes(to, tval))
3117bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#else
3127bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (futimes(to_fd, tval))
3137bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#endif
3147bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		warn("%s: set times", to);
3157bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (fchown(to_fd, sbp->st_uid, sbp->st_gid)) {
3167bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		if (errno != EPERM)
3177bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes			warn("%s: set owner/group", to);
3187bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		sbp->st_mode &= ~(S_ISUID | S_ISGID);
3197bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	}
3207bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (fchmod(to_fd, sbp->st_mode))
3217bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		warn("%s: set mode", to);
3227bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#ifndef __ANDROID__
3237bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (fchflags(to_fd, sbp->st_flags) && (errno != EOPNOTSUPP))
3247bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		warn("%s: set flags (was: 0%07o)", to, sbp->st_flags);
3257bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes#endif
3267bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
3277bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (close(to_fd)) {
3287bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		warn("%s", to);
3297bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		return (1);
3307bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	}
3317bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
3327bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (unlink(from)) {
3337bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		warn("%s: remove", from);
3347bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		return (1);
3357bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	}
3367bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
3377bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (vflg)
3387bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		printf("%s -> %s\n", from, to);
3397bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
3407bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	return (0);
3417bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes}
3427bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
3437bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesstatic int
3447bb5660647d0106f96b000c25f5690a45734c38cElliott Hughescopy(char *from, char *to)
3457bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes{
3467bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	pid_t pid;
3477bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	int status;
3487bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
3497bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if ((pid = vfork()) == 0) {
3507bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		execl(_PATH_CP, "mv", vflg ? "-PRpv" : "-PRp", "--", from, to, NULL);
3517bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		warn("%s", _PATH_CP);
3527bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		_exit(1);
3537bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	}
3547bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (waitpid(pid, &status, 0) == -1) {
3557bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		warn("%s: waitpid", _PATH_CP);
3567bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		return (1);
3577bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	}
3587bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (!WIFEXITED(status)) {
3597bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		warnx("%s: did not terminate normally", _PATH_CP);
3607bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		return (1);
3617bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	}
3627bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (WEXITSTATUS(status)) {
3637bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		warnx("%s: terminated with %d (non-zero) status",
3647bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		    _PATH_CP, WEXITSTATUS(status));
3657bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		return (1);
3667bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	}
3677bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (!(pid = vfork())) {
3687bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		execl(_PATH_RM, "mv", "-rf", "--", from, NULL);
3697bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		warn("%s", _PATH_RM);
3707bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		_exit(1);
3717bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	}
3727bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (waitpid(pid, &status, 0) == -1) {
3737bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		warn("%s: waitpid", _PATH_RM);
3747bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		return (1);
3757bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	}
3767bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (!WIFEXITED(status)) {
3777bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		warnx("%s: did not terminate normally", _PATH_RM);
3787bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		return (1);
3797bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	}
3807bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	if (WEXITSTATUS(status)) {
3817bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		warnx("%s: terminated with %d (non-zero) status",
3827bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		    _PATH_RM, WEXITSTATUS(status));
3837bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes		return (1);
3847bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	}
3857bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	return (0);
3867bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes}
3877bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes
3887bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesstatic void
3897bb5660647d0106f96b000c25f5690a45734c38cElliott Hughesusage(void)
3907bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes{
3917bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	(void)fprintf(stderr, "usage: %s [-fiv] source target\n"
3927bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	    "       %s [-fiv] source ... directory\n", getprogname(),
3937bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	    getprogname());
3947bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	exit(1);
3957bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes	/* NOTREACHED */
3967bb5660647d0106f96b000c25f5690a45734c38cElliott Hughes}
397