cp.c (28500B)
1 /* 2 * cp - copy files 3 * 4 * Gunnar Ritter, Freiburg i. Br., Germany, July 2002. 5 */ 6 /* 7 * Copyright (c) 2003 Gunnar Ritter 8 * 9 * This software is provided 'as-is', without any express or implied 10 * warranty. In no event will the authors be held liable for any damages 11 * arising from the use of this software. 12 * 13 * Permission is granted to anyone to use this software for any purpose, 14 * including commercial applications, and to alter it and redistribute 15 * it freely, subject to the following restrictions: 16 * 17 * 1. The origin of this software must not be misrepresented; you must not 18 * claim that you wrote the original software. If you use this software 19 * in a product, an acknowledgment in the product documentation would be 20 * appreciated but is not required. 21 * 22 * 2. Altered source versions must be plainly marked as such, and must not be 23 * misrepresented as being the original software. 24 * 25 * 3. This notice may not be removed or altered from any source distribution. 26 */ 27 28 #if __GNUC__ >= 3 && __GNUC_MINOR__ >= 4 || __GNUC__ >= 4 29 #define USED __attribute__ ((used)) 30 #elif defined __GNUC__ 31 #define USED __attribute__ ((unused)) 32 #else 33 #define USED 34 #endif 35 #if defined (SUS) 36 static const char sccsid[] USED = "@(#)cp_sus.sl 1.84 (gritter) 3/4/06"; 37 #elif defined (S42) 38 static const char sccsid[] USED = "@(#)cp_s42.sl 1.84 (gritter) 3/4/06"; 39 #else 40 static const char sccsid[] USED = "@(#)cp.sl 1.84 (gritter) 3/4/06"; 41 #endif 42 43 #include <sys/types.h> 44 #include <sys/stat.h> 45 #include <sys/socket.h> 46 #include <sys/un.h> 47 #include <sys/time.h> 48 #include <sys/resource.h> 49 #include <fcntl.h> 50 #include <unistd.h> 51 #include <stdio.h> 52 #include <string.h> 53 #include <stdlib.h> 54 #include <malloc.h> 55 #include <errno.h> 56 #include <libgen.h> 57 #include <limits.h> 58 #include <dirent.h> 59 #include <utime.h> 60 #include "sfile.h" 61 #include "memalign.h" 62 #include "alloca.h" 63 64 #ifndef S_IFDOOR 65 #define S_IFDOOR 0xD000 /* Solaris door */ 66 #endif 67 #ifndef S_IFNAM 68 #define S_IFNAM 0x5000 /* XENIX special named file */ 69 #endif 70 #ifndef S_IFNWK 71 #define S_IFNWK 0x9000 /* HP-UX network special file */ 72 #endif 73 74 static enum { 75 PERS_CP, 76 PERS_MV, 77 PERS_LN 78 } pers; 79 80 enum okay { 81 OKAY = 0, 82 STOP = 1 83 }; 84 85 struct islot { 86 struct islot *i_lln; 87 struct islot *i_rln; 88 char *i_name; 89 ino_t i_ino; 90 }; 91 92 struct dslot { 93 struct dslot *d_nxt; 94 struct islot *d_isl; 95 dev_t d_dev; 96 }; 97 98 static struct dslot *d0; 99 100 static unsigned errcnt; /* count of errors */ 101 static long bflag; /* buffer size */ 102 static int dflag; /* preserve hard links */ 103 #ifdef O_DIRECT 104 static int Dflag; /* use direct i/o */ 105 #endif /* O_DIRECT */ 106 static int fflag; /* force */ 107 static int iflag; /* ask before overwriting */ 108 static int nflag; /* ln: do not remove links */ 109 static int pflag; /* preserve owner and times */ 110 static int rflag; /* recursive, read FIFOs */ 111 static int Rflag; /* recursive, recreate FIFOs */ 112 static int sflag; /* make symlinks / show statistics */ 113 static int HLPflag; /* -H, -L, or -P */ 114 static int ontty; /* stdin is a terminal */ 115 static mode_t umsk; /* current umask */ 116 static uid_t myuid; /* current uid */ 117 static gid_t mygid; /* current gid */ 118 static char *progname; /* argv[0] to main() */ 119 static struct islot *inull; /* inode tree null element */ 120 static void (*go)(const char *, const char *, struct stat *, int, 121 int (*statfn)(const char *, struct stat *)); 122 123 static mode_t 124 check_suid(const struct stat *sp, mode_t mode) 125 { 126 if (sp->st_uid != myuid || sp->st_gid != mygid) { 127 mode &= ~(mode_t)S_ISUID; 128 if ((sp->st_mode&S_IFMT) != S_IFDIR || sp->st_mode&0010) 129 mode &= ~(mode_t)S_ISGID; 130 if ((sp->st_mode&S_IFMT) == S_IFDIR || sp->st_gid != mygid) 131 mode &= ~(mode_t)S_ISGID; 132 } 133 return mode; 134 } 135 136 static void 137 nomem(void) 138 { 139 write(2, progname, strlen(progname)); 140 write(2, ": Insufficient memory space.\n", 29); 141 _exit(077); 142 } 143 144 static void * 145 srealloc(void *vp, size_t nbytes) 146 { 147 void *p; 148 149 if ((p = realloc(vp, nbytes)) == NULL) 150 nomem(); 151 return p; 152 } 153 154 static void * 155 smalloc(size_t nbytes) 156 { 157 return srealloc(NULL, nbytes); 158 } 159 160 static void * 161 scalloc(size_t nelem, size_t nbytes) 162 { 163 void *p; 164 165 if ((p = calloc(nelem, nbytes)) == NULL) 166 nomem(); 167 return p; 168 } 169 170 static void 171 usage(void) 172 { 173 switch (pers) { 174 case PERS_CP: 175 fprintf(stderr, "\ 176 Usage: %s [-i] [-p] f1 f2\n\ 177 %s [-i] [-p] f1 ... fn d1\n\ 178 %s [-i] [-p] [-r] d1 d2\n", 179 progname, progname, progname); 180 break; 181 case PERS_MV: 182 fprintf(stderr, "\ 183 Usage: %s [-f] [-i] f1 f2\n\ 184 %s [-f] [-i] f1 ... fn d1\n\ 185 %s [-f] [-i] d1 d2\n", 186 progname, progname, progname); 187 break; 188 case PERS_LN: 189 { 190 #if defined (SUS) 191 const char nstr[] = ""; 192 #else /* !SUS */ 193 const char nstr[] = "[-n] "; 194 #endif /* !SUS */ 195 fprintf(stderr, "\ 196 Usage: %s [-f] %s[-s] f1 f2\n\ 197 %s [-f] %s[-s] f1 ... fn d1\n\ 198 %s [-f] %s[-s] d1 d2\n", 199 progname, nstr, progname, nstr, 200 progname, nstr); 201 } 202 break; 203 } 204 exit(2); 205 } 206 207 static void 208 freeislots(struct islot *ip) 209 { 210 if (ip == inull) 211 return; 212 freeislots(ip->i_lln); 213 freeislots(ip->i_rln); 214 free(ip->i_name); 215 free(ip); 216 } 217 218 static void 219 freedslots(void) 220 { 221 struct dslot *dp, *dn; 222 223 for (dp = d0; dp; dp = dn) { 224 dn = dp->d_nxt; 225 freeislots(dp->d_isl); 226 free(dp); 227 } 228 d0 = NULL; 229 } 230 231 static struct islot * 232 isplay(ino_t ino, struct islot *x) 233 { 234 struct islot hdr; 235 struct islot *leftmax, *rightmin; 236 struct islot *y; 237 238 hdr.i_lln = hdr.i_rln = inull; 239 leftmax = rightmin = &hdr; 240 inull->i_ino = ino; 241 while (ino != x->i_ino) { 242 if (ino < x->i_ino) { 243 if (ino < x->i_lln->i_ino) { 244 y = x->i_lln; 245 x->i_lln = y->i_rln; 246 y->i_rln = x; 247 x = y; 248 } 249 if (x->i_lln == inull) 250 break; 251 rightmin->i_lln = x; 252 rightmin = x; 253 x = x->i_lln; 254 } else { 255 if (ino > x->i_rln->i_ino) { 256 y = x->i_rln; 257 x->i_rln = y->i_lln; 258 y->i_lln = x; 259 x = y; 260 } 261 if (x->i_rln == inull) 262 break; 263 leftmax->i_rln = x; 264 leftmax = x; 265 x = x->i_rln; 266 } 267 } 268 leftmax->i_rln = x->i_lln; 269 rightmin->i_lln = x->i_rln; 270 x->i_lln = hdr.i_rln; 271 x->i_rln = hdr.i_lln; 272 inull->i_ino = !ino; 273 return x; 274 } 275 276 static struct islot * 277 ifind(ino_t ino, struct islot **it) 278 { 279 if (*it == NULL) 280 return NULL; 281 *it = isplay(ino, *it); 282 return (*it)->i_ino == ino ? *it : NULL; 283 } 284 285 static void 286 iput(struct islot *ik, struct islot **it) 287 { 288 if ((*it) == NULL) { 289 ik->i_lln = ik->i_rln = inull; 290 (*it) = ik; 291 } else { 292 /*(*it) = isplay(ik->i_ino, (*it));*/ 293 /* ifind() is always called before */ 294 if (ik->i_ino < (*it)->i_ino) { 295 ik->i_lln = (*it)->i_lln; 296 ik->i_rln = (*it); 297 (*it)->i_lln = inull; 298 (*it) = ik; 299 } else if ((*it)->i_ino < ik->i_ino) { 300 ik->i_rln = (*it)->i_rln; 301 ik->i_lln = (*it); 302 (*it)->i_rln = inull; 303 (*it) = ik; 304 } 305 } 306 } 307 static int 308 canlink(const char *path, const struct stat *sp) 309 { 310 struct dslot *ds, *dp; 311 struct islot *ip; 312 313 for (ds = d0, dp = NULL; ds; dp = ds, ds = ds->d_nxt) 314 if (ds->d_dev == sp->st_dev) 315 break; 316 if (ds == NULL) { 317 ds = scalloc(1, sizeof *ds); 318 ds->d_dev = sp->st_dev; 319 if (d0 == NULL) 320 d0 = ds; 321 else 322 dp->d_nxt = ds; 323 } 324 if ((ip = ifind(sp->st_ino, &ds->d_isl)) == NULL) { 325 ip = scalloc(1, sizeof *ip); 326 ip->i_name = smalloc(strlen(path) + 1); 327 strcpy(ip->i_name, path); 328 ip->i_ino = sp->st_ino; 329 iput(ip, &ds->d_isl); 330 } else { 331 if (link(ip->i_name, path) == 0) 332 return 1; 333 } 334 return 0; 335 } 336 337 static enum okay 338 confirm(void) 339 { 340 enum okay yes = STOP; 341 char c; 342 343 if (read(0, &c, 1) == 1) { 344 yes = (c == 'y' || c == 'Y') ? OKAY : STOP; 345 while (c != '\n' && read(0, &c, 1) == 1); 346 } 347 return yes; 348 } 349 350 static void 351 permissions(const char *path, const struct stat *ssp) 352 { 353 mode_t mode; 354 355 mode = ssp->st_mode & 07777; 356 if (pflag) { 357 struct utimbuf ut; 358 ut.actime = ssp->st_atime; 359 ut.modtime = ssp->st_mtime; 360 if (utime(path, &ut) < 0) { 361 #if defined (SUS) || defined (S42) 362 fprintf(stderr, "%s: cannot set times for %s\n%s: %s\n", 363 progname, path, 364 progname, strerror(errno)); 365 #endif /* SUS || S42 */ 366 if (pers != PERS_MV) 367 errcnt |= 010; 368 } 369 if (myuid == 0) { 370 if (chown(path, ssp->st_uid, ssp->st_gid) < 0) { 371 #if defined (SUS) || defined (S42) 372 fprintf(stderr, 373 "%s: cannot change owner and group of %s\n%s: %s\n", 374 progname, path, 375 progname, strerror(errno)); 376 #endif /* SUS || S42 */ 377 if (pers != PERS_MV) 378 errcnt |= 010; 379 mode &= ~(mode_t)(S_ISUID|S_ISGID); 380 } 381 } else 382 mode = check_suid(ssp, mode); 383 } else 384 mode = check_suid(ssp, mode & ~umsk); 385 if (chmod(path, mode) < 0) { 386 #if defined (SUS) || defined (S42) 387 fprintf(stderr, "%s: cannot set permissions for %s\n%s: %s\n", 388 progname, path, 389 progname, strerror(errno)); 390 #endif /* SUS || S42 */ 391 if (pers != PERS_MV) 392 errcnt |= 010; 393 } 394 } 395 396 static size_t 397 balign(const struct stat *ssp, const struct stat *dsp, 398 long long size, size_t prefd) 399 { 400 int n, m; 401 size_t s; 402 403 n = (ssp->st_mode&S_IFMT) == S_IFREG && ssp->st_blksize >= 0 ? 404 ssp->st_blksize : 512; 405 m = (dsp->st_mode&S_IFMT) == S_IFREG && dsp->st_blksize >= 0 ? 406 dsp->st_blksize : 512; 407 if (prefd <= size && prefd % n == 0 && prefd % m == 0) 408 return prefd; 409 else if (n % m == 0) 410 return n; 411 else if (m % n == 0) 412 return m; 413 else { 414 s = n; 415 while (s % m) 416 s *= 2; 417 return s; 418 } 419 } 420 421 /*ARGSUSED*/ 422 void 423 writerr(void *vp, int count, int written) 424 { 425 } 426 427 static long long 428 fdcopy(const char *src, const struct stat *ssp, const int sfd, 429 const char *tgt, const struct stat *dsp, const int dfd) 430 { 431 static long pagesize; 432 static char *buf = NULL; 433 static size_t bufsize; 434 ssize_t rsz, wo, wt; 435 size_t blksize; 436 long long copied = 0; 437 #ifdef O_DIRECT 438 int sfl = 0, dfl = 0, haverest = 0, dioen = 0; 439 off_t remsz = 0; 440 #endif 441 442 #ifdef __linux__ 443 if (!bflag && !Dflag && ssp->st_size > 0) { 444 long long sent; 445 446 if ((sent = sfile(dfd, sfd, ssp->st_mode, ssp->st_size)) == 447 ssp->st_size) 448 return sent; 449 if (sent < 0) 450 goto err; 451 } 452 #endif /* __linux__ */ 453 if (pagesize == 0) 454 if ((pagesize = sysconf(_SC_PAGESIZE)) < 0) 455 pagesize = 4096; 456 if (bflag) 457 blksize = bflag; 458 #ifdef O_DIRECT 459 else if (Dflag) 460 blksize = balign(ssp, dsp, ssp->st_size, 1048576); 461 #endif /* O_DIRECT */ 462 else 463 blksize = balign(ssp, dsp, ssp->st_size, 4096); 464 if (blksize > bufsize) { 465 if (buf) 466 free(buf); 467 if ((buf = memalign(pagesize, bufsize = blksize)) == 0) 468 nomem(); 469 } 470 #ifdef O_DIRECT 471 if (Dflag) { 472 if ((ssp->st_mode&S_IFMT) == S_IFREG && 473 ssp->st_size > blksize || 474 (ssp->st_mode&S_IFMT) == S_IFBLK) { 475 sfl = fcntl(sfd, F_GETFL); 476 fcntl(sfd, F_SETFL, sfl | O_DIRECT); 477 remsz = ssp->st_size; 478 } 479 if ((dsp->st_mode&S_IFMT) == S_IFREG || 480 (dsp->st_mode&S_IFMT) == S_IFBLK) { 481 dfl = fcntl(dfd, F_GETFL); 482 fcntl(dfd, F_SETFL, dfl | O_DIRECT); 483 dioen = 1; 484 } 485 } 486 #endif /* O_DIRECT */ 487 while ((rsz = read(sfd, buf, blksize)) > 0) { 488 #ifdef O_DIRECT 489 if (Dflag && rsz < blksize && dioen != 0) { 490 fcntl(dfd, F_SETFL, dfl); 491 dioen = 0; 492 } 493 #endif /* O_DIRECT */ 494 wt = 0; 495 do { 496 if ((wo = write(dfd, buf + wt, rsz - wt)) < 0) { 497 #ifdef __linux__ 498 err: 499 #endif /* __linux__ */ 500 fprintf(stderr, "%s: %s: write: %s\n", 501 progname, tgt, 502 strerror(errno)); 503 errcnt |= 04; 504 #ifdef notdef 505 if ((dsp->st_mode&S_IFMT) == S_IFREG) 506 unlink(tgt); 507 #endif /* notdef */ 508 return copied; 509 } 510 wt += wo; 511 copied += wo; 512 } while (wt < rsz); 513 #ifdef O_DIRECT 514 if (Dflag && ssp->st_size > blksize && 515 (ssp->st_mode&S_IFMT) == S_IFREG) { 516 remsz -= rsz; 517 if (remsz > 0 && remsz < blksize && 518 haverest == 0 && (bflag || 519 remsz<(blksize=balign(ssp, dsp, 520 ssp->st_size, 4096)))) { 521 fcntl(sfd, F_SETFL, sfl); 522 haverest = 1; 523 } 524 } 525 #endif /* O_DIRECT */ 526 } 527 if (rsz < 0) { 528 fprintf(stderr, "%s: %s: read: %s\n", 529 progname, src, strerror(errno)); 530 errcnt |= 04; 531 #ifdef notdef 532 if ((dsp->st_mode&S_IFMT) == S_IFREG) 533 unlink(tgt); 534 #endif /* notdef */ 535 } 536 #ifdef O_DIRECT 537 if (haverest) { 538 #if !defined (__FreeBSD__) && !defined (__DragonFly__) && !defined (__APPLE__) 539 fdatasync(dfd); 540 #else /* __FreeBSD__, __DragonFly__, __APPLE__ */ 541 fsync(dfd); 542 #endif /* __FreeBSD_, __DragonFly__, __APPLE__ */ 543 } 544 #endif /* O_DIRECT */ 545 return copied; 546 } 547 548 static void 549 filecopy(const char *src, const struct stat *ssp, 550 const char *tgt, const struct stat *dsp) 551 { 552 struct stat stbuf; 553 mode_t mode; 554 int sfd, dfd; 555 float f, s, t; 556 struct timeval tv1, tv2; 557 struct rusage ru1, ru2; 558 long long copied = 0; 559 560 if (sflag) { 561 gettimeofday(&tv1, NULL); 562 getrusage(RUSAGE_SELF, &ru1); 563 } 564 if ((sfd = open(src, O_RDONLY)) < 0) { 565 fprintf(stderr, "%s: cannot open %s\n%s: %s\n", 566 progname, src, 567 src, strerror(errno)); 568 errcnt |= 01; 569 return; 570 } 571 mode = check_suid(ssp, ssp->st_mode & 07777); 572 if ((dfd = creat(tgt, mode)) < 0) 573 if (pers != PERS_MV && dsp != NULL && fflag && unlink(tgt) == 0) 574 dfd = creat(tgt, mode); 575 if (dfd < 0) { 576 fprintf(stderr, "%s: cannot create %s\n%s: %s\n", 577 progname, tgt, 578 progname, strerror(errno)); 579 errcnt |= 01; 580 goto end1; 581 } 582 if (fstat(dfd, &stbuf) < 0) { 583 fprintf(stderr, "%s: fstat for %s failed: %s\n", 584 progname, tgt, strerror(errno)); 585 errcnt |= 04; 586 goto end2; 587 } 588 copied = fdcopy(src, ssp, sfd, tgt, &stbuf, dfd); 589 end2: 590 if (pflag) 591 permissions(tgt, ssp); 592 if (close(dfd) < 0) { 593 fprintf(stderr, "%s: close error on %s: %s\n", 594 progname, tgt, strerror(errno)); 595 errcnt |= 04; 596 } 597 if (sflag) { 598 gettimeofday(&tv2, NULL); 599 getrusage(RUSAGE_SELF, &ru2); 600 #define tv2f(tv) ((tv).tv_sec + (float)(tv).tv_usec / 1000000) 601 f = tv2f(tv2) - tv2f(tv1); 602 s = (float)copied / (2<<19); 603 t = f ? s / f : s; 604 printf(" ****** %s File Information ******\n" 605 " Input file : %s\n" 606 " Output file : %s\n" 607 " Real Time (secs) : %14.6f\n" 608 " User Time (secs) : %14.6f\n" 609 " System Time (secs) : %14.6f\n" 610 " File Size (MB) : %14.6f\n" 611 " Transfer Rate (MB/s) : %14.6f\n", 612 progname, src, tgt, 613 f, 614 tv2f(ru2.ru_utime) - tv2f(ru1.ru_utime), 615 tv2f(ru2.ru_stime) - tv2f(ru1.ru_stime), 616 s, 617 t); 618 } 619 end1: 620 close(sfd); 621 } 622 623 static void 624 ignoring(const char *type, const char *path) 625 { 626 fprintf(stderr, "%s: %signoring %s %s\n", progname, 627 #if defined (SUS) 628 "", 629 #else /* !SUS */ 630 "warning: ", 631 #endif /* !SUS */ 632 type, path); 633 #if defined (SUS) 634 if (pers == PERS_MV) 635 errcnt |= 020; 636 #endif /* SUS */ 637 } 638 639 static enum okay 640 do_unlink(const char *tgt, const struct stat *dsp) 641 { 642 if (dsp && unlink(tgt) < 0) { 643 fprintf(stderr, "%s: cannot unlink %s\n%s: %s\n", 644 progname, tgt, 645 progname, strerror(errno)); 646 errcnt |= 01; 647 return STOP; 648 } 649 return OKAY; 650 } 651 652 static void 653 devicecopy(const char *src, const struct stat *ssp, 654 const char *tgt, const struct stat *dsp) 655 { 656 if (do_unlink(tgt, dsp) != OKAY) 657 return; 658 if (mknod(tgt, check_suid(ssp, ssp->st_mode & (07777|S_IFMT)), 659 ssp->st_rdev) < 0) { 660 fprintf(stderr, "%s: cannot create special file %s\n%s: %s\n", 661 progname, tgt, 662 progname, strerror(errno)); 663 errcnt |= 01; 664 return; 665 } 666 if (pflag) 667 permissions(tgt, ssp); 668 } 669 670 static void 671 symlinkcopy(const char *src, const struct stat *ssp, 672 const char *tgt, const struct stat *dsp) 673 { 674 static char *buf; 675 static size_t bufsize; 676 ssize_t sz; 677 678 if (buf == NULL) 679 buf = smalloc(bufsize = 256); 680 for (;;) { 681 sz = readlink(src, buf, bufsize - 1); 682 if (sz < 0) { 683 fprintf(stderr, 684 "%s: cannot read symbolic link %s\n%s: %s\n", 685 progname, src, 686 progname, strerror(errno)); 687 errcnt |= 01; 688 return; 689 } 690 if (sz == bufsize - 1) { 691 buf = srealloc(buf, bufsize += 256); 692 continue; 693 } 694 buf[sz] = '\0'; 695 break; 696 } 697 if (do_unlink(tgt, dsp) != OKAY) 698 return; 699 if (symlink(buf, tgt) < 0) { 700 fprintf(stderr, "%s: cannot create symbolic link %s\n%s: %s\n", 701 progname, tgt, 702 progname, strerror(errno)); 703 errcnt |= 01; 704 return; 705 } 706 if (myuid == 0 && lchown(tgt, ssp->st_uid, ssp->st_gid) < 0) { 707 #if defined (SUS) 708 fprintf(stderr, 709 "%s: cannot change owner and group of %s\n%s: %s\n", 710 progname, tgt, 711 progname, strerror(errno)); 712 #endif /* SUS */ 713 if (pers != PERS_MV) 714 errcnt |= 010; 715 } 716 } 717 718 static void 719 socketcopy(const char *src, const struct stat *ssp, 720 const char *tgt, const struct stat *dsp) 721 { 722 int fd, addrsz; 723 struct sockaddr_un addr; 724 size_t len; 725 726 if (do_unlink(tgt, dsp) != OKAY) 727 return; 728 len = strlen(tgt); 729 memset(&addr, 0, sizeof addr); 730 addr.sun_family = AF_UNIX; 731 addrsz = sizeof addr - sizeof addr.sun_path + len; 732 if ((len >= sizeof addr.sun_path ? errno = ENAMETOOLONG, fd = -1, 1 : 733 (strncpy(addr.sun_path,tgt,sizeof addr.sun_path), 0)) || 734 (fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0 || 735 bind(fd, (struct sockaddr *)&addr, addrsz) < 0) { 736 fprintf(stderr, "%s: cannot create socket %s\n%s: %s\n", 737 progname, tgt, 738 progname, strerror(errno)); 739 if (fd >= 0) 740 close(fd); 741 errcnt |= 01; 742 return; 743 } 744 close(fd); 745 if (pflag) 746 permissions(tgt, ssp); 747 } 748 749 static void 750 specialcopy(const char *src, const struct stat *ssp, 751 const char *tgt, const struct stat *dsp) 752 { 753 switch (ssp->st_mode & S_IFMT) { 754 case S_IFIFO: 755 case S_IFCHR: 756 case S_IFBLK: 757 case S_IFNAM: 758 case S_IFNWK: 759 devicecopy(src, ssp, tgt, dsp); 760 break; 761 case S_IFLNK: 762 symlinkcopy(src, ssp, tgt, dsp); 763 break; 764 case S_IFSOCK: 765 socketcopy(src, ssp, tgt, dsp); 766 break; 767 case S_IFDOOR: 768 ignoring("door", src); 769 break; 770 default: 771 fprintf(stderr, "%s: %s: unknown file type %o\n", 772 progname, src, (int)ssp->st_mode); 773 if (pers == PERS_MV) 774 errcnt |= 020; 775 } 776 } 777 778 static void 779 getpath(const char *path, char **file, char **filend, size_t *sz, size_t *slen) 780 { 781 *sz = 14 + strlen(path) + 2; 782 *file = smalloc(*sz); 783 *filend = *file; 784 if (path[0] == '/' && path[1] == '\0') 785 *(*filend)++ = '/'; 786 else { 787 register const char *cp = path; 788 while ((*(*filend)++ = *cp++) != '\0'); 789 (*filend)[-1] = '/'; 790 } 791 *slen = *filend - *file; 792 } 793 794 static void 795 setpath(const char *base, char **file, char **filend, 796 size_t slen, size_t *sz, size_t *ss) 797 { 798 if (slen + (*ss = strlen(base)) >= *sz) { 799 *sz += slen + *ss + 15; 800 *file = srealloc(*file, *sz); 801 *filend = &(*file)[slen]; 802 } 803 strcpy(*filend, base); 804 } 805 806 static enum okay 807 trydelete(const char *path, int recursive) 808 { 809 struct stat st; 810 enum okay val = OKAY; 811 812 if (lstat(path, &st) < 0) { 813 fprintf(stderr, "%s: cannot stat %s for removal\n%s: %s\n", 814 progname, path, 815 progname, strerror(errno)); 816 errcnt |= 040; 817 val = STOP; 818 } else if ((st.st_mode & S_IFMT) == S_IFDIR) { 819 DIR *Dp; 820 821 if (recursive == 0) 822 goto do_rmdir; 823 if ((Dp = opendir(path)) != NULL) { 824 struct dirent *dp; 825 char *copy, *cend; 826 size_t sz, slen, ss; 827 828 getpath(path, ©, &cend, &sz, &slen); 829 while ((dp = readdir(Dp)) != NULL) { 830 if (dp->d_name[0] == '.' && 831 (dp->d_name[1] == '\0' || 832 (dp->d_name[1] == '.' && 833 dp->d_name[2] == '\0'))) 834 continue; 835 setpath(dp->d_name, ©, &cend, 836 slen, &sz, &ss); 837 if ((val = trydelete(copy, recursive)) == STOP) 838 break; 839 } 840 free(copy); 841 closedir(Dp); 842 if (val != STOP) { 843 do_rmdir: 844 if (rmdir(path) < 0) { 845 fprintf(stderr, 846 "%s: cannot remove directory %s\n%s: %s\n", 847 progname, path, 848 progname, strerror(errno)); 849 val = STOP; 850 } 851 } 852 } else { 853 fprintf(stderr, 854 "%s: cannot open directory %s for removal\n%s: %s\n", 855 progname, path, 856 progname, strerror(errno)); 857 errcnt |= 040; 858 val = STOP; 859 } 860 } else { 861 if (unlink(path) < 0) { 862 fprintf(stderr, "%s: cannot unlink %s\n%s: %s\n", 863 progname, path, 864 progname, strerror(errno)); 865 errcnt |= 040; 866 val = STOP; 867 } 868 } 869 return val; 870 } 871 872 static enum okay 873 tryrename(const char *src, const struct stat *ssp, 874 const char *tgt, const struct stat *dsp) 875 { 876 if (dsp && !fflag) { 877 if (iflag) { 878 fprintf(stderr, "%s: overwrite %s? ", 879 progname, tgt); 880 if (confirm() != OKAY) 881 return STOP; 882 } else if (ontty && (dsp->st_mode&S_IFMT) != S_IFLNK && 883 access(tgt, W_OK) < 0) { 884 fprintf(stderr, "%s: %s: %o mode? ", 885 progname, tgt, 886 (int)(dsp->st_mode & 0777)); 887 if (confirm() != OKAY) 888 return STOP; 889 } 890 } 891 if (rename(src, tgt) == 0) 892 return STOP; 893 if (errno != EXDEV) { 894 fprintf(stderr, "%s: cannot rename %s to %s\n%s: %s\n", 895 progname, src, tgt, 896 progname, strerror(errno)); 897 errcnt |= 01; 898 return STOP; 899 } 900 if (dsp) { 901 if ((dsp->st_mode & S_IFMT) == S_IFDIR && 902 (ssp->st_mode & S_IFMT) != S_IFDIR) { 903 fprintf(stderr, "%s: <%s> directory\n", 904 progname, tgt); 905 errcnt |= 01; 906 return STOP; 907 } 908 if ((dsp->st_mode & S_IFMT) != S_IFDIR && 909 (ssp->st_mode & S_IFMT) == S_IFDIR) { 910 fprintf(stderr, "%s: Target must be directory\n", 911 progname); 912 errcnt |= 01; 913 return STOP; 914 } 915 } 916 if (dsp == NULL || trydelete(tgt, 0) == OKAY) 917 return OKAY; 918 return STOP; 919 } 920 921 static enum okay 922 commoncheck(const char *src, const char *tgt, const struct stat *dsp, 923 struct stat *ssp, 924 int (*statfn)(const char *, struct stat *)) 925 { 926 if (statfn(src, ssp) < 0) { 927 if (pers == PERS_LN && sflag) 928 return OKAY; 929 fprintf(stderr, "%s: cannot access %s\n", progname, src); 930 errcnt |= 01; 931 return STOP; 932 } 933 if (dsp && (ssp->st_dev == dsp->st_dev && ssp->st_ino == dsp->st_ino)) { 934 fprintf(stderr, "%s: %s and %s are identical\n", 935 progname, src, tgt); 936 errcnt |= 01; 937 return STOP; 938 } 939 return OKAY; 940 } 941 942 static void 943 cpmv(const char *src, const char *tgt, struct stat *dsp, int level, 944 int (*statfn)(const char *, struct stat *)) 945 { 946 struct stat sst; 947 948 if (commoncheck(src, tgt, dsp, &sst, 949 Rflag && level == 0 ? 950 pers == PERS_MV || HLPflag == 'P' ? 951 lstat : stat : 952 statfn) != OKAY) 953 return; 954 if (pers == PERS_MV && level == 0) { 955 if (tryrename(src, &sst, tgt, dsp) == STOP) 956 return; 957 dsp = NULL; 958 } 959 if ((sst.st_mode & S_IFMT) == S_IFDIR) { 960 DIR *Dp; 961 struct dirent *dp; 962 char *scp, *send, *dcp, *dend; 963 size_t ssz, slen, sss, dsz, dlen, dss; 964 int destcreat = 0; 965 966 if (rflag == 0) { 967 fprintf(stderr, "%s: <%s> directory\n", 968 progname, src); 969 errcnt |= 01; 970 return; 971 } 972 if (dsp && (dsp->st_mode & S_IFMT) != S_IFDIR) { 973 fprintf(stderr, "%s: %s: Not a directory.\n", 974 progname, tgt); 975 errcnt |= 01; 976 return; 977 } 978 #if !defined (SUS) 979 if (pers == PERS_CP && dsp != NULL && iflag) { 980 fprintf(stderr, "%s: overwrite %s? ", 981 progname, tgt); 982 if (confirm() != OKAY) 983 return; 984 } 985 #endif /* !SUS */ 986 if (dsp == NULL) { 987 if (mkdir(tgt, check_suid(&sst, 988 sst.st_mode&07777 | S_IRWXU)) < 0) { 989 fprintf(stderr, "%s: %s: %s\n", 990 progname, tgt, strerror(errno)); 991 errcnt |= 01; 992 return; 993 } 994 destcreat = 1; 995 } 996 if ((Dp = opendir(src)) == NULL) { 997 fprintf(stderr, "%s: %s: %s\n", 998 progname, src, 999 strerror(errno)); 1000 errcnt |= 01; 1001 return; 1002 } 1003 getpath(src, &scp, &send, &ssz, &slen); 1004 getpath(tgt, &dcp, &dend, &dsz, &dlen); 1005 while ((dp = readdir(Dp)) != NULL) { 1006 struct stat xst; 1007 if (dp->d_name[0] == '.' && 1008 (dp->d_name[1] == '\0' || 1009 (dp->d_name[1] == '.' && 1010 dp->d_name[2] == '\0'))) 1011 continue; 1012 setpath(dp->d_name, &scp, &send, slen, &ssz, &sss); 1013 setpath(dp->d_name, &dcp, &dend, dlen, &dsz, &dss); 1014 go(scp, dcp, stat(dcp, &xst) < 0 ? NULL : &xst, 1015 level + 1, statfn); 1016 } 1017 free(scp); 1018 free(dcp); 1019 if (destcreat) 1020 permissions(tgt, &sst); 1021 closedir(Dp); 1022 } else { 1023 if (dsp != NULL && iflag) { 1024 fprintf(stderr, "%s: overwrite %s? ", 1025 progname, tgt); 1026 if (confirm() != OKAY) 1027 return; 1028 } 1029 if (dflag && sst.st_nlink > 1) { 1030 if (canlink(tgt, &sst)) 1031 return; 1032 } 1033 if ((sst.st_mode & S_IFMT) == S_IFREG || Rflag == 0) 1034 filecopy(src, &sst, tgt, dsp); 1035 else 1036 specialcopy(src, &sst, tgt, dsp); 1037 } 1038 if (pers == PERS_MV && errcnt == 0 && level == 0) 1039 trydelete(src, 1); 1040 if ((pers == PERS_CP || pers == PERS_MV) && level == 0 && d0) 1041 freedslots(); 1042 } 1043 1044 /*ARGSUSED3*/ 1045 static void 1046 ln(const char *src, const char *tgt, struct stat *dsp, int level, 1047 int (*statfn)(const char *, struct stat *)) 1048 { 1049 struct stat sst; 1050 int (*how)(const char *, const char *) = sflag ? symlink : link; 1051 1052 if (commoncheck(src, tgt, dsp, &sst, statfn) != OKAY) 1053 return; 1054 if ((sst.st_mode&S_IFMT) == S_IFDIR && !sflag) { 1055 fprintf(stderr, "%s: <%s> directory\n", progname, src); 1056 errcnt |= 01; 1057 return; 1058 } 1059 #if (defined (SUS) || defined (S42)) && (defined (__linux__) || defined (__sun)) 1060 if (sflag == 0) { 1061 char *rpbuf = alloca(PATH_MAX+1); 1062 if (realpath(src, rpbuf) == NULL) { 1063 fprintf(stderr, "%s: cannot access %s\n", 1064 progname, src); 1065 errcnt |= 01; 1066 return; 1067 } 1068 src = rpbuf; 1069 } 1070 #endif /* (SUS || S42) && (__linux__ || __sun) */ 1071 if (dsp 1072 #if !defined (SUS) 1073 && !sflag 1074 #endif /* !SUS */ 1075 ) { 1076 if (nflag && !fflag) { 1077 fprintf(stderr, "%s: %s: File exists\n", 1078 progname, tgt); 1079 errcnt |= 01; 1080 return; 1081 } 1082 if (!fflag && ontty && (dsp->st_mode&S_IFMT) != S_IFLNK && 1083 access(tgt, W_OK) < 0) { 1084 fprintf(stderr, "%s: %s: %o mode? ", 1085 progname, tgt, (int)(dsp->st_mode & 0777)); 1086 if (confirm() != OKAY) 1087 return; 1088 } 1089 if (unlink(tgt) < 0) { 1090 fprintf(stderr, "%s: cannot unlink %s\n%s: %s\n", 1091 progname, tgt, 1092 progname, strerror(errno)); 1093 errcnt |= 01; 1094 return; 1095 } 1096 } 1097 if (how(src, tgt) < 0) { 1098 if (sflag) 1099 fprintf(stderr, "%s: cannot create %s\n%s: %s\n", 1100 progname, tgt, 1101 progname, strerror(errno)); 1102 else if (errno == EXDEV) 1103 fprintf(stderr, "%s: different file system\n", 1104 progname); 1105 else 1106 fprintf(stderr, "%s: errno: %d no permission for %s\n", 1107 progname, errno, tgt); 1108 errcnt |= 01; 1109 } 1110 } 1111 1112 static const char * 1113 getfl(void) 1114 { 1115 const char *optstring; 1116 1117 if (progname[0] == 'm' && progname[1] == 'v') { 1118 pers = PERS_MV; 1119 optstring = "b:fi"; 1120 dflag = pflag = rflag = Rflag = 1; 1121 go = cpmv; 1122 } else if (progname[0] == 'l' && progname[1] == 'n') { 1123 pers = PERS_LN; 1124 optstring = "fns"; 1125 #if defined (SUS) 1126 nflag = 1; 1127 #endif /* SUS */ 1128 go = ln; 1129 } else { 1130 pers = PERS_CP; 1131 optstring = "ab:dDfiHLpPrRs"; 1132 go = cpmv; 1133 } 1134 return optstring; 1135 } 1136 1137 int 1138 main(int argc, char **argv) 1139 { 1140 struct stat dst, ust; 1141 const char *optstring; 1142 int (*statfn)(const char *, struct stat *); 1143 int i, illegal = 0; 1144 1145 #ifdef __GLIBC__ 1146 putenv("POSIXLY_CORRECT=1"); 1147 #endif 1148 progname = basename(argv[0]); 1149 optstring = getfl(); 1150 while ((i = getopt(argc, argv, optstring)) != EOF) { 1151 switch (i) { 1152 case 'b': 1153 bflag = atol(optarg); 1154 break; 1155 #ifdef O_DIRECT 1156 case 'D': 1157 Dflag = 1; 1158 break; 1159 #endif /* O_DIRECT */ 1160 case 'd': 1161 dflag = 1; 1162 break; 1163 case 'f': 1164 fflag = 1; 1165 #if defined (SUS) 1166 if (pers == PERS_MV) 1167 iflag = 0; 1168 #endif /* SUS */ 1169 break; 1170 case 'i': 1171 iflag = 1; 1172 #if defined (SUS) 1173 if (pers == PERS_MV) 1174 fflag = 0; 1175 #endif /* SUS */ 1176 break; 1177 case 'n': 1178 nflag = 1; 1179 break; 1180 case 'p': 1181 pflag = 1; 1182 break; 1183 case 'a': 1184 dflag = pflag = 1; 1185 /*FALLTHRU*/ 1186 case 'R': 1187 Rflag = 1; 1188 /*FALLTHRU*/ 1189 case 'r': 1190 rflag = 1; 1191 break; 1192 case 's': 1193 sflag = 1; 1194 break; 1195 case 'H': 1196 case 'L': 1197 case 'P': 1198 HLPflag = i; 1199 break; 1200 default: 1201 illegal = 1; 1202 } 1203 } 1204 argv += optind, argc -= optind; 1205 if (argc < 2) { 1206 fprintf(stderr, "%s: Insufficient arguments (%d)\n", 1207 progname, argc); 1208 illegal = 1; 1209 } 1210 if (illegal) 1211 usage(); 1212 umask(umsk = umask(0)); 1213 ontty = isatty(0); 1214 #if defined (SUS) 1215 /* nothing */ 1216 #elif defined (S42) 1217 if (pers == PERS_MV && !ontty) 1218 iflag = 0; 1219 #else /* !SUS, !S42 */ 1220 if (!ontty) 1221 iflag = 0; 1222 #endif /* !SUS, !S42 */ 1223 myuid = geteuid(); 1224 mygid = getegid(); 1225 inull = scalloc(1, sizeof *inull); 1226 inull->i_lln = inull->i_rln = inull; 1227 statfn = (Rflag && HLPflag != 'L' 1228 #if !defined (SUS) && !defined (S42) 1229 || pers == PERS_LN 1230 #endif /* !SUS && !S42 */ 1231 ? lstat : stat); 1232 if (lstat(argv[argc-1], &dst) == 0) { 1233 if ((dst.st_mode&S_IFMT) != S_IFLNK || 1234 stat(argv[argc-1], &ust) < 0) 1235 ust = dst; 1236 if ((ust.st_mode&S_IFMT) == S_IFDIR) { 1237 char *copy, *cend; 1238 size_t sz, slen, ss; 1239 unsigned saverrs = errcnt; 1240 1241 getpath(argv[argc-1], ©, &cend, &sz, &slen); 1242 for (i = 0; i < argc-1; i++) { 1243 errcnt = 0; 1244 setpath(basename(argv[i]), ©, &cend, 1245 slen, &sz, &ss); 1246 go(argv[i], copy, statfn(copy, &dst) < 0 ? 1247 NULL : &dst, 0, statfn); 1248 saverrs |= errcnt; 1249 } 1250 errcnt = saverrs; 1251 } else if (argc > 2) { 1252 fprintf(stderr, "%s: Target must be directory\n", 1253 progname); 1254 usage(); 1255 } else 1256 go(argv[0], argv[1], pers == PERS_CP ? &ust : &dst, 1257 0, statfn); 1258 } else if (argc > 2) { 1259 fprintf(stderr, "%s: %s not found\n", progname, argv[argc-1]); 1260 errcnt |= 01; 1261 } else 1262 go(argv[0], argv[1], NULL, 0, statfn); 1263 return errcnt; 1264 }