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