mv.c revision 284916
1227569Sphilip/*-
2227569Sphilip * Copyright (c) 1989, 1993, 1994
3227569Sphilip *	The Regents of the University of California.  All rights reserved.
4227569Sphilip *
5227569Sphilip * This code is derived from software contributed to Berkeley by
6227569Sphilip * Ken Smith of The State University of New York at Buffalo.
7227569Sphilip *
8227569Sphilip * Redistribution and use in source and binary forms, with or without
9227569Sphilip * modification, are permitted provided that the following conditions
10227569Sphilip * are met:
11227569Sphilip * 1. Redistributions of source code must retain the above copyright
12227569Sphilip *    notice, this list of conditions and the following disclaimer.
13227569Sphilip * 2. Redistributions in binary form must reproduce the above copyright
14227569Sphilip *    notice, this list of conditions and the following disclaimer in the
15227569Sphilip *    documentation and/or other materials provided with the distribution.
16227569Sphilip * 4. Neither the name of the University nor the names of its contributors
17227569Sphilip *    may be used to endorse or promote products derived from this software
18227569Sphilip *    without specific prior written permission.
19227569Sphilip *
20227569Sphilip * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21227569Sphilip * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22227569Sphilip * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23227569Sphilip * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24227569Sphilip * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25227569Sphilip * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26228078Sphilip * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27228078Sphilip * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28228078Sphilip * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29227569Sphilip * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30227569Sphilip * SUCH DAMAGE.
31227569Sphilip */
32227569Sphilip
33227569Sphilip#if 0
34227569Sphilip#ifndef lint
35227569Sphilipstatic char const copyright[] =
36227569Sphilip"@(#) Copyright (c) 1989, 1993, 1994\n\
37227569Sphilip	The Regents of the University of California.  All rights reserved.\n";
38227569Sphilip#endif /* not lint */
39227569Sphilip
40227569Sphilip#ifndef lint
41227569Sphilipstatic char sccsid[] = "@(#)mv.c	8.2 (Berkeley) 4/2/94";
42227569Sphilip#endif /* not lint */
43227569Sphilip#endif
44227569Sphilip#include <sys/cdefs.h>
45227569Sphilip__FBSDID("$FreeBSD: head/bin/mv/mv.c 284916 2015-06-28 21:36:00Z jilles $");
46227569Sphilip
47227569Sphilip#include <sys/types.h>
48227569Sphilip#include <sys/acl.h>
49227569Sphilip#include <sys/param.h>
50227569Sphilip#include <sys/time.h>
51227569Sphilip#include <sys/wait.h>
52227569Sphilip#include <sys/stat.h>
53227569Sphilip#include <sys/mount.h>
54227569Sphilip
55227569Sphilip#include <err.h>
56227569Sphilip#include <errno.h>
57227569Sphilip#include <fcntl.h>
58227569Sphilip#include <grp.h>
59227569Sphilip#include <limits.h>
60227569Sphilip#include <paths.h>
61227569Sphilip#include <pwd.h>
62227569Sphilip#include <stdio.h>
63227569Sphilip#include <stdlib.h>
64227569Sphilip#include <string.h>
65227569Sphilip#include <sysexits.h>
66227569Sphilip#include <unistd.h>
67227569Sphilip
68227569Sphilip/* Exit code for a failed exec. */
69227569Sphilip#define EXEC_FAILED 127
70227569Sphilip
71227569Sphilipstatic int	fflg, hflg, iflg, nflg, vflg;
72227569Sphilip
73227569Sphilipstatic int	copy(const char *, const char *);
74227569Sphilipstatic int	do_move(const char *, const char *);
75227569Sphilipstatic int	fastcopy(const char *, const char *, struct stat *);
76227569Sphilipstatic void	usage(void);
77227569Sphilipstatic void	preserve_fd_acls(int source_fd, int dest_fd, const char *source_path,
78227569Sphilip		    const char *dest_path);
79227569Sphilip
80227569Sphilipint
81227569Sphilipmain(int argc, char *argv[])
82227569Sphilip{
83227569Sphilip	size_t baselen, len;
84227569Sphilip	int rval;
85227569Sphilip	char *p, *endp;
86227569Sphilip	struct stat sb;
87227569Sphilip	int ch;
88227569Sphilip	char path[PATH_MAX];
89227569Sphilip
90227569Sphilip	while ((ch = getopt(argc, argv, "fhinv")) != -1)
91227569Sphilip		switch (ch) {
92227569Sphilip		case 'h':
93227569Sphilip			hflg = 1;
94227569Sphilip			break;
95227569Sphilip		case 'i':
96227569Sphilip			iflg = 1;
97227569Sphilip			fflg = nflg = 0;
98227569Sphilip			break;
99227569Sphilip		case 'f':
100227569Sphilip			fflg = 1;
101227569Sphilip			iflg = nflg = 0;
102227569Sphilip			break;
103227569Sphilip		case 'n':
104227569Sphilip			nflg = 1;
105227569Sphilip			fflg = iflg = 0;
106227569Sphilip			break;
107227569Sphilip		case 'v':
108227569Sphilip			vflg = 1;
109227569Sphilip			break;
110227569Sphilip		default:
111227569Sphilip			usage();
112227569Sphilip		}
113227569Sphilip	argc -= optind;
114227569Sphilip	argv += optind;
115227569Sphilip
116227569Sphilip	if (argc < 2)
117227569Sphilip		usage();
118227569Sphilip
119227569Sphilip	/*
120227569Sphilip	 * If the stat on the target fails or the target isn't a directory,
121227569Sphilip	 * try the move.  More than 2 arguments is an error in this case.
122227569Sphilip	 */
123227569Sphilip	if (stat(argv[argc - 1], &sb) || !S_ISDIR(sb.st_mode)) {
124227569Sphilip		if (argc > 2)
125227569Sphilip			errx(1, "%s is not a directory", argv[argc - 1]);
126227569Sphilip		exit(do_move(argv[0], argv[1]));
127227569Sphilip	}
128227569Sphilip
129227569Sphilip	/*
130227569Sphilip	 * If -h was specified, treat the target as a symlink instead of
131227569Sphilip	 * directory.
132227569Sphilip	 */
133227569Sphilip	if (hflg) {
134227569Sphilip		if (argc > 2)
135227569Sphilip			usage();
136227569Sphilip		if (lstat(argv[1], &sb) == 0 && S_ISLNK(sb.st_mode))
137227569Sphilip			exit(do_move(argv[0], argv[1]));
138227569Sphilip	}
139227569Sphilip
140227569Sphilip	/* It's a directory, move each file into it. */
141227569Sphilip	if (strlen(argv[argc - 1]) > sizeof(path) - 1)
142227569Sphilip		errx(1, "%s: destination pathname too long", *argv);
143227569Sphilip	(void)strcpy(path, argv[argc - 1]);
144227569Sphilip	baselen = strlen(path);
145227569Sphilip	endp = &path[baselen];
146227569Sphilip	if (!baselen || *(endp - 1) != '/') {
147227569Sphilip		*endp++ = '/';
148227569Sphilip		++baselen;
149227569Sphilip	}
150227569Sphilip	for (rval = 0; --argc; ++argv) {
151227569Sphilip		/*
152227569Sphilip		 * Find the last component of the source pathname.  It
153227569Sphilip		 * may have trailing slashes.
154227569Sphilip		 */
155227569Sphilip		p = *argv + strlen(*argv);
156227569Sphilip		while (p != *argv && p[-1] == '/')
157227569Sphilip			--p;
158227569Sphilip		while (p != *argv && p[-1] != '/')
159227569Sphilip			--p;
160227569Sphilip
161227569Sphilip		if ((baselen + (len = strlen(p))) >= PATH_MAX) {
162227569Sphilip			warnx("%s: destination pathname too long", *argv);
163227569Sphilip			rval = 1;
164227569Sphilip		} else {
165227569Sphilip			memmove(endp, p, (size_t)len + 1);
166227569Sphilip			if (do_move(*argv, path))
167227569Sphilip				rval = 1;
168227569Sphilip		}
169227569Sphilip	}
170227569Sphilip	exit(rval);
171227569Sphilip}
172227569Sphilip
173227569Sphilipstatic int
174227569Sphilipdo_move(const char *from, const char *to)
175227569Sphilip{
176227569Sphilip	struct stat sb;
177227569Sphilip	int ask, ch, first;
178227569Sphilip	char modep[15];
179227569Sphilip
180227569Sphilip	/*
181227569Sphilip	 * Check access.  If interactive and file exists, ask user if it
182227569Sphilip	 * should be replaced.  Otherwise if file exists but isn't writable
183227569Sphilip	 * make sure the user wants to clobber it.
184227569Sphilip	 */
185227569Sphilip	if (!fflg && !access(to, F_OK)) {
186227569Sphilip
187227569Sphilip		/* prompt only if source exist */
188227569Sphilip	        if (lstat(from, &sb) == -1) {
189227569Sphilip			warn("%s", from);
190227569Sphilip			return (1);
191227569Sphilip		}
192227569Sphilip
193227569Sphilip#define YESNO "(y/n [n]) "
194227569Sphilip		ask = 0;
195227569Sphilip		if (nflg) {
196227569Sphilip			if (vflg)
197227569Sphilip				printf("%s not overwritten\n", to);
198227569Sphilip			return (0);
199227569Sphilip		} else if (iflg) {
200227569Sphilip			(void)fprintf(stderr, "overwrite %s? %s", to, YESNO);
201227569Sphilip			ask = 1;
202227569Sphilip		} else if (access(to, W_OK) && !stat(to, &sb) && isatty(STDIN_FILENO)) {
203227569Sphilip			strmode(sb.st_mode, modep);
204227569Sphilip			(void)fprintf(stderr, "override %s%s%s/%s for %s? %s",
205227569Sphilip			    modep + 1, modep[9] == ' ' ? "" : " ",
206227569Sphilip			    user_from_uid((unsigned long)sb.st_uid, 0),
207227569Sphilip			    group_from_gid((unsigned long)sb.st_gid, 0), to, YESNO);
208227569Sphilip			ask = 1;
209227569Sphilip		}
210227569Sphilip		if (ask) {
211227569Sphilip			first = ch = getchar();
212227569Sphilip			while (ch != '\n' && ch != EOF)
213227569Sphilip				ch = getchar();
214227569Sphilip			if (first != 'y' && first != 'Y') {
215227569Sphilip				(void)fprintf(stderr, "not overwritten\n");
216227569Sphilip				return (0);
217227569Sphilip			}
218227569Sphilip		}
219227569Sphilip	}
220227569Sphilip	/*
221227569Sphilip	 * Rename on FreeBSD will fail with EISDIR and ENOTDIR, before failing
222227569Sphilip	 * with EXDEV.  Therefore, copy() doesn't have to perform the checks
223227569Sphilip	 * specified in the Step 3 of the POSIX mv specification.
224227569Sphilip	 */
225227569Sphilip	if (!rename(from, to)) {
226227569Sphilip		if (vflg)
227227569Sphilip			printf("%s -> %s\n", from, to);
228227569Sphilip		return (0);
229227569Sphilip	}
230227569Sphilip
231227569Sphilip	if (errno == EXDEV) {
232227569Sphilip		struct statfs sfs;
233227569Sphilip		char path[PATH_MAX];
234227569Sphilip
235227569Sphilip		/*
236227569Sphilip		 * If the source is a symbolic link and is on another
237227569Sphilip		 * filesystem, it can be recreated at the destination.
238227569Sphilip		 */
239227569Sphilip		if (lstat(from, &sb) == -1) {
240227569Sphilip			warn("%s", from);
241227569Sphilip			return (1);
242227569Sphilip		}
243227569Sphilip		if (!S_ISLNK(sb.st_mode)) {
244227569Sphilip			/* Can't mv(1) a mount point. */
245227569Sphilip			if (realpath(from, path) == NULL) {
246227569Sphilip				warn("cannot resolve %s: %s", from, path);
247227569Sphilip				return (1);
248227569Sphilip			}
249227569Sphilip			if (!statfs(path, &sfs) &&
250227569Sphilip			    !strcmp(path, sfs.f_mntonname)) {
251227569Sphilip				warnx("cannot rename a mount point");
252227569Sphilip				return (1);
253227569Sphilip			}
254227569Sphilip		}
255227569Sphilip	} else {
256227569Sphilip		warn("rename %s to %s", from, to);
257227569Sphilip		return (1);
258227569Sphilip	}
259227569Sphilip
260227569Sphilip	/*
261227569Sphilip	 * If rename fails because we're trying to cross devices, and
262227569Sphilip	 * it's a regular file, do the copy internally; otherwise, use
263227569Sphilip	 * cp and rm.
264227569Sphilip	 */
265227569Sphilip	if (lstat(from, &sb)) {
266227569Sphilip		warn("%s", from);
267227569Sphilip		return (1);
268227569Sphilip	}
269227569Sphilip	return (S_ISREG(sb.st_mode) ?
270227569Sphilip	    fastcopy(from, to, &sb) : copy(from, to));
271227569Sphilip}
272227569Sphilip
273227569Sphilipstatic int
274227569Sphilipfastcopy(const char *from, const char *to, struct stat *sbp)
275227569Sphilip{
276227569Sphilip	struct timespec ts[2];
277227569Sphilip	static u_int blen = MAXPHYS;
278227569Sphilip	static char *bp = NULL;
279227569Sphilip	mode_t oldmode;
280227569Sphilip	int nread, from_fd, to_fd;
281227569Sphilip	struct stat tsb;
282227569Sphilip
283227569Sphilip	if ((from_fd = open(from, O_RDONLY, 0)) < 0) {
284227569Sphilip		warn("fastcopy: open() failed (from): %s", from);
285227569Sphilip		return (1);
286227569Sphilip	}
287227569Sphilip	if (bp == NULL && (bp = malloc((size_t)blen)) == NULL) {
288227569Sphilip		warnx("malloc(%u) failed", blen);
289227569Sphilip		return (1);
290227569Sphilip	}
291227569Sphilip	while ((to_fd =
292227569Sphilip	    open(to, O_CREAT | O_EXCL | O_TRUNC | O_WRONLY, 0)) < 0) {
293227569Sphilip		if (errno == EEXIST && unlink(to) == 0)
294227569Sphilip			continue;
295227569Sphilip		warn("fastcopy: open() failed (to): %s", to);
296227569Sphilip		(void)close(from_fd);
297227569Sphilip		return (1);
298227569Sphilip	}
299227569Sphilip	while ((nread = read(from_fd, bp, (size_t)blen)) > 0)
300227569Sphilip		if (write(to_fd, bp, (size_t)nread) != nread) {
301227569Sphilip			warn("fastcopy: write() failed: %s", to);
302227569Sphilip			goto err;
303227569Sphilip		}
304227569Sphilip	if (nread < 0) {
305227569Sphilip		warn("fastcopy: read() failed: %s", from);
306227569Sphiliperr:		if (unlink(to))
307227569Sphilip			warn("%s: remove", to);
308227569Sphilip		(void)close(from_fd);
309227569Sphilip		(void)close(to_fd);
310227569Sphilip		return (1);
311227569Sphilip	}
312227569Sphilip
313227569Sphilip	oldmode = sbp->st_mode & ALLPERMS;
314227569Sphilip	if (fchown(to_fd, sbp->st_uid, sbp->st_gid)) {
315227569Sphilip		warn("%s: set owner/group (was: %lu/%lu)", to,
316227569Sphilip		    (u_long)sbp->st_uid, (u_long)sbp->st_gid);
317227569Sphilip		if (oldmode & (S_ISUID | S_ISGID)) {
318227569Sphilip			warnx(
319227569Sphilip"%s: owner/group changed; clearing suid/sgid (mode was 0%03o)",
320227569Sphilip			    to, oldmode);
321227569Sphilip			sbp->st_mode &= ~(S_ISUID | S_ISGID);
322227569Sphilip		}
323227569Sphilip	}
324227569Sphilip	if (fchmod(to_fd, sbp->st_mode))
325227569Sphilip		warn("%s: set mode (was: 0%03o)", to, oldmode);
326227569Sphilip	/*
327227569Sphilip	 * POSIX 1003.2c states that if _POSIX_ACL_EXTENDED is in effect
328227569Sphilip	 * for dest_file, then its ACLs shall reflect the ACLs of the
329227569Sphilip	 * source_file.
330227569Sphilip	 */
331227569Sphilip	preserve_fd_acls(from_fd, to_fd, from, to);
332227569Sphilip	(void)close(from_fd);
333227569Sphilip	/*
334227569Sphilip	 * XXX
335227569Sphilip	 * NFS doesn't support chflags; ignore errors unless there's reason
336227569Sphilip	 * to believe we're losing bits.  (Note, this still won't be right
337227569Sphilip	 * if the server supports flags and we were trying to *remove* flags
338227569Sphilip	 * on a file that we copied, i.e., that we didn't create.)
339227569Sphilip	 */
340227569Sphilip	if (fstat(to_fd, &tsb) == 0) {
341227569Sphilip		if ((sbp->st_flags  & ~UF_ARCHIVE) !=
342227569Sphilip		    (tsb.st_flags & ~UF_ARCHIVE)) {
343227569Sphilip			if (fchflags(to_fd,
344227569Sphilip			    sbp->st_flags | (tsb.st_flags & UF_ARCHIVE)))
345227569Sphilip				if (errno != EOPNOTSUPP ||
346227569Sphilip				    ((sbp->st_flags & ~UF_ARCHIVE) != 0))
347227569Sphilip					warn("%s: set flags (was: 0%07o)",
348227569Sphilip					    to, sbp->st_flags);
349227569Sphilip		}
350227569Sphilip	} else
351227569Sphilip		warn("%s: cannot stat", to);
352227569Sphilip
353227569Sphilip	ts[0] = sbp->st_atim;
354227569Sphilip	ts[1] = sbp->st_mtim;
355227569Sphilip	if (futimens(to_fd, ts))
356227569Sphilip		warn("%s: set times", to);
357227569Sphilip
358227569Sphilip	if (close(to_fd)) {
359227569Sphilip		warn("%s", to);
360227569Sphilip		return (1);
361227569Sphilip	}
362227569Sphilip
363227569Sphilip	if (unlink(from)) {
364227569Sphilip		warn("%s: remove", from);
365227569Sphilip		return (1);
366227569Sphilip	}
367227569Sphilip	if (vflg)
368227569Sphilip		printf("%s -> %s\n", from, to);
369227569Sphilip	return (0);
370227569Sphilip}
371227569Sphilip
372227569Sphilipstatic int
373227569Sphilipcopy(const char *from, const char *to)
374227569Sphilip{
375227569Sphilip	struct stat sb;
376227569Sphilip	int pid, status;
377227569Sphilip
378227569Sphilip	if (lstat(to, &sb) == 0) {
379227569Sphilip		/* Destination path exists. */
380227569Sphilip		if (S_ISDIR(sb.st_mode)) {
381227569Sphilip			if (rmdir(to) != 0) {
382227569Sphilip				warn("rmdir %s", to);
383227569Sphilip				return (1);
384227569Sphilip			}
385227569Sphilip		} else {
386227569Sphilip			if (unlink(to) != 0) {
387227569Sphilip				warn("unlink %s", to);
388227569Sphilip				return (1);
389227569Sphilip			}
390227569Sphilip		}
391227569Sphilip	} else if (errno != ENOENT) {
392227569Sphilip		warn("%s", to);
393227569Sphilip		return (1);
394227569Sphilip	}
395227569Sphilip
396227569Sphilip	/* Copy source to destination. */
397227569Sphilip	if (!(pid = vfork())) {
398227569Sphilip		execl(_PATH_CP, "mv", vflg ? "-PRpv" : "-PRp", "--", from, to,
399227569Sphilip		    (char *)NULL);
400227569Sphilip		_exit(EXEC_FAILED);
401227569Sphilip	}
402227569Sphilip	if (waitpid(pid, &status, 0) == -1) {
403227569Sphilip		warn("%s %s %s: waitpid", _PATH_CP, from, to);
404227569Sphilip		return (1);
405227569Sphilip	}
406227569Sphilip	if (!WIFEXITED(status)) {
407227569Sphilip		warnx("%s %s %s: did not terminate normally",
408227569Sphilip		    _PATH_CP, from, to);
409227569Sphilip		return (1);
410227569Sphilip	}
411227569Sphilip	switch (WEXITSTATUS(status)) {
412227569Sphilip	case 0:
413227569Sphilip		break;
414227569Sphilip	case EXEC_FAILED:
415227569Sphilip		warnx("%s %s %s: exec failed", _PATH_CP, from, to);
416227569Sphilip		return (1);
417227569Sphilip	default:
418227569Sphilip		warnx("%s %s %s: terminated with %d (non-zero) status",
419227569Sphilip		    _PATH_CP, from, to, WEXITSTATUS(status));
420227569Sphilip		return (1);
421227569Sphilip	}
422227569Sphilip
423227569Sphilip	/* Delete the source. */
424227569Sphilip	if (!(pid = vfork())) {
425227569Sphilip		execl(_PATH_RM, "mv", "-rf", "--", from, (char *)NULL);
426227569Sphilip		_exit(EXEC_FAILED);
427227569Sphilip	}
428227569Sphilip	if (waitpid(pid, &status, 0) == -1) {
429227569Sphilip		warn("%s %s: waitpid", _PATH_RM, from);
430227569Sphilip		return (1);
431227569Sphilip	}
432227569Sphilip	if (!WIFEXITED(status)) {
433227569Sphilip		warnx("%s %s: did not terminate normally", _PATH_RM, from);
434227569Sphilip		return (1);
435227569Sphilip	}
436227569Sphilip	switch (WEXITSTATUS(status)) {
437227569Sphilip	case 0:
438227569Sphilip		break;
439227569Sphilip	case EXEC_FAILED:
440227569Sphilip		warnx("%s %s: exec failed", _PATH_RM, from);
441227569Sphilip		return (1);
442227569Sphilip	default:
443227569Sphilip		warnx("%s %s: terminated with %d (non-zero) status",
444227569Sphilip		    _PATH_RM, from, WEXITSTATUS(status));
445227569Sphilip		return (1);
446227569Sphilip	}
447227569Sphilip	return (0);
448227569Sphilip}
449227569Sphilip
450227569Sphilipstatic void
451227569Sphilippreserve_fd_acls(int source_fd, int dest_fd, const char *source_path,
452227569Sphilip    const char *dest_path)
453227569Sphilip{
454227569Sphilip	acl_t acl;
455227569Sphilip	acl_type_t acl_type;
456227569Sphilip	int acl_supported = 0, ret, trivial;
457227569Sphilip
458227569Sphilip	ret = fpathconf(source_fd, _PC_ACL_NFS4);
459227569Sphilip	if (ret > 0 ) {
460227569Sphilip		acl_supported = 1;
461227569Sphilip		acl_type = ACL_TYPE_NFS4;
462227569Sphilip	} else if (ret < 0 && errno != EINVAL) {
463227569Sphilip		warn("fpathconf(..., _PC_ACL_NFS4) failed for %s",
464227569Sphilip		    source_path);
465227569Sphilip		return;
466227569Sphilip	}
467227569Sphilip	if (acl_supported == 0) {
468227569Sphilip		ret = fpathconf(source_fd, _PC_ACL_EXTENDED);
469227569Sphilip		if (ret > 0 ) {
470227569Sphilip			acl_supported = 1;
471227569Sphilip			acl_type = ACL_TYPE_ACCESS;
472227569Sphilip		} else if (ret < 0 && errno != EINVAL) {
473227569Sphilip			warn("fpathconf(..., _PC_ACL_EXTENDED) failed for %s",
474227569Sphilip			    source_path);
475227569Sphilip			return;
476227569Sphilip		}
477227569Sphilip	}
478227569Sphilip	if (acl_supported == 0)
479227569Sphilip		return;
480227569Sphilip
481227569Sphilip	acl = acl_get_fd_np(source_fd, acl_type);
482227569Sphilip	if (acl == NULL) {
483227569Sphilip		warn("failed to get acl entries for %s", source_path);
484227569Sphilip		return;
485227569Sphilip	}
486227569Sphilip	if (acl_is_trivial_np(acl, &trivial)) {
487227569Sphilip		warn("acl_is_trivial() failed for %s", source_path);
488227569Sphilip		acl_free(acl);
489227569Sphilip		return;
490227569Sphilip	}
491227569Sphilip	if (trivial) {
492227569Sphilip		acl_free(acl);
493227569Sphilip		return;
494227569Sphilip	}
495227569Sphilip	if (acl_set_fd_np(dest_fd, acl, acl_type) < 0) {
496227569Sphilip		warn("failed to set acl entries for %s", dest_path);
497227569Sphilip		acl_free(acl);
498227569Sphilip		return;
499227569Sphilip	}
500227569Sphilip	acl_free(acl);
501227569Sphilip}
502227569Sphilip
503227569Sphilipstatic void
504227569Sphilipusage(void)
505227569Sphilip{
506227569Sphilip
507227569Sphilip	(void)fprintf(stderr, "%s\n%s\n",
508227569Sphilip		      "usage: mv [-f | -i | -n] [-hv] source target",
509227569Sphilip		      "       mv [-f | -i | -n] [-v] source ... directory");
510227569Sphilip	exit(EX_USAGE);
511227569Sphilip}
512227569Sphilip