1/*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 1991, 1993, 1994
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#ifndef lint
33#if 0
34static char sccsid[] = "@(#)utils.c	8.3 (Berkeley) 4/1/94";
35#endif
36#endif /* not lint */
37#include <sys/cdefs.h>
38__FBSDID("$FreeBSD$");
39
40#include <sys/types.h>
41#include <sys/acl.h>
42#include <sys/param.h>
43#include <sys/stat.h>
44#ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED
45#include <sys/mman.h>
46#endif
47
48#include <err.h>
49#include <errno.h>
50#include <fcntl.h>
51#include <fts.h>
52#include <limits.h>
53#include <stdio.h>
54#include <stdlib.h>
55#include <sysexits.h>
56#include <unistd.h>
57
58#include "extern.h"
59
60#define	cp_pct(x, y)	((y == 0) ? 0 : (int)(100.0 * (x) / (y)))
61
62/*
63 * Memory strategy threshold, in pages: if physmem is larger then this, use a
64 * large buffer.
65 */
66#define PHYSPAGES_THRESHOLD (32*1024)
67
68/* Maximum buffer size in bytes - do not allow it to grow larger than this. */
69#define BUFSIZE_MAX (2*1024*1024)
70
71/*
72 * Small (default) buffer size in bytes. It's inefficient for this to be
73 * smaller than MAXPHYS.
74 */
75#define BUFSIZE_SMALL (MAXPHYS)
76
77int
78copy_file(const FTSENT *entp, int dne)
79{
80	static char *buf = NULL;
81	static size_t bufsize;
82	struct stat *fs;
83	ssize_t wcount;
84	size_t wresid;
85	off_t wtotal;
86	int ch, checkch, from_fd, rcount, rval, to_fd;
87	char *bufp;
88#ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED
89	char *p;
90#endif
91
92	from_fd = to_fd = -1;
93	if (!lflag && !sflag &&
94	    (from_fd = open(entp->fts_path, O_RDONLY, 0)) == -1) {
95		warn("%s", entp->fts_path);
96		return (1);
97	}
98
99	fs = entp->fts_statp;
100
101	/*
102	 * If the file exists and we're interactive, verify with the user.
103	 * If the file DNE, set the mode to be the from file, minus setuid
104	 * bits, modified by the umask; arguably wrong, but it makes copying
105	 * executables work right and it's been that way forever.  (The
106	 * other choice is 666 or'ed with the execute bits on the from file
107	 * modified by the umask.)
108	 */
109	if (!dne) {
110#define YESNO "(y/n [n]) "
111		if (nflag) {
112			if (vflag)
113				printf("%s not overwritten\n", to.p_path);
114			rval = 1;
115			goto done;
116		} else if (iflag) {
117			(void)fprintf(stderr, "overwrite %s? %s",
118			    to.p_path, YESNO);
119			checkch = ch = getchar();
120			while (ch != '\n' && ch != EOF)
121				ch = getchar();
122			if (checkch != 'y' && checkch != 'Y') {
123				(void)fprintf(stderr, "not overwritten\n");
124				rval = 1;
125				goto done;
126			}
127		}
128
129		if (fflag) {
130			/*
131			 * Remove existing destination file name create a new
132			 * file.
133			 */
134			(void)unlink(to.p_path);
135			if (!lflag && !sflag) {
136				to_fd = open(to.p_path,
137				    O_WRONLY | O_TRUNC | O_CREAT,
138				    fs->st_mode & ~(S_ISUID | S_ISGID));
139			}
140		} else if (!lflag && !sflag) {
141			/* Overwrite existing destination file name. */
142			to_fd = open(to.p_path, O_WRONLY | O_TRUNC, 0);
143		}
144	} else if (!lflag && !sflag) {
145		to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT,
146		    fs->st_mode & ~(S_ISUID | S_ISGID));
147	}
148
149	if (!lflag && !sflag && to_fd == -1) {
150		warn("%s", to.p_path);
151		rval = 1;
152		goto done;
153	}
154
155	rval = 0;
156
157	if (!lflag && !sflag) {
158		/*
159		 * Mmap and write if less than 8M (the limit is so we don't
160		 * totally trash memory on big files.  This is really a minor
161		 * hack, but it wins some CPU back.
162		 * Some filesystems, such as smbnetfs, don't support mmap,
163		 * so this is a best-effort attempt.
164		 */
165#ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED
166		if (S_ISREG(fs->st_mode) && fs->st_size > 0 &&
167		    fs->st_size <= 8 * 1024 * 1024 &&
168		    (p = mmap(NULL, (size_t)fs->st_size, PROT_READ,
169		    MAP_SHARED, from_fd, (off_t)0)) != MAP_FAILED) {
170			wtotal = 0;
171			for (bufp = p, wresid = fs->st_size; ;
172			    bufp += wcount, wresid -= (size_t)wcount) {
173				wcount = write(to_fd, bufp, wresid);
174				if (wcount <= 0)
175					break;
176				wtotal += wcount;
177				if (info) {
178					info = 0;
179					(void)fprintf(stderr,
180					    "%s -> %s %3d%%\n",
181					    entp->fts_path, to.p_path,
182					    cp_pct(wtotal, fs->st_size));
183				}
184				if (wcount >= (ssize_t)wresid)
185					break;
186			}
187			if (wcount != (ssize_t)wresid) {
188				warn("%s", to.p_path);
189				rval = 1;
190			}
191			/* Some systems don't unmap on close(2). */
192			if (munmap(p, fs->st_size) < 0) {
193				warn("%s", entp->fts_path);
194				rval = 1;
195			}
196		} else
197#endif
198		{
199			if (buf == NULL) {
200				/*
201				 * Note that buf and bufsize are static. If
202				 * malloc() fails, it will fail at the start
203				 * and not copy only some files.
204				 */
205				if (sysconf(_SC_PHYS_PAGES) >
206				    PHYSPAGES_THRESHOLD)
207					bufsize = MIN(BUFSIZE_MAX, MAXPHYS * 8);
208				else
209					bufsize = BUFSIZE_SMALL;
210				buf = malloc(bufsize);
211				if (buf == NULL)
212					err(1, "Not enough memory");
213			}
214			wtotal = 0;
215			while ((rcount = read(from_fd, buf, bufsize)) > 0) {
216				for (bufp = buf, wresid = rcount; ;
217				    bufp += wcount, wresid -= wcount) {
218					wcount = write(to_fd, bufp, wresid);
219					if (wcount <= 0)
220						break;
221					wtotal += wcount;
222					if (info) {
223						info = 0;
224						(void)fprintf(stderr,
225						    "%s -> %s %3d%%\n",
226						    entp->fts_path, to.p_path,
227						    cp_pct(wtotal, fs->st_size));
228					}
229					if (wcount >= (ssize_t)wresid)
230						break;
231				}
232				if (wcount != (ssize_t)wresid) {
233					warn("%s", to.p_path);
234					rval = 1;
235					break;
236				}
237			}
238			if (rcount < 0) {
239				warn("%s", entp->fts_path);
240				rval = 1;
241			}
242		}
243	} else if (lflag) {
244		if (link(entp->fts_path, to.p_path)) {
245			warn("%s", to.p_path);
246			rval = 1;
247		}
248	} else if (sflag) {
249		if (symlink(entp->fts_path, to.p_path)) {
250			warn("%s", to.p_path);
251			rval = 1;
252		}
253	}
254
255	/*
256	 * Don't remove the target even after an error.  The target might
257	 * not be a regular file, or its attributes might be important,
258	 * or its contents might be irreplaceable.  It would only be safe
259	 * to remove it if we created it and its length is 0.
260	 */
261
262	if (!lflag && !sflag) {
263		if (pflag && setfile(fs, to_fd))
264			rval = 1;
265		if (pflag && preserve_fd_acls(from_fd, to_fd) != 0)
266			rval = 1;
267		if (close(to_fd)) {
268			warn("%s", to.p_path);
269			rval = 1;
270		}
271	}
272
273done:
274	if (from_fd != -1)
275		(void)close(from_fd);
276	return (rval);
277}
278
279int
280copy_link(const FTSENT *p, int exists)
281{
282	int len;
283	char llink[PATH_MAX];
284
285	if (exists && nflag) {
286		if (vflag)
287			printf("%s not overwritten\n", to.p_path);
288		return (1);
289	}
290	if ((len = readlink(p->fts_path, llink, sizeof(llink) - 1)) == -1) {
291		warn("readlink: %s", p->fts_path);
292		return (1);
293	}
294	llink[len] = '\0';
295	if (exists && unlink(to.p_path)) {
296		warn("unlink: %s", to.p_path);
297		return (1);
298	}
299	if (symlink(llink, to.p_path)) {
300		warn("symlink: %s", llink);
301		return (1);
302	}
303	return (pflag ? setfile(p->fts_statp, -1) : 0);
304}
305
306int
307copy_fifo(struct stat *from_stat, int exists)
308{
309
310	if (exists && nflag) {
311		if (vflag)
312			printf("%s not overwritten\n", to.p_path);
313		return (1);
314	}
315	if (exists && unlink(to.p_path)) {
316		warn("unlink: %s", to.p_path);
317		return (1);
318	}
319	if (mkfifo(to.p_path, from_stat->st_mode)) {
320		warn("mkfifo: %s", to.p_path);
321		return (1);
322	}
323	return (pflag ? setfile(from_stat, -1) : 0);
324}
325
326int
327copy_special(struct stat *from_stat, int exists)
328{
329
330	if (exists && nflag) {
331		if (vflag)
332			printf("%s not overwritten\n", to.p_path);
333		return (1);
334	}
335	if (exists && unlink(to.p_path)) {
336		warn("unlink: %s", to.p_path);
337		return (1);
338	}
339	if (mknod(to.p_path, from_stat->st_mode, from_stat->st_rdev)) {
340		warn("mknod: %s", to.p_path);
341		return (1);
342	}
343	return (pflag ? setfile(from_stat, -1) : 0);
344}
345
346int
347setfile(struct stat *fs, int fd)
348{
349	static struct timespec tspec[2];
350	struct stat ts;
351	int rval, gotstat, islink, fdval;
352
353	rval = 0;
354	fdval = fd != -1;
355	islink = !fdval && S_ISLNK(fs->st_mode);
356	fs->st_mode &= S_ISUID | S_ISGID | S_ISVTX |
357	    S_IRWXU | S_IRWXG | S_IRWXO;
358
359	tspec[0] = fs->st_atim;
360	tspec[1] = fs->st_mtim;
361	if (fdval ? futimens(fd, tspec) : utimensat(AT_FDCWD, to.p_path, tspec,
362	    islink ? AT_SYMLINK_NOFOLLOW : 0)) {
363		warn("utimensat: %s", to.p_path);
364		rval = 1;
365	}
366	if (fdval ? fstat(fd, &ts) :
367	    (islink ? lstat(to.p_path, &ts) : stat(to.p_path, &ts)))
368		gotstat = 0;
369	else {
370		gotstat = 1;
371		ts.st_mode &= S_ISUID | S_ISGID | S_ISVTX |
372		    S_IRWXU | S_IRWXG | S_IRWXO;
373	}
374	/*
375	 * Changing the ownership probably won't succeed, unless we're root
376	 * or POSIX_CHOWN_RESTRICTED is not set.  Set uid/gid before setting
377	 * the mode; current BSD behavior is to remove all setuid bits on
378	 * chown.  If chown fails, lose setuid/setgid bits.
379	 */
380	if (!gotstat || fs->st_uid != ts.st_uid || fs->st_gid != ts.st_gid)
381		if (fdval ? fchown(fd, fs->st_uid, fs->st_gid) :
382		    (islink ? lchown(to.p_path, fs->st_uid, fs->st_gid) :
383		    chown(to.p_path, fs->st_uid, fs->st_gid))) {
384			if (errno != EPERM) {
385				warn("chown: %s", to.p_path);
386				rval = 1;
387			}
388			fs->st_mode &= ~(S_ISUID | S_ISGID);
389		}
390
391	if (!gotstat || fs->st_mode != ts.st_mode)
392		if (fdval ? fchmod(fd, fs->st_mode) :
393		    (islink ? lchmod(to.p_path, fs->st_mode) :
394		    chmod(to.p_path, fs->st_mode))) {
395			warn("chmod: %s", to.p_path);
396			rval = 1;
397		}
398
399	if (!gotstat || fs->st_flags != ts.st_flags)
400		if (fdval ?
401		    fchflags(fd, fs->st_flags) :
402		    (islink ? lchflags(to.p_path, fs->st_flags) :
403		    chflags(to.p_path, fs->st_flags))) {
404			warn("chflags: %s", to.p_path);
405			rval = 1;
406		}
407
408	return (rval);
409}
410
411int
412preserve_fd_acls(int source_fd, int dest_fd)
413{
414	acl_t acl;
415	acl_type_t acl_type;
416	int acl_supported = 0, ret, trivial;
417
418	ret = fpathconf(source_fd, _PC_ACL_NFS4);
419	if (ret > 0 ) {
420		acl_supported = 1;
421		acl_type = ACL_TYPE_NFS4;
422	} else if (ret < 0 && errno != EINVAL) {
423		warn("fpathconf(..., _PC_ACL_NFS4) failed for %s", to.p_path);
424		return (1);
425	}
426	if (acl_supported == 0) {
427		ret = fpathconf(source_fd, _PC_ACL_EXTENDED);
428		if (ret > 0 ) {
429			acl_supported = 1;
430			acl_type = ACL_TYPE_ACCESS;
431		} else if (ret < 0 && errno != EINVAL) {
432			warn("fpathconf(..., _PC_ACL_EXTENDED) failed for %s",
433			    to.p_path);
434			return (1);
435		}
436	}
437	if (acl_supported == 0)
438		return (0);
439
440	acl = acl_get_fd_np(source_fd, acl_type);
441	if (acl == NULL) {
442		warn("failed to get acl entries while setting %s", to.p_path);
443		return (1);
444	}
445	if (acl_is_trivial_np(acl, &trivial)) {
446		warn("acl_is_trivial() failed for %s", to.p_path);
447		acl_free(acl);
448		return (1);
449	}
450	if (trivial) {
451		acl_free(acl);
452		return (0);
453	}
454	if (acl_set_fd_np(dest_fd, acl, acl_type) < 0) {
455		warn("failed to set acl entries for %s", to.p_path);
456		acl_free(acl);
457		return (1);
458	}
459	acl_free(acl);
460	return (0);
461}
462
463int
464preserve_dir_acls(struct stat *fs, char *source_dir, char *dest_dir)
465{
466	acl_t (*aclgetf)(const char *, acl_type_t);
467	int (*aclsetf)(const char *, acl_type_t, acl_t);
468	struct acl *aclp;
469	acl_t acl;
470	acl_type_t acl_type;
471	int acl_supported = 0, ret, trivial;
472
473	ret = pathconf(source_dir, _PC_ACL_NFS4);
474	if (ret > 0) {
475		acl_supported = 1;
476		acl_type = ACL_TYPE_NFS4;
477	} else if (ret < 0 && errno != EINVAL) {
478		warn("fpathconf(..., _PC_ACL_NFS4) failed for %s", source_dir);
479		return (1);
480	}
481	if (acl_supported == 0) {
482		ret = pathconf(source_dir, _PC_ACL_EXTENDED);
483		if (ret > 0) {
484			acl_supported = 1;
485			acl_type = ACL_TYPE_ACCESS;
486		} else if (ret < 0 && errno != EINVAL) {
487			warn("fpathconf(..., _PC_ACL_EXTENDED) failed for %s",
488			    source_dir);
489			return (1);
490		}
491	}
492	if (acl_supported == 0)
493		return (0);
494
495	/*
496	 * If the file is a link we will not follow it.
497	 */
498	if (S_ISLNK(fs->st_mode)) {
499		aclgetf = acl_get_link_np;
500		aclsetf = acl_set_link_np;
501	} else {
502		aclgetf = acl_get_file;
503		aclsetf = acl_set_file;
504	}
505	if (acl_type == ACL_TYPE_ACCESS) {
506		/*
507		 * Even if there is no ACL_TYPE_DEFAULT entry here, a zero
508		 * size ACL will be returned. So it is not safe to simply
509		 * check the pointer to see if the default ACL is present.
510		 */
511		acl = aclgetf(source_dir, ACL_TYPE_DEFAULT);
512		if (acl == NULL) {
513			warn("failed to get default acl entries on %s",
514			    source_dir);
515			return (1);
516		}
517		aclp = &acl->ats_acl;
518		if (aclp->acl_cnt != 0 && aclsetf(dest_dir,
519		    ACL_TYPE_DEFAULT, acl) < 0) {
520			warn("failed to set default acl entries on %s",
521			    dest_dir);
522			acl_free(acl);
523			return (1);
524		}
525		acl_free(acl);
526	}
527	acl = aclgetf(source_dir, acl_type);
528	if (acl == NULL) {
529		warn("failed to get acl entries on %s", source_dir);
530		return (1);
531	}
532	if (acl_is_trivial_np(acl, &trivial)) {
533		warn("acl_is_trivial() failed on %s", source_dir);
534		acl_free(acl);
535		return (1);
536	}
537	if (trivial) {
538		acl_free(acl);
539		return (0);
540	}
541	if (aclsetf(dest_dir, acl_type, acl) < 0) {
542		warn("failed to set acl entries on %s", dest_dir);
543		acl_free(acl);
544		return (1);
545	}
546	acl_free(acl);
547	return (0);
548}
549
550void
551usage(void)
552{
553
554	(void)fprintf(stderr, "%s\n%s\n",
555	    "usage: cp [-R [-H | -L | -P]] [-f | -i | -n] [-alpsvx] "
556	    "source_file target_file",
557	    "       cp [-R [-H | -L | -P]] [-f | -i | -n] [-alpsvx] "
558	    "source_file ... "
559	    "target_directory");
560	exit(EX_USAGE);
561}
562