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