xref: /original-bsd/bin/cp/cp.c (revision 1b11f3a3)
1 /*
2  * Copyright (c) 1988 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * David Hitz of Auspex Systems Inc.
7  *
8  * %sccs.include.redist.c%
9  */
10 
11 #ifndef lint
12 char copyright[] =
13 "@(#) Copyright (c) 1988 The Regents of the University of California.\n\
14  All rights reserved.\n";
15 #endif /* not lint */
16 
17 #ifndef lint
18 static char sccsid[] = "@(#)cp.c	5.26 (Berkeley) 10/27/91";
19 #endif /* not lint */
20 
21 /*
22  * cp copies source files to target files.
23  *
24  * The global PATH_T structures "to" and "from" always contain paths to the
25  * current source and target files, respectively.  Since cp does not change
26  * directories, these paths can be either absolute or dot-realative.
27  *
28  * The basic algorithm is to initialize "to" and "from", and then call the
29  * recursive copy() function to do the actual work.  If "from" is a file,
30  * copy copies the data.  If "from" is a directory, copy creates the
31  * corresponding "to" directory, and calls itself recursively on all of
32  * the entries in the "from" directory.
33  */
34 
35 #include <sys/param.h>
36 #include <sys/stat.h>
37 #include <sys/mman.h>
38 #include <sys/time.h>
39 #include <dirent.h>
40 #include <fcntl.h>
41 #include <errno.h>
42 #include <unistd.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include "extern.h"
47 
48 static void copy __P((void));
49 static void copy_dir __P((void));
50 static void copy_fifo __P((struct stat *, int));
51 static void copy_file __P((struct stat *, int));
52 static void copy_link __P((int));
53 static void copy_special __P((struct stat *, int));
54 static void setfile __P((struct stat *, int));
55 static void usage __P((void));
56 
57 PATH_T from = { from.p_path, "" };
58 PATH_T to = { to.p_path, "" };
59 
60 uid_t myuid;
61 int exit_val, myumask;
62 int iflag, pflag, orflag, rflag;
63 int (*statfcn)();
64 char *progname;
65 
66 main(argc, argv)
67 	int argc;
68 	char **argv;
69 {
70 	extern int optind;
71 	struct stat to_stat;
72 	register int c, r;
73 	int symfollow, lstat(), stat();
74 	char *old_to, *p;
75 
76 	/*
77 	 * The utility cp(1) is used by mv(1) -- except for usage statements,
78 	 * print the "called as" program name.
79 	 */
80 	progname = (p = rindex(*argv,'/')) ? ++p : *argv;
81 
82 	symfollow = 0;
83 	while ((c = getopt(argc, argv, "Rfhipr")) != EOF) {
84 	switch ((char)c) {
85 		case 'f':
86 			iflag = 0;
87 			break;
88 		case 'h':
89 			symfollow = 1;
90 			break;
91 		case 'i':
92 			iflag = isatty(fileno(stdin));
93 			break;
94 		case 'p':
95 			pflag = 1;
96 			break;
97 		case 'R':
98 			rflag = 1;
99 			break;
100 		case 'r':
101 			orflag = 1;
102 			break;
103 		case '?':
104 		default:
105 			usage();
106 			break;
107 		}
108 	}
109 	argc -= optind;
110 	argv += optind;
111 
112 	if (argc < 2)
113 		usage();
114 
115 	if (rflag && orflag) {
116 		(void)fprintf(stderr,
117 		    "cp: the -R and -r options are mutually exclusive.\n");
118 		exit(1);
119 	}
120 
121 	myuid = getuid();
122 
123 	/* copy the umask for explicit mode setting */
124 	myumask = umask(0);
125 	(void)umask(myumask);
126 
127 	/* consume last argument first. */
128 	if (!path_set(&to, argv[--argc]))
129 		exit(1);
130 
131 	statfcn = symfollow || !rflag ? stat : lstat;
132 
133 	/*
134 	 * Cp has two distinct cases:
135 	 *
136 	 * % cp [-rip] source target
137 	 * % cp [-rip] source1 ... directory
138 	 *
139 	 * In both cases, source can be either a file or a directory.
140 	 *
141 	 * In (1), the target becomes a copy of the source. That is, if the
142 	 * source is a file, the target will be a file, and likewise for
143 	 * directories.
144 	 *
145 	 * In (2), the real target is not directory, but "directory/source".
146 	 */
147 
148 	r = stat(to.p_path, &to_stat);
149 	if (r == -1 && errno != ENOENT) {
150 		err("%s: %s", to.p_path, strerror(errno));
151 		exit(1);
152 	}
153 	if (r == -1 || !S_ISDIR(to_stat.st_mode)) {
154 		/*
155 		 * Case (1).  Target is not a directory.
156 		 */
157 		if (argc > 1) {
158 			usage();
159 			exit(1);
160 		}
161 		if (!path_set(&from, *argv))
162 			exit(1);
163 		copy();
164 	}
165 	else {
166 		/*
167 		 * Case (2).  Target is a directory.
168 		 */
169 		for (;; ++argv) {
170 			if (!path_set(&from, *argv))
171 				continue;
172 			if (!(old_to =
173 			    path_append(&to, path_basename(&from), -1)))
174 				continue;
175 			copy();
176 			if (!--argc)
177 				break;
178 			path_restore(&to, old_to);
179 		}
180 	}
181 	exit(exit_val);
182 }
183 
184 /* copy file or directory at "from" to "to". */
185 static void
186 copy()
187 {
188 	struct stat from_stat, to_stat;
189 	int dne, statval;
190 
191 	statval = statfcn(from.p_path, &from_stat);
192 	if (statval == -1) {
193 		err("%s: %s", from.p_path, strerror(errno));
194 		return;
195 	}
196 
197 	/* not an error, but need to remember it happened */
198 	if (stat(to.p_path, &to_stat) == -1)
199 		dne = 1;
200 	else {
201 		if (to_stat.st_dev == from_stat.st_dev &&
202 		    to_stat.st_ino == from_stat.st_ino) {
203 			(void)fprintf(stderr,
204 			    "%s: %s and %s are identical (not copied).\n",
205 			    progname, to.p_path, from.p_path);
206 			exit_val = 1;
207 			return;
208 		}
209 		dne = 0;
210 	}
211 
212 	switch(from_stat.st_mode & S_IFMT) {
213 	case S_IFLNK:
214 		copy_link(!dne);
215 		return;
216 	case S_IFDIR:
217 		if (!rflag && !orflag) {
218 			(void)fprintf(stderr,
219 			    "%s: %s is a directory (not copied).\n",
220 			    progname, from.p_path);
221 			exit_val = 1;
222 			return;
223 		}
224 		if (dne) {
225 			/*
226 			 * If the directory doesn't exist, create the new
227 			 * one with the from file mode plus owner RWX bits,
228 			 * modified by the umask.  Trade-off between being
229 			 * able to write the directory (if from directory is
230 			 * 555) and not causing a permissions race.  If the
231 			 * umask blocks owner writes cp fails.
232 			 */
233 			if (mkdir(to.p_path, from_stat.st_mode|S_IRWXU) < 0) {
234 				err("%s: %s", to.p_path, strerror(errno));
235 				return;
236 			}
237 		}
238 		else if (!S_ISDIR(to_stat.st_mode)) {
239 			(void)fprintf(stderr, "%s: %s: not a directory.\n",
240 			    progname, to.p_path);
241 			return;
242 		}
243 		copy_dir();
244 		/*
245 		 * If not -p and directory didn't exist, set it to be the
246 		 * same as the from directory, umodified by the umask;
247 		 * arguably wrong, but it's been that way forever.
248 		 */
249 		if (pflag)
250 			setfile(&from_stat, 0);
251 		else if (dne)
252 			(void)chmod(to.p_path, from_stat.st_mode);
253 		return;
254 	case S_IFCHR:
255 	case S_IFBLK:
256 		if (rflag) {
257 			copy_special(&from_stat, !dne);
258 			return;
259 		}
260 		break;
261 	case S_IFIFO:
262 		if (rflag) {
263 			copy_fifo(&from_stat, !dne);
264 			return;
265 		}
266 		break;
267 	}
268 	copy_file(&from_stat, dne);
269 }
270 
271 static void
272 copy_file(fs, dne)
273 	struct stat *fs;
274 	int dne;
275 {
276 	static char buf[MAXBSIZE];
277 	register int from_fd, to_fd, rcount, wcount;
278 	struct stat to_stat;
279 	char *p;
280 
281 	if ((from_fd = open(from.p_path, O_RDONLY, 0)) == -1) {
282 		err("%s: %s", from.p_path, strerror(errno));
283 		return;
284 	}
285 
286 	/*
287 	 * If the file exists and we're interactive, verify with the user.
288 	 * If the file DNE, set the mode to be the from file, minus setuid
289 	 * bits, modified by the umask; arguably wrong, but it makes copying
290 	 * executables work right and it's been that way forever.  (The
291 	 * other choice is 666 or'ed with the execute bits on the from file
292 	 * modified by the umask.)
293 	 */
294 	if (!dne) {
295 		if (iflag) {
296 			int checkch, ch;
297 
298 			(void)fprintf(stderr, "overwrite %s? ", to.p_path);
299 			checkch = ch = getchar();
300 			while (ch != '\n' && ch != EOF)
301 				ch = getchar();
302 			if (checkch != 'y') {
303 				(void)close(from_fd);
304 				return;
305 			}
306 		}
307 		to_fd = open(to.p_path, O_WRONLY|O_TRUNC, 0);
308 	} else
309 		to_fd = open(to.p_path, O_WRONLY|O_CREAT|O_TRUNC,
310 		    fs->st_mode & ~(S_ISUID|S_ISGID));
311 
312 	if (to_fd == -1) {
313 		err("%s: %s", to.p_path, strerror(errno));
314 		(void)close(from_fd);
315 		return;
316 	}
317 
318 	/*
319 	 * Mmap and write if less than 8M (the limit is so we don't totally
320 	 * trash memory on big files.  This is really a minor hack, but it
321 	 * wins some CPU back.
322 	 */
323 	if (fs->st_size <= 8 * 1048576) {
324 		if ((p = mmap(NULL, fs->st_size, PROT_READ,
325 		    MAP_FILE, from_fd, (off_t)0)) == (char *)-1)
326 			err("%s: %s", from.p_path, strerror(errno));
327 		if (write(to_fd, p, fs->st_size) != fs->st_size)
328 			err("%s: %s", to.p_path, strerror(errno));
329 	} else {
330 		while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) {
331 			wcount = write(to_fd, buf, rcount);
332 			if (rcount != wcount || wcount == -1) {
333 				err("%s: %s", to.p_path, strerror(errno));
334 				break;
335 			}
336 		}
337 		if (rcount < 0)
338 			err("%s: %s", from.p_path, strerror(errno));
339 	}
340 	if (pflag)
341 		setfile(fs, to_fd);
342 	/*
343 	 * If the source was setuid or setgid, lose the bits unless the
344 	 * copy is owned by the same user and group.
345 	 */
346 	else if (fs->st_mode & (S_ISUID|S_ISGID) && fs->st_uid == myuid)
347 		if (fstat(to_fd, &to_stat))
348 			err("%s: %s", to.p_path, strerror(errno));
349 #define	RETAINBITS	(S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)
350 		else if (fs->st_gid == to_stat.st_gid && fchmod(to_fd,
351 		    fs->st_mode & RETAINBITS & ~myumask))
352 			err("%s: %s", to.p_path, strerror(errno));
353 	(void)close(from_fd);
354 	if (close(to_fd))
355 		err("%s: %s", to.p_path, strerror(errno));
356 }
357 
358 static void
359 copy_dir()
360 {
361 	struct stat from_stat;
362 	struct dirent *dp, **dir_list;
363 	register int dir_cnt, i;
364 	char *old_from, *old_to;
365 
366 	dir_cnt = scandir(from.p_path, &dir_list, NULL, NULL);
367 	if (dir_cnt == -1) {
368 		(void)fprintf(stderr, "%s: can't read directory %s.\n",
369 		    progname, from.p_path);
370 		exit_val = 1;
371 	}
372 
373 	/*
374 	 * Instead of handling directory entries in the order they appear
375 	 * on disk, do non-directory files before directory files.
376 	 * There are two reasons to do directories last.  The first is
377 	 * efficiency.  Files tend to be in the same cylinder group as
378 	 * their parent, whereas directories tend not to be.  Copying files
379 	 * all at once reduces seeking.  Second, deeply nested tree's
380 	 * could use up all the file descriptors if we didn't close one
381 	 * directory before recursivly starting on the next.
382 	 */
383 	/* copy files */
384 	for (i = 0; i < dir_cnt; ++i) {
385 		dp = dir_list[i];
386 		if (dp->d_namlen <= 2 && dp->d_name[0] == '.'
387 		    && (dp->d_name[1] == NULL || dp->d_name[1] == '.'))
388 			goto done;
389 		if (!(old_from =
390 		    path_append(&from, dp->d_name, (int)dp->d_namlen)))
391 			goto done;
392 
393 		if (statfcn(from.p_path, &from_stat) < 0) {
394 			err("%s: %s", dp->d_name, strerror(errno));
395 			path_restore(&from, old_from);
396 			goto done;
397 		}
398 		if (S_ISDIR(from_stat.st_mode)) {
399 			path_restore(&from, old_from);
400 			continue;
401 		}
402 		if (old_to = path_append(&to, dp->d_name, (int)dp->d_namlen)) {
403 			copy();
404 			path_restore(&to, old_to);
405 		}
406 		path_restore(&from, old_from);
407 done:		dir_list[i] = NULL;
408 		free(dp);
409 	}
410 
411 	/* copy directories */
412 	for (i = 0; i < dir_cnt; ++i) {
413 		dp = dir_list[i];
414 		if (!dp)
415 			continue;
416 		if (!(old_from =
417 		    path_append(&from, dp->d_name, (int)dp->d_namlen))) {
418 			free(dp);
419 			continue;
420 		}
421 		if (!(old_to =
422 		    path_append(&to, dp->d_name, (int)dp->d_namlen))) {
423 			free(dp);
424 			path_restore(&from, old_from);
425 			continue;
426 		}
427 		copy();
428 		free(dp);
429 		path_restore(&from, old_from);
430 		path_restore(&to, old_to);
431 	}
432 	free(dir_list);
433 }
434 
435 static void
436 copy_link(exists)
437 	int exists;
438 {
439 	int len;
440 	char link[MAXPATHLEN];
441 
442 	if ((len = readlink(from.p_path, link, sizeof(link))) == -1) {
443 		err("readlink: %s: %s", from.p_path, strerror(errno));
444 		return;
445 	}
446 	link[len] = '\0';
447 	if (exists && unlink(to.p_path)) {
448 		err("unlink: %s: %s", to.p_path, strerror(errno));
449 		return;
450 	}
451 	if (symlink(link, to.p_path)) {
452 		err("symlink: %s: %s", link, strerror(errno));
453 		return;
454 	}
455 }
456 
457 static void
458 copy_fifo(from_stat, exists)
459 	struct stat *from_stat;
460 	int exists;
461 {
462 	if (exists && unlink(to.p_path)) {
463 		err("unlink: %s: %s", to.p_path, strerror(errno));
464 		return;
465 	}
466 	if (mkfifo(to.p_path, from_stat->st_mode)) {
467 		err("mkfifo: %s: %s", to.p_path, strerror(errno));
468 		return;
469 	}
470 	if (pflag)
471 		setfile(from_stat, 0);
472 }
473 
474 static void
475 copy_special(from_stat, exists)
476 	struct stat *from_stat;
477 	int exists;
478 {
479 	if (exists && unlink(to.p_path)) {
480 		err("unlink: %s: %s", to.p_path, strerror(errno));
481 		return;
482 	}
483 	if (mknod(to.p_path, from_stat->st_mode,  from_stat->st_rdev)) {
484 		err("mknod: %s: %s", to.p_path, strerror(errno));
485 		return;
486 	}
487 	if (pflag)
488 		setfile(from_stat, 0);
489 }
490 
491 static void
492 setfile(fs, fd)
493 	register struct stat *fs;
494 	int fd;
495 {
496 	static struct timeval tv[2];
497 
498 	fs->st_mode &= S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO;
499 
500 	tv[0].tv_sec = fs->st_atime;
501 	tv[1].tv_sec = fs->st_mtime;
502 	if (utimes(to.p_path, tv))
503 		err("utimes: %s: %s", to.p_path, strerror(errno));
504 	/*
505 	 * Changing the ownership probably won't succeed, unless we're root
506 	 * or POSIX_CHOWN_RESTRICTED is not set.  Set uid/gid before setting
507 	 * the mode; current BSD behavior is to remove all setuid bits on
508 	 * chown.  If chown fails, lose setuid/setgid bits.
509 	 */
510 	if (fd ? fchown(fd, fs->st_uid, fs->st_gid) :
511 	    chown(to.p_path, fs->st_uid, fs->st_gid)) {
512 		if (errno != EPERM)
513 			err("chown: %s: %s", to.p_path, strerror(errno));
514 		fs->st_mode &= ~(S_ISUID|S_ISGID);
515 	}
516 	if (fd ? fchmod(fd, fs->st_mode) : chmod(to.p_path, fs->st_mode))
517 		err("chown: %s: %s", to.p_path, strerror(errno));
518 }
519 
520 static void
521 usage()
522 {
523 	(void)fprintf(stderr,
524 "usage: cp [-Rfhip] src target;\n       cp [-Rfhip] src1 ... srcN directory\n");
525 	exit(1);
526 }
527 
528 #if __STDC__
529 #include <stdarg.h>
530 #else
531 #include <varargs.h>
532 #endif
533 
534 void
535 #if __STDC__
536 err(const char *fmt, ...)
537 #else
538 err(fmt, va_alist)
539 	char *fmt;
540         va_dcl
541 #endif
542 {
543 	va_list ap;
544 #if __STDC__
545 	va_start(ap, fmt);
546 #else
547 	va_start(ap);
548 #endif
549 	(void)fprintf(stderr, "%s: ", progname);
550 	(void)vfprintf(stderr, fmt, ap);
551 	va_end(ap);
552 	(void)fprintf(stderr, "\n");
553 	exit_val = 1;
554 }
555