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