1 /* 2 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 7 /* All Rights Reserved */ 8 9 /* 10 * Copyright (c) 1983 Regents of the University of California. 11 * All rights reserved. The Berkeley software License Agreement 12 * specifies the terms and conditions for redistribution. 13 */ 14 15 #pragma ident "%Z%%M% %I% %E% SMI" 16 17 #include "restore.h" 18 #include <ctype.h> 19 #include <errno.h> 20 #include <syslog.h> 21 #include <limits.h> 22 /* LINTED: this file really is necessary */ 23 #include <euc.h> 24 #include <widec.h> 25 26 /* 27 * Insure that all the components of a pathname exist. Note that 28 * lookupname() and addentry() both expect complex names as 29 * input arguments, so a double NULL needs to be added to each name. 30 */ 31 void 32 pathcheck(char *name) 33 { 34 char *cp, save; 35 struct entry *ep; 36 char *start; 37 38 start = strchr(name, '/'); 39 if (start == 0) 40 return; 41 for (cp = start; *cp != '\0'; cp++) { 42 if (*cp != '/') 43 continue; 44 *cp = '\0'; 45 save = *(cp+1); 46 *(cp+1) = '\0'; 47 ep = lookupname(name); 48 if (ep == NIL) { 49 ep = addentry(name, psearch(name), NODE); 50 newnode(ep); 51 } 52 /* LINTED: result fits in a short */ 53 ep->e_flags |= NEW|KEEP; 54 *cp = '/'; 55 *(cp+1) = save; 56 } 57 } 58 59 /* 60 * Change a name to a unique temporary name. 61 */ 62 void 63 mktempname(struct entry *ep) 64 { 65 char *newname; 66 67 if (ep->e_flags & TMPNAME) 68 badentry(ep, gettext("mktempname: called with TMPNAME")); 69 /* LINTED: result fits in a short */ 70 ep->e_flags |= TMPNAME; 71 newname = savename(gentempname(ep)); 72 renameit(myname(ep), newname); 73 freename(ep->e_name); 74 ep->e_name = newname; 75 /* LINTED: savename guarantees strlen will fit */ 76 ep->e_namlen = strlen(ep->e_name); 77 } 78 79 /* 80 * Generate a temporary name for an entry. 81 */ 82 char * 83 gentempname(struct entry *ep) 84 { 85 static char name[MAXPATHLEN]; 86 struct entry *np; 87 long i = 0; 88 89 for (np = lookupino(ep->e_ino); np != NIL && np != ep; np = np->e_links) 90 i++; 91 if (np == NIL) 92 badentry(ep, gettext("not on ino list")); 93 (void) snprintf(name, sizeof (name), "%s%ld%lu", TMPHDR, i, ep->e_ino); 94 return (name); 95 } 96 97 /* 98 * Rename a file or directory. 99 */ 100 void 101 renameit(char *fp, char *tp) 102 { 103 int fromfd, tofd; 104 char *from, *to; 105 char tobuf[MAXPATHLEN]; 106 char *pathend; 107 108 resolve(fp, &fromfd, &from); 109 /* 110 * The to pointer argument is assumed to be either a fully 111 * specified path (starting with "./") or a simple temporary 112 * file name (starting with TMPHDR). If passed a simple temp 113 * file name, we need to set up the descriptors explicitly. 114 */ 115 if (strncmp(tp, TMPHDR, sizeof (TMPHDR) - 1) == 0) { 116 tofd = fromfd; 117 if ((pathend = strrchr(from, '/')) != NULL) { 118 strncpy(tobuf, from, pathend - from + 1); 119 tobuf[pathend - from + 1] = NULL; 120 strlcat(tobuf, tp, sizeof (tobuf)); 121 to = tobuf; 122 } else { 123 to = tp; 124 } 125 } else 126 resolve(tp, &tofd, &to); 127 if (renameat(fromfd, from, tofd, to) < 0) { 128 int saverr = errno; 129 (void) fprintf(stderr, 130 gettext("Warning: cannot rename %s to %s: %s\n"), 131 from, to, strerror(saverr)); 132 (void) fflush(stderr); 133 } else { 134 vprintf(stdout, gettext("rename %s to %s\n"), from, to); 135 } 136 if (fromfd != AT_FDCWD) (void) close(fromfd); 137 if (tofd != AT_FDCWD) (void) close(tofd); 138 } 139 140 /* 141 * Create a new node (directory). Note that, because we have no 142 * mkdirat() function, fchdir() must be used set up the appropriate 143 * name space context prior to the call to mkdir() if we are 144 * operating in attribute space. 145 */ 146 void 147 newnode(struct entry *np) 148 { 149 char *cp; 150 int dfd; 151 152 if (np->e_type != NODE) 153 badentry(np, gettext("newnode: not a node")); 154 resolve(myname(np), &dfd, &cp); 155 if (dfd != AT_FDCWD) { 156 if (fchdir(dfd) < 0) { 157 int saverr = errno; 158 (void) fprintf(stderr, 159 gettext("Warning: cannot create %s: %s"), 160 cp, strerror(saverr)); 161 (void) fflush(stderr); 162 (void) close(dfd); 163 return; 164 } 165 } 166 if (mkdir(cp, 0777) < 0) { 167 int saverr = errno; 168 /* LINTED: result fits in a short */ 169 np->e_flags |= EXISTED; 170 (void) fprintf(stderr, gettext("Warning: ")); 171 (void) fflush(stderr); 172 (void) fprintf(stderr, "%s: %s\n", cp, strerror(saverr)); 173 } else { 174 vprintf(stdout, gettext("Make node %s\n"), cp); 175 } 176 if (dfd != AT_FDCWD) { 177 fchdir(savepwd); 178 (void) close(dfd); 179 } 180 } 181 182 /* 183 * Remove an old node (directory). See comment above on newnode() 184 * for explanation of fchdir() use below. 185 */ 186 void 187 removenode(struct entry *ep) 188 { 189 char *cp; 190 int dfd; 191 192 if (ep->e_type != NODE) 193 badentry(ep, gettext("removenode: not a node")); 194 if (ep->e_entries != NIL) 195 badentry(ep, gettext("removenode: non-empty directory")); 196 /* LINTED: result fits in a short */ 197 ep->e_flags |= REMOVED; 198 /* LINTED: result fits in a short */ 199 ep->e_flags &= ~TMPNAME; 200 resolve(myname(ep), &dfd, &cp); 201 if (dfd != AT_FDCWD) { 202 if (fchdir(dfd) < 0) { 203 int saverr = errno; 204 (void) fprintf(stderr, 205 gettext("Warning: cannot remove %s: %s"), 206 cp, strerror(saverr)); 207 (void) fflush(stderr); 208 (void) close(dfd); 209 return; 210 } 211 } 212 if (rmdir(cp) < 0) { /* NOTE: could use unlinkat (..,REMOVEDIR) */ 213 int saverr = errno; 214 (void) fprintf(stderr, gettext("Warning: %s: %s\n"), 215 cp, strerror(saverr)); 216 (void) fflush(stderr); 217 } else { 218 vprintf(stdout, gettext("Remove node %s\n"), cp); 219 } 220 if (dfd != AT_FDCWD) { 221 (void) fchdir(savepwd); 222 (void) close(dfd); 223 } 224 } 225 226 /* 227 * Remove a leaf. 228 */ 229 void 230 removeleaf(struct entry *ep) 231 { 232 char *cp; 233 int dfd; 234 235 if (ep->e_type != LEAF) 236 badentry(ep, gettext("removeleaf: not a leaf")); 237 /* LINTED: result fits in a short */ 238 ep->e_flags |= REMOVED; 239 /* LINTED: result fits in a short */ 240 ep->e_flags &= ~TMPNAME; 241 resolve(myname(ep), &dfd, &cp); 242 if (unlinkat(dfd, cp, 0) < 0) { 243 int saverr = errno; 244 (void) fprintf(stderr, gettext("Warning: %s: %s\n"), 245 cp, strerror(saverr)); 246 (void) fflush(stderr); 247 } else { 248 vprintf(stdout, gettext("Remove leaf %s\n"), cp); 249 } 250 if (dfd != AT_FDCWD) 251 (void) close(dfd); 252 } 253 254 /* 255 * Create a link. 256 * This function assumes that the context has already been set 257 * for the link file to be created (i.e., we have "fchdir-ed" 258 * into attribute space already if this is an attribute link). 259 */ 260 int 261 lf_linkit(char *existing, char *new, int type) 262 { 263 char linkbuf[MAXPATHLEN]; 264 struct stat64 s1[1], s2[1]; 265 char *name; 266 int dfd, l, result; 267 268 resolve(existing, &dfd, &name); 269 if (dfd == -1) { 270 (void) fprintf(stderr, gettext( 271 "Warning: cannot restore %s link %s->%s\n"), 272 (type == SYMLINK ? "symbolic" : "hard"), new, existing); 273 result = FAIL; 274 goto out; 275 } 276 if (type == SYMLINK) { 277 if (symlink(name, new) < 0) { 278 /* No trailing \0 from readlink(2) */ 279 if (((l = readlink(new, linkbuf, sizeof (linkbuf))) 280 > 0) && 281 (l == strlen(name)) && 282 (strncmp(linkbuf, name, l) == 0)) { 283 vprintf(stdout, 284 gettext("Symbolic link %s->%s ok\n"), 285 new, name); 286 result = GOOD; 287 goto out; 288 } else { 289 int saverr = errno; 290 (void) fprintf(stderr, gettext( 291 "Warning: cannot create symbolic link %s->%s: %s"), 292 new, name, strerror(saverr)); 293 (void) fflush(stderr); 294 result = FAIL; 295 goto out; 296 } 297 } 298 } else if (type == HARDLINK) { 299 if (link(name, new) < 0) { 300 int saverr = errno; 301 if ((stat64(name, s1) == 0) && 302 (stat64(new, s2) == 0) && 303 (s1->st_dev == s2->st_dev) && 304 (s1->st_ino == s2->st_ino)) { 305 vprintf(stdout, 306 gettext("Hard link %s->%s ok\n"), 307 new, name); 308 result = GOOD; 309 goto out; 310 } else { 311 (void) fprintf(stderr, gettext( 312 "Warning: cannot create hard link %s->%s: %s\n"), 313 new, name, strerror(saverr)); 314 (void) fflush(stderr); 315 result = FAIL; 316 goto out; 317 } 318 } 319 } else { 320 panic(gettext("%s: unknown type %d\n"), "linkit", type); 321 result = FAIL; 322 goto out; 323 } 324 result = GOOD; 325 if (type == SYMLINK) 326 vprintf(stdout, gettext("Create symbolic link %s->%s\n"), 327 new, name); 328 else 329 vprintf(stdout, gettext("Create hard link %s->%s\n"), 330 new, name); 331 out: 332 if (dfd != AT_FDCWD) { 333 (void) close(dfd); 334 } 335 return (result); 336 } 337 338 /* 339 * Find lowest-numbered inode (above "start") that needs to be extracted. 340 * Caller knows that a return value of maxino means there's nothing left. 341 */ 342 ino_t 343 lowerbnd(ino_t start) 344 { 345 struct entry *ep; 346 347 for (; start < maxino; start++) { 348 ep = lookupino(start); 349 if (ep == NIL || ep->e_type == NODE) 350 continue; 351 if (ep->e_flags & (NEW|EXTRACT)) 352 return (start); 353 } 354 return (start); 355 } 356 357 /* 358 * Find highest-numbered inode (below "start") that needs to be extracted. 359 */ 360 ino_t 361 upperbnd(ino_t start) 362 { 363 struct entry *ep; 364 365 for (; start > ROOTINO; start--) { 366 ep = lookupino(start); 367 if (ep == NIL || ep->e_type == NODE) 368 continue; 369 if (ep->e_flags & (NEW|EXTRACT)) 370 return (start); 371 } 372 return (start); 373 } 374 375 /* 376 * report on a badly formed entry 377 */ 378 void 379 badentry(struct entry *ep, char *msg) 380 { 381 382 (void) fprintf(stderr, gettext("bad entry: %s\n"), msg); 383 (void) fprintf(stderr, gettext("name: %s\n"), myname(ep)); 384 (void) fprintf(stderr, gettext("parent name %s\n"), 385 myname(ep->e_parent)); 386 if (ep->e_sibling != NIL) 387 (void) fprintf(stderr, gettext("sibling name: %s\n"), 388 myname(ep->e_sibling)); 389 if (ep->e_entries != NIL) 390 (void) fprintf(stderr, gettext("next entry name: %s\n"), 391 myname(ep->e_entries)); 392 if (ep->e_links != NIL) 393 (void) fprintf(stderr, gettext("next link name: %s\n"), 394 myname(ep->e_links)); 395 if (ep->e_xattrs != NIL) 396 (void) fprintf(stderr, gettext("attribute root name: %s\n"), 397 myname(ep->e_xattrs)); 398 if (ep->e_next != NIL) 399 (void) fprintf(stderr, gettext("next hashchain name: %s\n"), 400 myname(ep->e_next)); 401 (void) fprintf(stderr, gettext("entry type: %s\n"), 402 ep->e_type == NODE ? gettext("NODE") : gettext("LEAF")); 403 (void) fprintf(stderr, gettext("inode number: %lu\n"), ep->e_ino); 404 panic(gettext("flags: %s\n"), flagvalues(ep)); 405 /* Our callers are expected to handle our returning. */ 406 } 407 408 /* 409 * Construct a string indicating the active flag bits of an entry. 410 */ 411 char * 412 flagvalues(struct entry *ep) 413 { 414 static char flagbuf[BUFSIZ]; 415 416 (void) strlcpy(flagbuf, gettext("|NIL"), sizeof (flagbuf)); 417 flagbuf[0] = '\0'; 418 if (ep->e_flags & REMOVED) 419 (void) strlcat(flagbuf, gettext("|REMOVED"), sizeof (flagbuf)); 420 if (ep->e_flags & TMPNAME) 421 (void) strlcat(flagbuf, gettext("|TMPNAME"), sizeof (flagbuf)); 422 if (ep->e_flags & EXTRACT) 423 (void) strlcat(flagbuf, gettext("|EXTRACT"), sizeof (flagbuf)); 424 if (ep->e_flags & NEW) 425 (void) strlcat(flagbuf, gettext("|NEW"), sizeof (flagbuf)); 426 if (ep->e_flags & KEEP) 427 (void) strlcat(flagbuf, gettext("|KEEP"), sizeof (flagbuf)); 428 if (ep->e_flags & EXISTED) 429 (void) strlcat(flagbuf, gettext("|EXISTED"), sizeof (flagbuf)); 430 if (ep->e_flags & XATTR) 431 (void) strlcat(flagbuf, gettext("|XATTR"), sizeof (flagbuf)); 432 if (ep->e_flags & XATTRROOT) 433 (void) strlcat(flagbuf, gettext("|XATTRROOT"), 434 sizeof (flagbuf)); 435 return (&flagbuf[1]); 436 } 437 438 /* 439 * Check to see if a name is on a dump tape. 440 */ 441 ino_t 442 dirlookup(char *name) 443 { 444 ino_t ino; 445 446 ino = psearch(name); 447 if (ino == 0 || BIT(ino, dumpmap) == 0) 448 (void) fprintf(stderr, gettext("%s is not on volume\n"), name); 449 return (ino); 450 } 451 452 /* 453 * Elicit a reply. 454 */ 455 int 456 reply(char *question) 457 { 458 char *yesorno = gettext("yn"); /* must be two characters, "yes" first */ 459 int c; 460 461 do { 462 (void) fprintf(stderr, "%s? [%s] ", question, yesorno); 463 (void) fflush(stderr); 464 c = getc(terminal); 465 while (c != '\n' && getc(terminal) != '\n') { 466 if (ferror(terminal)) { 467 (void) fprintf(stderr, gettext( 468 "Error reading response\n")); 469 (void) fflush(stderr); 470 return (FAIL); 471 } 472 if (feof(terminal)) 473 return (FAIL); 474 } 475 if (isupper(c)) 476 c = tolower(c); 477 } while (c != yesorno[0] && c != yesorno[1]); 478 if (c == yesorno[0]) 479 return (GOOD); 480 return (FAIL); 481 } 482 483 /* 484 * handle unexpected inconsistencies 485 */ 486 /* 487 * Note that a panic w/ EOF on the tty means all panics will return... 488 */ 489 #ifdef __STDC__ 490 #include <stdarg.h> 491 492 /* VARARGS1 */ 493 void 494 panic(const char *msg, ...) 495 { 496 va_list args; 497 498 va_start(args, msg); 499 (void) vfprintf(stderr, msg, args); 500 va_end(args); 501 if (reply(gettext("abort")) == GOOD) { 502 if (reply(gettext("dump core")) == GOOD) 503 abort(); 504 done(1); 505 } 506 } 507 #else 508 #include <varargs.h> 509 510 /* VARARGS1 */ 511 void 512 panic(va_dcl) 513 { 514 va_list args; 515 char *msg; 516 517 va_start(args); 518 msg = va_arg(args, char *); 519 (void) vfprintf(stderr, msg, args); 520 va_end(args); 521 if (reply(gettext("abort")) == GOOD) { 522 if (reply(gettext("dump core")) == GOOD) 523 abort(); 524 done(1); 525 } 526 #endif 527 528 /* 529 * Locale-specific version of ctime 530 */ 531 char * 532 lctime(time_t *tp) 533 { 534 static char buf[256]; 535 struct tm *tm; 536 537 tm = localtime(tp); 538 (void) strftime(buf, sizeof (buf), "%c\n", tm); 539 return (buf); 540 } 541 542 static int 543 statcmp(const struct stat *left, const struct stat *right) 544 { 545 int result = 1; 546 547 if ((left->st_dev == right->st_dev) && 548 (left->st_ino == right->st_ino) && 549 (left->st_mode == right->st_mode) && 550 (left->st_nlink == right->st_nlink) && 551 (left->st_uid == right->st_uid) && 552 (left->st_gid == right->st_gid) && 553 (left->st_rdev == right->st_rdev) && 554 (left->st_ctim.tv_sec == right->st_ctim.tv_sec) && 555 (left->st_ctim.tv_nsec == right->st_ctim.tv_nsec) && 556 (left->st_mtim.tv_sec == right->st_mtim.tv_sec) && 557 (left->st_mtim.tv_nsec == right->st_mtim.tv_nsec) && 558 (left->st_blksize == right->st_blksize) && 559 (left->st_blocks == right->st_blocks)) { 560 result = 0; 561 } 562 563 return (result); 564 } 565 566 /* 567 * Safely open a file. 568 */ 569 int 570 safe_open(int dfd, const char *filename, int mode, int perms) 571 { 572 static int init_syslog = 1; 573 int fd; 574 int working_mode; 575 int saverr; 576 char *errtext; 577 struct stat pre_stat, pre_lstat; 578 struct stat post_stat, post_lstat; 579 580 if (init_syslog) { 581 openlog(progname, LOG_CONS, LOG_DAEMON); 582 init_syslog = 0; 583 } 584 585 /* 586 * Don't want to be spoofed into trashing something we 587 * shouldn't, thus the following rigamarole. If it doesn't 588 * exist, we create it and proceed. Otherwise, require that 589 * what's there be a real file with no extraneous links and 590 * owned by whoever ran us. 591 * 592 * The silliness with using both lstat() and fstat() is to avoid 593 * race-condition games with someone replacing the file with a 594 * symlink after we've opened it. If there was an flstat(), 595 * we wouldn't need the fstat(). 596 * 597 * The initial open with the hard-coded flags is ok even if we 598 * are intending to open only for reading. If it succeeds, 599 * then the file did not exist, and we'll synthesize an appropriate 600 * complaint below. Otherwise, it does exist, so we won't be 601 * truncating it with the open. 602 */ 603 if ((fd = openat(dfd, filename, 604 O_WRONLY|O_CREAT|O_TRUNC|O_EXCL|O_LARGEFILE, perms)) < 0) { 605 if (errno == EEXIST) { 606 if (fstatat(dfd, filename, &pre_lstat, 607 AT_SYMLINK_NOFOLLOW) < 0) { 608 saverr = errno; 609 (void) close(fd); 610 errno = saverr; 611 return (-1); 612 } 613 614 if (fstatat(dfd, filename, &pre_stat, 0) < 0) { 615 saverr = errno; 616 (void) close(fd); 617 errno = saverr; 618 return (-1); 619 } 620 621 working_mode = mode & (O_WRONLY|O_RDWR|O_RDONLY); 622 working_mode |= O_LARGEFILE; 623 624 if ((fd = openat(dfd, filename, working_mode)) < 0) { 625 if (errno == ENOENT) { 626 errtext = gettext( 627 "Unexpected condition detected: %s used to exist, but doesn't any longer\n"); 628 (void) fprintf(stderr, errtext, 629 filename); 630 syslog(LOG_WARNING, errtext, filename); 631 errno = ENOENT; 632 } 633 return (-1); 634 } 635 636 if (fstatat(fd, NULL, &post_lstat, 637 AT_SYMLINK_NOFOLLOW) < 0) { 638 saverr = errno; 639 (void) close(fd); 640 errno = saverr; 641 return (-1); 642 } 643 644 if (fstatat(fd, NULL, &post_stat, 0) < 0) { 645 saverr = errno; 646 (void) close(fd); 647 errno = saverr; 648 return (-1); 649 } 650 651 if (statcmp(&pre_lstat, &post_lstat) != 0) { 652 errtext = gettext( 653 "Unexpected condition detected: %s's lstat(2) information changed\n"); 654 (void) fprintf(stderr, errtext, filename); 655 syslog(LOG_WARNING, errtext, filename); 656 errno = EPERM; 657 return (-1); 658 } 659 660 if (statcmp(&pre_stat, &post_stat) != 0) { 661 errtext = gettext( 662 "Unexpected condition detected: %s's stat(2) information changed\n"); 663 (void) fprintf(stderr, errtext, filename); 664 syslog(LOG_WARNING, errtext, filename); 665 errno = EPERM; 666 return (-1); 667 } 668 669 /* 670 * If inode, device, or type are wrong, bail out. 671 */ 672 if ((!S_ISREG(post_lstat.st_mode) || 673 (post_stat.st_ino != post_lstat.st_ino) || 674 (post_stat.st_dev != post_lstat.st_dev))) { 675 errtext = gettext( 676 "Unexpected condition detected: %s is not a regular file\n"); 677 (void) fprintf(stderr, errtext, filename); 678 syslog(LOG_WARNING, errtext, filename); 679 (void) close(fd); 680 errno = EPERM; 681 return (-1); 682 } 683 684 /* 685 * Bad link count implies someone's linked our 686 * target to something else, which we probably 687 * shouldn't step on. 688 */ 689 if (post_lstat.st_nlink != 1) { 690 errtext = gettext( 691 "Unexpected condition detected: %s must have exactly one link\n"); 692 (void) fprintf(stderr, errtext, filename); 693 syslog(LOG_WARNING, errtext, filename); 694 (void) close(fd); 695 errno = EPERM; 696 return (-1); 697 } 698 /* 699 * Root might make a file, but non-root might 700 * need to open it. If the permissions let us 701 * get this far, then let it through. 702 */ 703 if (post_lstat.st_uid != getuid() && 704 post_lstat.st_uid != 0) { 705 errtext = gettext( 706 "Unsupported condition detected: %s must be owned by uid %ld or 0\n"); 707 (void) fprintf(stderr, errtext, filename, 708 (long)getuid()); 709 syslog(LOG_WARNING, errtext, filename, 710 (long)getuid()); 711 (void) close(fd); 712 errno = EPERM; 713 return (-1); 714 } 715 if (mode & (O_WRONLY|O_TRUNC)) { 716 if (ftruncate(fd, (off_t)0) < 0) { 717 (void) fprintf(stderr, 718 "ftruncate(%s): %s\n", 719 filename, strerror(errno)); 720 (void) close(fd); 721 return (-1); 722 } 723 } 724 } else { 725 /* 726 * Didn't exist, but couldn't open it. 727 */ 728 return (-1); 729 } 730 } else { 731 /* 732 * If truncating open succeeded for a read-only open, 733 * bail out, as we really shouldn't have succeeded. 734 */ 735 if (mode & O_RDONLY) { 736 /* Undo the O_CREAT */ 737 (void) unlinkat(dfd, filename, 0); 738 (void) fprintf(stderr, "open(%s): %s\n", 739 filename, strerror(ENOENT)); 740 (void) close(fd); 741 errno = ENOENT; 742 return (-1); 743 } 744 } 745 746 return (fd); 747 } 748 749 /* 750 * STDIO version of safe_open. Equivalent to fopen64(...). 751 */ 752 FILE * 753 safe_fopen(const char *filename, const char *smode, int perms) 754 { 755 int fd; 756 int bmode; 757 758 /* 759 * accepts only modes "r", "r+", and "w" 760 */ 761 if (smode[0] == 'r') { 762 if (smode[1] == '\0') { 763 bmode = O_RDONLY; 764 } else if ((smode[1] == '+') && (smode[2] == '\0')) { 765 bmode = O_RDWR; 766 } 767 } else if ((smode[0] == 'w') && (smode[1] == '\0')) { 768 bmode = O_WRONLY; 769 } else { 770 (void) fprintf(stderr, 771 gettext("internal error: safe_fopen: invalid mode `%s'\n"), 772 smode); 773 return (NULL); 774 } 775 776 fd = safe_open(AT_FDCWD, filename, bmode, perms); 777 778 /* 779 * caller is expected to report error. 780 */ 781 if (fd >= 0) 782 return (fdopen(fd, smode)); 783 784 return ((FILE *)NULL); 785 } 786 787 /* 788 * Read the contents of a directory. 789 */ 790 int 791 mkentry(char *name, ino_t ino, struct arglist *ap) 792 { 793 struct afile *fp; 794 795 if (ap->base == NULL) { 796 ap->nent = 20; 797 ap->base = (struct afile *)calloc((unsigned)ap->nent, 798 sizeof (*(ap->base))); 799 if (ap->base == NULL) { 800 (void) fprintf(stderr, 801 gettext("%s: out of memory\n"), ap->cmd); 802 return (FAIL); 803 } 804 } 805 if (ap->head == NULL) 806 ap->head = ap->last = ap->base; 807 fp = ap->last; 808 fp->fnum = ino; 809 fp->fname = savename(name); 810 fp++; 811 if (fp == ap->head + ap->nent) { 812 ap->base = (struct afile *)realloc((char *)ap->base, 813 (size_t)(2 * ap->nent * (size_t)sizeof (*(ap->base)))); 814 if (ap->base == NULL) { 815 (void) fprintf(stderr, 816 gettext("%s: out of memory\n"), ap->cmd); 817 return (FAIL); 818 } 819 ap->head = ap->base; 820 fp = ap->head + ap->nent; 821 ap->nent *= 2; 822 } 823 ap->last = fp; 824 return (GOOD); 825 } 826 827 #ifdef __STDC__ 828 static int gmatch(wchar_t *, wchar_t *); 829 static int addg(struct direct *, char *, char *, struct arglist *); 830 #else 831 static int gmatch(); 832 static int addg(); 833 #endif 834 835 /* 836 * XXX This value is ASCII (but not language) dependent. In 837 * ASCII, it is the DEL character (unlikely to appear in paths). 838 * If you are compiling on an EBCDIC-based machine, re-define 839 * this (0x7f is '"') to be something like 0x7 (DEL). It's 840 * either this hack or re-write the expand() algorithm... 841 */ 842 #define DELIMCHAR ((char)0x7f) 843 844 /* 845 * Expand a file name. 846 * "as" is the pattern to expand. 847 * "rflg" non-zero indicates that we're recursing. 848 * "ap" is where to put the results of the expansion. 849 * 850 * Our caller guarantees that "as" is at least the string ".". 851 */ 852 int 853 expand(char *as, int rflg, struct arglist *ap) 854 { 855 int count, size; 856 char dir = 0; 857 char *rescan = 0; 858 RST_DIR *dirp; 859 char *s, *cs; 860 int sindex, rindexa, lindex; 861 struct direct *dp; 862 char slash; 863 char *rs; 864 char c; 865 wchar_t w_fname[PATH_MAX+1]; 866 wchar_t w_pname[PATH_MAX+1]; 867 868 /* 869 * check for meta chars 870 */ 871 s = cs = as; 872 slash = 0; 873 while (*cs != '*' && *cs != '?' && *cs != '[') { 874 if (*cs++ == 0) { 875 if (rflg && slash) 876 break; 877 else 878 return (0); 879 } else if (*cs == '/') { 880 slash++; 881 } 882 } 883 for (;;) { 884 if (cs == s) { 885 s = ""; 886 break; 887 } else if (*--cs == '/') { 888 *cs = 0; 889 if (s == cs) 890 s = "/"; 891 break; 892 } 893 } 894 if ((dirp = rst_opendir(s)) != NULL) 895 dir++; 896 count = 0; 897 if (*cs == 0) 898 *cs++ = DELIMCHAR; 899 if (dir) { 900 /* 901 * check for rescan 902 */ 903 rs = cs; 904 do { 905 if (*rs == '/') { 906 rescan = rs; 907 *rs = 0; 908 } 909 } while (*rs++); 910 /* LINTED: result fits into an int */ 911 sindex = (int)(ap->last - ap->head); 912 (void) mbstowcs(w_pname, cs, PATH_MAX); 913 w_pname[PATH_MAX - 1] = 0; 914 while ((dp = rst_readdir(dirp)) != NULL && dp->d_ino != 0) { 915 if (!dflag && BIT(dp->d_ino, dumpmap) == 0) 916 continue; 917 if ((*dp->d_name == '.' && *cs != '.')) 918 continue; 919 (void) mbstowcs(w_fname, dp->d_name, PATH_MAX); 920 w_fname[PATH_MAX - 1] = 0; 921 if (gmatch(w_fname, w_pname)) { 922 if (addg(dp, s, rescan, ap) < 0) { 923 rst_closedir(dirp); 924 return (-1); 925 } 926 count++; 927 } 928 } 929 if (rescan) { 930 rindexa = sindex; 931 /* LINTED: result fits into an int */ 932 lindex = (int)(ap->last - ap->head); 933 if (count) { 934 count = 0; 935 while (rindexa < lindex) { 936 size = expand(ap->head[rindexa].fname, 937 1, ap); 938 if (size < 0) { 939 rst_closedir(dirp); 940 return (size); 941 } 942 count += size; 943 rindexa++; 944 } 945 } 946 /* LINTED: lint is confused about pointer size/type */ 947 bcopy((void *)(&ap->head[lindex]), 948 (void *)(&ap->head[sindex]), 949 (size_t)((ap->last - &ap->head[rindexa])) * 950 sizeof (*ap->head)); 951 ap->last -= lindex - sindex; 952 *rescan = '/'; 953 } 954 rst_closedir(dirp); 955 } 956 s = as; 957 while ((c = *s) != '\0') 958 *s++ = (c != DELIMCHAR ? c : '/'); 959 960 return (count); 961 } 962 963 /* 964 * Check for a name match 965 */ 966 static int 967 gmatch(wchar_t *s, wchar_t *p) 968 { 969 long scc; /* source character to text */ 970 wchar_t c; /* pattern character to match */ 971 char ok; /* [x-y] range match status */ 972 long lc; /* left character of [x-y] range */ 973 974 scc = *s++; 975 switch (c = *p++) { 976 977 case '[': 978 ok = 0; 979 lc = -1; 980 while (c = *p++) { 981 if (c == ']') { 982 return (ok ? gmatch(s, p) : 0); 983 } else if (c == '-') { 984 wchar_t rc = *p++; 985 /* 986 * Check both ends must belong to 987 * the same codeset. 988 */ 989 if (wcsetno(lc) != wcsetno(rc)) { 990 /* 991 * If not, ignore the '-' 992 * operator and [x-y] is 993 * treated as if it were 994 * [xy]. 995 */ 996 if (scc == lc) 997 ok++; 998 if (scc == (lc = rc)) 999 ok++; 1000 } else if (lc <= scc && scc <= rc) 1001 ok++; 1002 } else { 1003 lc = c; 1004 if (scc == lc) 1005 ok++; 1006 } 1007 } 1008 /* No closing bracket => failure */ 1009 return (0); 1010 1011 default: 1012 if (c != scc) 1013 return (0); 1014 /*FALLTHROUGH*/ 1015 1016 case '?': 1017 return (scc ? gmatch(s, p) : 0); 1018 1019 case '*': 1020 if (*p == 0) 1021 return (1); 1022 s--; 1023 while (*s) { 1024 if (gmatch(s++, p)) 1025 return (1); 1026 } 1027 return (0); 1028 1029 case 0: 1030 return (scc == 0); 1031 } 1032 } 1033 1034 /* 1035 * Construct a matched name. 1036 */ 1037 static int 1038 addg(struct direct *dp, char *as1, char *as3, struct arglist *ap) 1039 { 1040 char *s1, *s2, *limit; 1041 int c; 1042 char buf[MAXPATHLEN + 1]; 1043 1044 s2 = buf; 1045 limit = buf + sizeof (buf) - 1; 1046 s1 = as1; 1047 while ((c = *s1++) != '\0' && s2 < limit) { 1048 if (c == DELIMCHAR) { 1049 *s2++ = '/'; 1050 break; 1051 } 1052 /* LINTED narrowing cast */ 1053 *s2++ = (char)c; 1054 } 1055 s1 = dp->d_name; 1056 while ((*s2 = *s1++) != '\0' && s2 < limit) 1057 s2++; 1058 s1 = as3; 1059 if (s1 != NULL && s2 < limit) { 1060 *s2++ = '/'; 1061 1062 while ((*s2++ = *++s1) != '\0' && s2 < limit) { 1063 continue; 1064 /*LINTED [empty loop body]*/ 1065 } 1066 } 1067 *s2 = '\0'; 1068 if (mkentry(buf, dp->d_ino, ap) == FAIL) 1069 return (-1); 1070 return (0); 1071 } 1072 1073 1074 /* 1075 * Resolve a "complex" pathname (as generated by myname()) into 1076 * a file descriptor and a relative path. The file descriptor 1077 * will reference the hidden directory containing the attribute 1078 * named by the relative path. If the provided path is not 1079 * complex, the returned file descriptor will be AT_FDCWD and rpath 1080 * will equal path. 1081 * 1082 * This function is intended to be used to transform a complex 1083 * pathname into a pair of handles that can be used to actually 1084 * manipulate the named file. Since extended attributes have 1085 * an independant name space, a file descriptor for a directory 1086 * in the attribute name space is necessary to actually manipulate 1087 * the attribute file (via the path-relative xxxat() system calls 1088 * or a call to fchdir()). 1089 * 1090 * In the event of an error, the returned file descriptor will be 1091 * -1. It is expected that callers will either check for this 1092 * condition directly, or attempt to use the descriptor, fail, and 1093 * generate an appropriate context-specific error message. 1094 * 1095 * This function is pretty much a no-op for "simple" (non-attribute) 1096 * paths. 1097 */ 1098 void 1099 resolve(char *path, int *fd, char **rpath) 1100 { 1101 int tfd; 1102 1103 *fd = tfd = AT_FDCWD; 1104 *rpath = path; 1105 path = *rpath + strlen(*rpath) +1; 1106 while (*path != '\0' && 1107 (*fd = openat64(tfd, *rpath, O_RDONLY)) > 0) { 1108 if (tfd != AT_FDCWD) (void) close(tfd); 1109 tfd = *fd; 1110 *rpath = path; 1111 path = *rpath + strlen(*rpath) +1; 1112 } 1113 if (*fd == AT_FDCWD) 1114 return; 1115 if (*fd < 0 || (*fd = openat64(tfd, ".", O_RDONLY|O_XATTR)) < 0) { 1116 int saverr = errno; 1117 (void) fprintf(stderr, 1118 gettext("Warning: cannot fully resolve %s: %s"), 1119 path, strerror(saverr)); 1120 (void) fflush(stderr); 1121 } 1122 if (tfd != AT_FDCWD) (void) close(tfd); 1123 } 1124 1125 /* 1126 * Copy a complex pathname to another string. Note that the 1127 * length returned by this function is the number of characters 1128 * up to (but not including) the final NULL. 1129 */ 1130 int 1131 complexcpy(char *s1, char *s2, int max) 1132 { 1133 int nullseen = 0; 1134 int len = 0; 1135 1136 while (len++ < max) { 1137 *s1++ = *s2; 1138 if (*s2++ == '\0') { 1139 if (nullseen) 1140 return (len-1); 1141 else 1142 nullseen = 1; 1143 } else { 1144 nullseen = 0; 1145 } 1146 } 1147 *s1 = '\0'; 1148 if (nullseen == 0) 1149 *--s1 = '\0'; 1150 fprintf(stderr, 1151 gettext("Warning: unterminated source string in complexcpy\n")); 1152 return (max-1); 1153 } 1154