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