xref: /original-bsd/bin/cp/cp.c (revision 8431ec24)
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  * Redistribution and use in source and binary forms are permitted
9  * provided that the above copyright notice and this paragraph are
10  * duplicated in all such forms and that any documentation,
11  * advertising materials, and other materials related to such
12  * distribution and use acknowledge that the software was developed
13  * by the University of California, Berkeley.  The name of the
14  * University may not be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19  */
20 
21 #ifndef lint
22 char copyright[] =
23 "@(#) Copyright (c) 1988 The Regents of the University of California.\n\
24  All rights reserved.\n";
25 #endif /* not lint */
26 
27 #ifndef lint
28 static char sccsid[] = "@(#)cp.c	5.15 (Berkeley) 03/05/90";
29 #endif /* not lint */
30 
31 /*
32  * cp copies source files to target files.
33  *
34  * The global PATH_T structures "to" and "from" always contain paths to the
35  * current source and target files, respectively.  Since cp does not change
36  * directories, these paths can be either absolute or dot-realative.
37  *
38  * The basic algorithm is to initialize "to" and "from", and then call the
39  * recursive copy() function to do the actual work.  If "from" is a file,
40  * copy copies the data.  If "from" is a directory, copy creates the
41  * corresponding "to" directory, and calls itself recursively on all of
42  * the entries in the "from" directory.
43  */
44 
45 #include <sys/param.h>
46 #include <sys/stat.h>
47 #include <sys/file.h>
48 #include <sys/dir.h>
49 #include <sys/time.h>
50 #include <stdio.h>
51 #include <errno.h>
52 #include <strings.h>
53 
54 #define	type(st)	((st).st_mode & S_IFMT)
55 
56 typedef struct {
57 	char	p_path[MAXPATHLEN + 1];	/* pointer to the start of a path. */
58 	char	*p_end;			/* pointer to NULL at end of path. */
59 } PATH_T;
60 
61 PATH_T from = { "", from.p_path };
62 PATH_T to = { "", to.p_path };
63 
64 extern int errno;
65 uid_t myuid;
66 int exit_val, myumask;
67 int interactive_flag, preserve_flag, recursive_flag;
68 int (*statfcn)();
69 char *buf, *pname;
70 char *path_append(), *path_basename();
71 
72 main(argc, argv)
73 	int argc;
74 	char **argv;
75 {
76 	extern int optind;
77 	struct stat to_stat;
78 	register int c, r;
79 	int force_flag, symfollow, lstat(), stat();
80 	char *old_to, *p, *malloc();
81 
82 	/*
83 	 * cp is used by mv(1) -- except for usage statements, print
84 	 * the "called as" program name.
85 	 */
86 	pname = (p = rindex(*argv,'/')) ? ++p : *argv;
87 
88 	force_flag = symfollow = 0;
89 	while ((c = getopt(argc, argv, "Rfhipr")) != EOF) {
90 	switch ((char)c) {
91 		case 'f':
92 			force_flag = 1;
93 			break;
94 		case 'h':
95 			symfollow = 1;
96 			break;
97 		case 'i':
98 			interactive_flag = isatty(fileno(stdin));
99 			break;
100 		case 'p':
101 			preserve_flag = 1;
102 			break;
103 		case 'r':
104 		case 'R':
105 			recursive_flag = 1;
106 			break;
107 		case '?':
108 		default:
109 			usage();
110 			break;
111 		}
112 	}
113 	argc -= optind;
114 	argv += optind;
115 
116 	if (argc < 2)
117 		usage();
118 
119 	if (force_flag)
120 		interactive_flag = 0;
121 
122 	buf = (char *)malloc(MAXBSIZE);
123 	if (!buf) {
124 		(void)fprintf(stderr, "%s: out of space.\n", pname);
125 		exit(1);
126 	}
127 
128 	myuid = getuid();
129 
130 	/* copy the umask for explicit mode setting */
131 	myumask = umask(0);
132 	(void)umask(myumask);
133 
134 	/* consume last argument first. */
135 	if (!path_set(&to, argv[--argc]))
136 		exit(exit_val);
137 
138 	statfcn = symfollow || !recursive_flag ? stat : lstat;
139 
140 	/*
141 	 * Cp has two distinct cases:
142 	 *
143 	 * Case (1)	  $ cp [-rip] source target
144 	 *
145 	 * Case (2)	  $ cp [-rip] source1 ... directory
146 	 *
147 	 * In both cases, source can be either a file or a directory.
148 	 *
149 	 * In (1), the target becomes a copy of the source. That is, if the
150 	 * source is a file, the target will be a file, and likewise for
151 	 * directories.
152 	 *
153 	 * In (2), the real target is not directory, but "directory/source".
154 	 */
155 
156 	r = stat(to.p_path, &to_stat);
157 	if (r == -1 && errno != ENOENT) {
158 		error(to.p_path);
159 		exit(1);
160 	}
161 	if (r == -1 || type(to_stat) != S_IFDIR) {
162 		/*
163 		 * Case (1).  Target is not a directory.
164 		 */
165 		if (argc > 1) {
166 			usage();
167 			exit(1);
168 		}
169 		if (!path_set(&from, *argv))
170 			exit(exit_val);
171 		copy();
172 	}
173 	else {
174 		/*
175 		 * Case (2).  Target is a directory.
176 		 */
177 		for (;; ++argv) {
178 			if (!path_set(&from, *argv))
179 				continue;
180 			old_to = path_append(&to, path_basename(&from), -1);
181 			if (!old_to)
182 				continue;
183 			copy();
184 			if (!--argc)
185 				break;
186 			path_restore(&to, old_to);
187 		}
188 	}
189 	exit(exit_val);
190 }
191 
192 /* copy file or directory at "from" to "to". */
193 copy()
194 {
195 	struct stat from_stat, to_stat;
196 	int dne, statval;
197 
198 	statval = statfcn(from.p_path, &from_stat);
199 	if (statval == -1) {
200 		error(from.p_path);
201 		return;
202 	}
203 
204 	/* not an error, but need to remember it happened */
205 	if (stat(to.p_path, &to_stat) == -1)
206 		dne = 1;
207 	else {
208 		if (to_stat.st_dev == from_stat.st_dev &&
209 		    to_stat.st_ino == from_stat.st_ino) {
210 			(void)fprintf(stderr,
211 			    "%s: %s and %s are identical (not copied).\n",
212 			    pname, to.p_path, from.p_path);
213 			exit_val = 1;
214 			return;
215 		}
216 		dne = 0;
217 	}
218 
219 	switch(type(from_stat)) {
220 	case S_IFLNK:
221 		copy_link(!dne);
222 		return;
223 	case S_IFDIR:
224 		if (!recursive_flag) {
225 			(void)fprintf(stderr,
226 			    "%s: %s is a directory (not copied).\n",
227 			    pname, from.p_path);
228 			exit_val = 1;
229 			return;
230 		}
231 		if (dne) {
232 			/*
233 			 * If the directory doesn't exist, create the new
234 			 * one with the from file mode plus owner RWX bits,
235 			 * modified by the umask.  Trade-off between being
236 			 * able to write the directory (if from directory is
237 			 * 555) and not causing a permissions race.  If the
238 			 * umask blocks owner writes cp fails.
239 			 */
240 			if (mkdir(to.p_path, from_stat.st_mode|S_IRWXU) < 0) {
241 				error(to.p_path);
242 				return;
243 			}
244 		}
245 		else if (type(to_stat) != S_IFDIR) {
246 			(void)fprintf(stderr, "%s: %s: not a directory.\n",
247 			    pname, to.p_path);
248 			return;
249 		}
250 		copy_dir();
251 		/*
252 		 * If not -p and directory didn't exist, set it to be the
253 		 * same as the from directory, umodified by the umask;
254 		 * arguably wrong, but it's been that way forever.
255 		 */
256 		if (preserve_flag)
257 			setfile(&from_stat, 0);
258 		else if (dne)
259 			(void)chmod(to.p_path, from_stat.st_mode);
260 		break;
261 	case S_IFCHR:
262 	case S_IFBLK:
263 		/*
264 		 * if recursive flag on, try and create the special device
265 		 * otherwise copy the contents.
266 		 */
267 		if (recursive_flag) {
268 			copy_special(&from_stat, !dne);
269 			if (preserve_flag)
270 				setfile(&from_stat, 0);
271 			return;
272 		}
273 		/* FALLTHROUGH */
274 	default:
275 		copy_file(&from_stat, dne);
276 	}
277 }
278 
279 copy_file(fs, dne)
280 	struct stat *fs;
281 	int dne;
282 {
283 	register int from_fd, to_fd, rcount, wcount;
284 	struct stat to_stat;
285 
286 	if ((from_fd = open(from.p_path, O_RDONLY, 0)) == -1) {
287 		error(from.p_path);
288 		return;
289 	}
290 
291 	/*
292 	 * If the file exists and we're interactive, verify with the user.
293 	 * If the file DNE, set the mode to be the from file, minus setuid
294 	 * bits, modified by the umask; arguably wrong, but it makes copying
295 	 * executables work right and it's been that way forever.  (The
296 	 * other choice is 666 or'ed with the execute bits on the from file
297 	 * modified by the umask.)
298 	 */
299 	if (!dne) {
300 		if (interactive_flag) {
301 			int checkch, ch;
302 
303 			(void)fprintf(stderr, "overwrite %s? ", to.p_path);
304 			checkch = ch = getchar();
305 			while (ch != '\n' && ch != EOF)
306 				ch = getchar();
307 			if (checkch != 'y') {
308 				(void)close(from_fd);
309 				return;
310 			}
311 		}
312 		to_fd = open(to.p_path, O_WRONLY|O_TRUNC, 0);
313 	} else
314 		to_fd = open(to.p_path, O_WRONLY|O_CREAT|O_TRUNC,
315 		    fs->st_mode & ~(S_ISUID|S_ISGID));
316 
317 	if (to_fd == -1) {
318 		error(to.p_path);
319 		(void)close(from_fd);
320 		return;
321 	}
322 
323 	while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) {
324 		wcount = write(to_fd, buf, rcount);
325 		if (rcount != wcount || wcount == -1) {
326 			error(to.p_path);
327 			break;
328 		}
329 	}
330 	if (rcount < 0)
331 		error(from.p_path);
332 	if (preserve_flag)
333 		setfile(fs, to_fd);
334 	/*
335 	 * If the source was setuid, set the bits on the copy if the copy
336 	 * was created and is owned by the same uid.  If the source was
337 	 * setgid, set the bits on the copy if the copy was created and is
338 	 * owned by the same gid and the user is a member of that group.
339 	 * If both setuid and setgid, lose both bits unless all the above
340 	 * conditions are met.
341 	 */
342 	else if (fs->st_mode & (S_ISUID|S_ISGID)) {
343 		if (fs->st_mode & S_ISUID && myuid != fs->st_uid)
344 			fs->st_mode &= ~(S_ISUID|S_ISGID);
345 		if (fs->st_mode & S_ISGID) {
346 			if (fstat(to_fd, &to_stat)) {
347 				error(to.p_path);
348 				fs->st_mode &= ~(S_ISUID|S_ISGID);
349 			}
350 			else if (fs->st_gid != to_stat.st_gid ||
351 			    !ismember(fs->st_gid))
352 				fs->st_mode &= ~(S_ISUID|S_ISGID);
353 		}
354 		if (fs->st_mode & (S_ISUID|S_ISGID) && fchmod(to_fd,
355 		    fs->st_mode & (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO) &
356 		    ~myumask))
357 			error(to.p_path);
358 	}
359 	(void)close(from_fd);
360 	(void)close(to_fd);
361 }
362 
363 copy_dir()
364 {
365 	struct stat from_stat;
366 	struct direct *dp, **dir_list;
367 	register int dir_cnt, i;
368 	char *old_from, *old_to;
369 
370 	dir_cnt = scandir(from.p_path, &dir_list, NULL, NULL);
371 	if (dir_cnt == -1) {
372 		(void)fprintf(stderr, "%s: can't read directory %s.\n",
373 		    pname, from.p_path);
374 		exit_val = 1;
375 	}
376 
377 	/*
378 	 * Instead of handling directory entries in the order they appear
379 	 * on disk, do non-directory files before directory files.
380 	 * There are two reasons to do directories last.  The first is
381 	 * efficiency.  Files tend to be in the same cylinder group as
382 	 * their parent, whereas directories tend not to be.  Copying files
383 	 * all at once reduces seeking.  Second, deeply nested tree's
384 	 * could use up all the file descriptors if we didn't close one
385 	 * directory before recursivly starting on the next.
386 	 */
387 	/* copy files */
388 	for (i = 0; i < dir_cnt; ++i) {
389 		dp = dir_list[i];
390 		if (dp->d_namlen <= 2 && dp->d_name[0] == '.'
391 		    && (dp->d_name[1] == NULL || dp->d_name[1] == '.'))
392 			goto done;
393 		old_from = path_append(&from, dp->d_name, (int)dp->d_namlen);
394 		if (!old_from)
395 			goto done;
396 
397 		if (statfcn(from.p_path, &from_stat) < 0) {
398 			error(dp->d_name);
399 			path_restore(&from, old_from);
400 			goto done;
401 		}
402 		if (type(from_stat) == S_IFDIR) {
403 			path_restore(&from, old_from);
404 			continue;
405 		}
406 		old_to = path_append(&to, dp->d_name, (int)dp->d_namlen);
407 		if (old_to) {
408 			copy();
409 			path_restore(&to, old_to);
410 		}
411 		path_restore(&from, old_from);
412 done:		dir_list[i] = NULL;
413 		(void)free((char *)dp);
414 	}
415 
416 	/* copy directories */
417 	for (i = 0; i < dir_cnt; ++i) {
418 		dp = dir_list[i];
419 		if (!dp)
420 			continue;
421 		old_from = path_append(&from, dp->d_name, (int) dp->d_namlen);
422 		if (!old_from) {
423 			(void)free((char *)dp);
424 			continue;
425 		}
426 		old_to = path_append(&to, dp->d_name, (int) dp->d_namlen);
427 		if (!old_to) {
428 			(void)free((char *)dp);
429 			path_restore(&from, old_from);
430 			continue;
431 		}
432 		copy();
433 		free((char *)dp);
434 		path_restore(&from, old_from);
435 		path_restore(&to, old_to);
436 	}
437 	free((char *)dir_list);
438 }
439 
440 copy_link(exists)
441 	int exists;
442 {
443 	int len;
444 	char link[MAXPATHLEN];
445 
446 	if ((len = readlink(from.p_path, link, sizeof(link))) == -1) {
447 		error(from.p_path);
448 		return;
449 	}
450 	link[len] = '\0';
451 	if (exists && unlink(to.p_path)) {
452 		error(to.p_path);
453 		return;
454 	}
455 	if (symlink(link, to.p_path)) {
456 		error(link);
457 		return;
458 	}
459 }
460 
461 copy_special(from_stat, exists)
462 	struct stat *from_stat;
463 	int exists;
464 {
465 	if (exists && unlink(to.p_path)) {
466 		error(to.p_path);
467 		return;
468 	}
469 	if (mknod(to.p_path, from_stat->st_mode,  from_stat->st_rdev)) {
470 		error(to.p_path);
471 		return;
472 	}
473 }
474 
475 setfile(fs, fd)
476 	register struct stat *fs;
477 	int fd;
478 {
479 	static struct timeval tv[2];
480 
481 	tv[0].tv_sec = fs->st_atime;
482 	tv[1].tv_sec = fs->st_mtime;
483 	if (utimes(to.p_path, tv))
484 		error(to.p_path);
485 	/*
486 	 * Changing the ownership probably won't succeed, unless we're root
487 	 * or POSIX_CHOWN_RESTRICTED is not set.  Set uid before setting the
488 	 * mode; current BSD behavior is to remove all setuid bits on chown.
489 	 * If setuid, lose the bits if chown fails.
490 	 * If setgid, lose the bits if chgrp fails.
491 	 * If both, lose the bits if either fails.
492 	 */
493 	if ((fd ?
494 	    fchown(fd, fs->st_uid, -1) : chown(to.p_path, fs->st_uid, -1))) {
495 		if (errno != EPERM)
496 			error(to.p_path);
497 		if (fs->st_mode & S_ISUID)
498 			fs->st_mode &= ~(S_ISUID|S_ISGID);
499 	}
500 	if ((fd ?
501 	    fchown(fd, -1, fs->st_gid) : chown(to.p_path, -1, fs->st_gid))) {
502 		if (errno != EPERM)
503 			error(to.p_path);
504 		if (fs->st_mode & S_ISGID)
505 			fs->st_mode &= ~(S_ISUID|S_ISGID);
506 	}
507 	fs->st_mode &= S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO;
508 	if (fd ? fchmod(fd, fs->st_mode) : chmod(to.p_path, fs->st_mode))
509 		error(to.p_path);
510 }
511 
512 ismember(gid)
513 	gid_t gid;
514 {
515 	register int cnt;
516 	static int ngroups, groups[NGROUPS];
517 
518 	if (!ngroups) {
519 		ngroups = getgroups(NGROUPS, groups);
520 		if (ngroups == -1) {
521 			ngroups = 0;
522 			exit_val = 1;
523 			(void)fprintf(stderr, "%s: %s\n",
524 			    pname, strerror(errno));
525 			return(0);
526 		}
527 	}
528 	for (cnt = ngroups; cnt--;)
529 		if (gid == groups[cnt])
530 			return(1);
531 	return(0);
532 }
533 
534 error(s)
535 	char *s;
536 {
537 	exit_val = 1;
538 	(void)fprintf(stderr, "%s: %s: %s\n", pname, s, strerror(errno));
539 }
540 
541 /********************************************************************
542  * Path Manipulation Routines.
543  ********************************************************************/
544 
545 /*
546  * These functions manipulate paths in PATH_T structures.
547  *
548  * They eliminate multiple slashes in paths when they notice them, and keep
549  * the path non-slash terminated.
550  *
551  * Both path_set() and path_append() return 0 if the requested name
552  * would be too long.
553  */
554 
555 #define	STRIP_TRAILING_SLASH(p) { \
556 	while ((p)->p_end > (p)->p_path && (p)->p_end[-1] == '/') \
557 		*--(p)->p_end = 0; \
558 	}
559 
560 /*
561  * Move specified string into path.  Convert "" to "." to handle BSD
562  * semantics for a null path.  Strip trailing slashes.
563  */
564 path_set(p, string)
565 	register PATH_T *p;
566 	char *string;
567 {
568 	if (strlen(string) > MAXPATHLEN) {
569 		(void)fprintf(stderr, "%s: %s: name too long.\n",
570 		    pname, string);
571 		exit_val = 1;
572 		return(0);
573 	}
574 
575 	(void)strcpy(p->p_path, string);
576 	p->p_end = p->p_path + strlen(p->p_path);
577 
578 	if (p->p_path == p->p_end) {
579 		*p->p_end++ = '.';
580 		*p->p_end = 0;
581 	}
582 
583 	STRIP_TRAILING_SLASH(p);
584 	return(1);
585 }
586 
587 /*
588  * Append specified string to path, inserting '/' if necessary.  Return a
589  * pointer to the old end of path for restoration.
590  */
591 char *
592 path_append(p, name, len)
593 	register PATH_T *p;
594 	char *name;
595 	int len;
596 {
597 	char *old;
598 
599 	old = p->p_end;
600 	if (len == -1)
601 		len = strlen(name);
602 
603 	/*
604 	 * The final "+ 1" accounts for the '/' between old path and name.
605 	 */
606 	if ((len + p->p_end - p->p_path + 1) > MAXPATHLEN) {
607 		(void)fprintf(stderr,
608 		    "%s: %s/%s: name too long.\n", pname, p->p_path, name);
609 		exit_val = 1;
610 		return(0);
611 	}
612 
613 	/*
614 	 * This code should always be executed, since paths shouldn't
615 	 * end in '/'.
616 	 */
617 	if (p->p_end[-1] != '/') {
618 		*p->p_end++ = '/';
619 		*p->p_end = 0;
620 	}
621 
622 	(void)strncat(p->p_end, name, len);
623 	p->p_end += len;
624 	*p->p_end = 0;
625 
626 	STRIP_TRAILING_SLASH(p);
627 	return(old);
628 }
629 
630 /*
631  * Restore path to previous value.  (As returned by path_append.)
632  */
633 path_restore(p, old)
634 	PATH_T *p;
635 	char *old;
636 {
637 	p->p_end = old;
638 	*p->p_end = 0;
639 }
640 
641 /*
642  * Return basename of path.  (Like basename(1).)
643  */
644 char *
645 path_basename(p)
646 	PATH_T *p;
647 {
648 	char *basename;
649 
650 	basename = rindex(p->p_path, '/');
651 	return(basename ? ++basename : p->p_path);
652 }
653 
654 usage()
655 {
656 	(void)fprintf(stderr,
657 "usage: cp [-fhipr] src target;\n   or: cp [-fhipr] src1 ... srcN directory\n");
658 	exit(1);
659 }
660