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] = '\0'; 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 } 525 #endif 526 527 /* 528 * Locale-specific version of ctime 529 */ 530 char * 531 lctime(time_t *tp) 532 { 533 static char buf[256]; 534 struct tm *tm; 535 536 tm = localtime(tp); 537 (void) strftime(buf, sizeof (buf), "%c\n", tm); 538 return (buf); 539 } 540 541 static int 542 statcmp(const struct stat *left, const struct stat *right) 543 { 544 int result = 1; 545 546 if ((left->st_dev == right->st_dev) && 547 (left->st_ino == right->st_ino) && 548 (left->st_mode == right->st_mode) && 549 (left->st_nlink == right->st_nlink) && 550 (left->st_uid == right->st_uid) && 551 (left->st_gid == right->st_gid) && 552 (left->st_rdev == right->st_rdev) && 553 (left->st_ctim.tv_sec == right->st_ctim.tv_sec) && 554 (left->st_ctim.tv_nsec == right->st_ctim.tv_nsec) && 555 (left->st_mtim.tv_sec == right->st_mtim.tv_sec) && 556 (left->st_mtim.tv_nsec == right->st_mtim.tv_nsec) && 557 (left->st_blksize == right->st_blksize) && 558 (left->st_blocks == right->st_blocks)) { 559 result = 0; 560 } 561 562 return (result); 563 } 564 565 /* 566 * Safely open a file. 567 */ 568 int 569 safe_open(int dfd, const char *filename, int mode, int perms) 570 { 571 static int init_syslog = 1; 572 int fd; 573 int working_mode; 574 int saverr; 575 char *errtext; 576 struct stat pre_stat, pre_lstat; 577 struct stat post_stat, post_lstat; 578 579 if (init_syslog) { 580 openlog(progname, LOG_CONS, LOG_DAEMON); 581 init_syslog = 0; 582 } 583 584 /* 585 * Don't want to be spoofed into trashing something we 586 * shouldn't, thus the following rigamarole. If it doesn't 587 * exist, we create it and proceed. Otherwise, require that 588 * what's there be a real file with no extraneous links and 589 * owned by whoever ran us. 590 * 591 * The silliness with using both lstat() and fstat() is to avoid 592 * race-condition games with someone replacing the file with a 593 * symlink after we've opened it. If there was an flstat(), 594 * we wouldn't need the fstat(). 595 * 596 * The initial open with the hard-coded flags is ok even if we 597 * are intending to open only for reading. If it succeeds, 598 * then the file did not exist, and we'll synthesize an appropriate 599 * complaint below. Otherwise, it does exist, so we won't be 600 * truncating it with the open. 601 */ 602 if ((fd = openat(dfd, filename, 603 O_WRONLY|O_CREAT|O_TRUNC|O_EXCL|O_LARGEFILE, perms)) < 0) { 604 if (errno == EEXIST) { 605 if (fstatat(dfd, filename, &pre_lstat, 606 AT_SYMLINK_NOFOLLOW) < 0) { 607 saverr = errno; 608 (void) close(fd); 609 errno = saverr; 610 return (-1); 611 } 612 613 if (fstatat(dfd, filename, &pre_stat, 0) < 0) { 614 saverr = errno; 615 (void) close(fd); 616 errno = saverr; 617 return (-1); 618 } 619 620 working_mode = mode & (O_WRONLY|O_RDWR|O_RDONLY); 621 working_mode |= O_LARGEFILE; 622 623 if ((fd = openat(dfd, filename, working_mode)) < 0) { 624 if (errno == ENOENT) { 625 errtext = gettext( 626 "Unexpected condition detected: %s used to exist, but doesn't any longer\n"); 627 (void) fprintf(stderr, errtext, 628 filename); 629 syslog(LOG_WARNING, errtext, filename); 630 errno = ENOENT; 631 } 632 return (-1); 633 } 634 635 if (fstatat(fd, NULL, &post_lstat, 636 AT_SYMLINK_NOFOLLOW) < 0) { 637 saverr = errno; 638 (void) close(fd); 639 errno = saverr; 640 return (-1); 641 } 642 643 if (fstatat(fd, NULL, &post_stat, 0) < 0) { 644 saverr = errno; 645 (void) close(fd); 646 errno = saverr; 647 return (-1); 648 } 649 650 if (statcmp(&pre_lstat, &post_lstat) != 0) { 651 errtext = gettext( 652 "Unexpected condition detected: %s's lstat(2) information changed\n"); 653 (void) fprintf(stderr, errtext, filename); 654 syslog(LOG_WARNING, errtext, filename); 655 errno = EPERM; 656 return (-1); 657 } 658 659 if (statcmp(&pre_stat, &post_stat) != 0) { 660 errtext = gettext( 661 "Unexpected condition detected: %s's stat(2) information changed\n"); 662 (void) fprintf(stderr, errtext, filename); 663 syslog(LOG_WARNING, errtext, filename); 664 errno = EPERM; 665 return (-1); 666 } 667 668 /* 669 * If inode, device, or type are wrong, bail out. 670 */ 671 if ((!S_ISREG(post_lstat.st_mode) || 672 (post_stat.st_ino != post_lstat.st_ino) || 673 (post_stat.st_dev != post_lstat.st_dev))) { 674 errtext = gettext( 675 "Unexpected condition detected: %s is not a regular file\n"); 676 (void) fprintf(stderr, errtext, filename); 677 syslog(LOG_WARNING, errtext, filename); 678 (void) close(fd); 679 errno = EPERM; 680 return (-1); 681 } 682 683 /* 684 * Bad link count implies someone's linked our 685 * target to something else, which we probably 686 * shouldn't step on. 687 */ 688 if (post_lstat.st_nlink != 1) { 689 errtext = gettext( 690 "Unexpected condition detected: %s must have exactly one link\n"); 691 (void) fprintf(stderr, errtext, filename); 692 syslog(LOG_WARNING, errtext, filename); 693 (void) close(fd); 694 errno = EPERM; 695 return (-1); 696 } 697 /* 698 * Root might make a file, but non-root might 699 * need to open it. If the permissions let us 700 * get this far, then let it through. 701 */ 702 if (post_lstat.st_uid != getuid() && 703 post_lstat.st_uid != 0) { 704 errtext = gettext( 705 "Unsupported condition detected: %s must be owned by uid %ld or 0\n"); 706 (void) fprintf(stderr, errtext, filename, 707 (long)getuid()); 708 syslog(LOG_WARNING, errtext, filename, 709 (long)getuid()); 710 (void) close(fd); 711 errno = EPERM; 712 return (-1); 713 } 714 if (mode & (O_WRONLY|O_TRUNC)) { 715 if (ftruncate(fd, (off_t)0) < 0) { 716 (void) fprintf(stderr, 717 "ftruncate(%s): %s\n", 718 filename, strerror(errno)); 719 (void) close(fd); 720 return (-1); 721 } 722 } 723 } else { 724 /* 725 * Didn't exist, but couldn't open it. 726 */ 727 return (-1); 728 } 729 } else { 730 /* 731 * If truncating open succeeded for a read-only open, 732 * bail out, as we really shouldn't have succeeded. 733 */ 734 if (mode & O_RDONLY) { 735 /* Undo the O_CREAT */ 736 (void) unlinkat(dfd, filename, 0); 737 (void) fprintf(stderr, "open(%s): %s\n", 738 filename, strerror(ENOENT)); 739 (void) close(fd); 740 errno = ENOENT; 741 return (-1); 742 } 743 } 744 745 return (fd); 746 } 747 748 /* 749 * STDIO version of safe_open. Equivalent to fopen64(...). 750 */ 751 FILE * 752 safe_fopen(const char *filename, const char *smode, int perms) 753 { 754 int fd; 755 int bmode; 756 757 /* 758 * accepts only modes "r", "r+", and "w" 759 */ 760 if (smode[0] == 'r') { 761 if (smode[1] == '\0') { 762 bmode = O_RDONLY; 763 } else if ((smode[1] == '+') && (smode[2] == '\0')) { 764 bmode = O_RDWR; 765 } 766 } else if ((smode[0] == 'w') && (smode[1] == '\0')) { 767 bmode = O_WRONLY; 768 } else { 769 (void) fprintf(stderr, 770 gettext("internal error: safe_fopen: invalid mode `%s'\n"), 771 smode); 772 return (NULL); 773 } 774 775 fd = safe_open(AT_FDCWD, filename, bmode, perms); 776 777 /* 778 * caller is expected to report error. 779 */ 780 if (fd >= 0) 781 return (fdopen(fd, smode)); 782 783 return ((FILE *)NULL); 784 } 785 786 /* 787 * Read the contents of a directory. 788 */ 789 int 790 mkentry(char *name, ino_t ino, struct arglist *ap) 791 { 792 struct afile *fp; 793 794 if (ap->base == NULL) { 795 ap->nent = 20; 796 ap->base = (struct afile *)calloc((unsigned)ap->nent, 797 sizeof (*(ap->base))); 798 if (ap->base == NULL) { 799 (void) fprintf(stderr, 800 gettext("%s: out of memory\n"), ap->cmd); 801 return (FAIL); 802 } 803 } 804 if (ap->head == NULL) 805 ap->head = ap->last = ap->base; 806 fp = ap->last; 807 fp->fnum = ino; 808 fp->fname = savename(name); 809 fp++; 810 if (fp == ap->head + ap->nent) { 811 ap->base = (struct afile *)realloc((char *)ap->base, 812 (size_t)(2 * ap->nent * (size_t)sizeof (*(ap->base)))); 813 if (ap->base == NULL) { 814 (void) fprintf(stderr, 815 gettext("%s: out of memory\n"), ap->cmd); 816 return (FAIL); 817 } 818 ap->head = ap->base; 819 fp = ap->head + ap->nent; 820 ap->nent *= 2; 821 } 822 ap->last = fp; 823 return (GOOD); 824 } 825 826 #ifdef __STDC__ 827 static int gmatch(wchar_t *, wchar_t *); 828 static int addg(struct direct *, char *, char *, struct arglist *); 829 #else 830 static int gmatch(); 831 static int addg(); 832 #endif 833 834 /* 835 * XXX This value is ASCII (but not language) dependent. In 836 * ASCII, it is the DEL character (unlikely to appear in paths). 837 * If you are compiling on an EBCDIC-based machine, re-define 838 * this (0x7f is '"') to be something like 0x7 (DEL). It's 839 * either this hack or re-write the expand() algorithm... 840 */ 841 #define DELIMCHAR ((char)0x7f) 842 843 /* 844 * Expand a file name. 845 * "as" is the pattern to expand. 846 * "rflg" non-zero indicates that we're recursing. 847 * "ap" is where to put the results of the expansion. 848 * 849 * Our caller guarantees that "as" is at least the string ".". 850 */ 851 int 852 expand(char *as, int rflg, struct arglist *ap) 853 { 854 int count, size; 855 char dir = 0; 856 char *rescan = 0; 857 RST_DIR *dirp; 858 char *s, *cs; 859 int sindex, rindexa, lindex; 860 struct direct *dp; 861 char slash; 862 char *rs; 863 char c; 864 wchar_t w_fname[PATH_MAX+1]; 865 wchar_t w_pname[PATH_MAX+1]; 866 867 /* 868 * check for meta chars 869 */ 870 s = cs = as; 871 slash = 0; 872 while (*cs != '*' && *cs != '?' && *cs != '[') { 873 if (*cs++ == 0) { 874 if (rflg && slash) 875 break; 876 else 877 return (0); 878 } else if (*cs == '/') { 879 slash++; 880 } 881 } 882 for (;;) { 883 if (cs == s) { 884 s = ""; 885 break; 886 } else if (*--cs == '/') { 887 *cs = 0; 888 if (s == cs) 889 s = "/"; 890 break; 891 } 892 } 893 if ((dirp = rst_opendir(s)) != NULL) 894 dir++; 895 count = 0; 896 if (*cs == 0) 897 *cs++ = DELIMCHAR; 898 if (dir) { 899 /* 900 * check for rescan 901 */ 902 rs = cs; 903 do { 904 if (*rs == '/') { 905 rescan = rs; 906 *rs = 0; 907 } 908 } while (*rs++); 909 /* LINTED: result fits into an int */ 910 sindex = (int)(ap->last - ap->head); 911 (void) mbstowcs(w_pname, cs, PATH_MAX); 912 w_pname[PATH_MAX - 1] = 0; 913 while ((dp = rst_readdir(dirp)) != NULL && dp->d_ino != 0) { 914 if (!dflag && BIT(dp->d_ino, dumpmap) == 0) 915 continue; 916 if ((*dp->d_name == '.' && *cs != '.')) 917 continue; 918 (void) mbstowcs(w_fname, dp->d_name, PATH_MAX); 919 w_fname[PATH_MAX - 1] = 0; 920 if (gmatch(w_fname, w_pname)) { 921 if (addg(dp, s, rescan, ap) < 0) { 922 rst_closedir(dirp); 923 return (-1); 924 } 925 count++; 926 } 927 } 928 if (rescan) { 929 rindexa = sindex; 930 /* LINTED: result fits into an int */ 931 lindex = (int)(ap->last - ap->head); 932 if (count) { 933 count = 0; 934 while (rindexa < lindex) { 935 size = expand(ap->head[rindexa].fname, 936 1, ap); 937 if (size < 0) { 938 rst_closedir(dirp); 939 return (size); 940 } 941 count += size; 942 rindexa++; 943 } 944 } 945 /* LINTED: lint is confused about pointer size/type */ 946 bcopy((void *)(&ap->head[lindex]), 947 (void *)(&ap->head[sindex]), 948 (size_t)((ap->last - &ap->head[rindexa])) * 949 sizeof (*ap->head)); 950 ap->last -= lindex - sindex; 951 *rescan = '/'; 952 } 953 rst_closedir(dirp); 954 } 955 s = as; 956 while ((c = *s) != '\0') 957 *s++ = (c != DELIMCHAR ? c : '/'); 958 959 return (count); 960 } 961 962 /* 963 * Check for a name match 964 */ 965 static int 966 gmatch(wchar_t *s, wchar_t *p) 967 { 968 long scc; /* source character to text */ 969 wchar_t c; /* pattern character to match */ 970 char ok; /* [x-y] range match status */ 971 long lc; /* left character of [x-y] range */ 972 973 scc = *s++; 974 switch (c = *p++) { 975 976 case '[': 977 ok = 0; 978 lc = -1; 979 while (c = *p++) { 980 if (c == ']') { 981 return (ok ? gmatch(s, p) : 0); 982 } else if (c == '-') { 983 wchar_t rc = *p++; 984 /* 985 * Check both ends must belong to 986 * the same codeset. 987 */ 988 if (wcsetno(lc) != wcsetno(rc)) { 989 /* 990 * If not, ignore the '-' 991 * operator and [x-y] is 992 * treated as if it were 993 * [xy]. 994 */ 995 if (scc == lc) 996 ok++; 997 if (scc == (lc = rc)) 998 ok++; 999 } else if (lc <= scc && scc <= rc) 1000 ok++; 1001 } else { 1002 lc = c; 1003 if (scc == lc) 1004 ok++; 1005 } 1006 } 1007 /* No closing bracket => failure */ 1008 return (0); 1009 1010 default: 1011 if (c != scc) 1012 return (0); 1013 /*FALLTHROUGH*/ 1014 1015 case '?': 1016 return (scc ? gmatch(s, p) : 0); 1017 1018 case '*': 1019 if (*p == 0) 1020 return (1); 1021 s--; 1022 while (*s) { 1023 if (gmatch(s++, p)) 1024 return (1); 1025 } 1026 return (0); 1027 1028 case 0: 1029 return (scc == 0); 1030 } 1031 } 1032 1033 /* 1034 * Construct a matched name. 1035 */ 1036 static int 1037 addg(struct direct *dp, char *as1, char *as3, struct arglist *ap) 1038 { 1039 char *s1, *s2, *limit; 1040 int c; 1041 char buf[MAXPATHLEN + 1]; 1042 1043 s2 = buf; 1044 limit = buf + sizeof (buf) - 1; 1045 s1 = as1; 1046 while ((c = *s1++) != '\0' && s2 < limit) { 1047 if (c == DELIMCHAR) { 1048 *s2++ = '/'; 1049 break; 1050 } 1051 /* LINTED narrowing cast */ 1052 *s2++ = (char)c; 1053 } 1054 s1 = dp->d_name; 1055 while ((*s2 = *s1++) != '\0' && s2 < limit) 1056 s2++; 1057 s1 = as3; 1058 if (s1 != NULL && s2 < limit) { 1059 *s2++ = '/'; 1060 1061 while ((*s2++ = *++s1) != '\0' && s2 < limit) { 1062 continue; 1063 /*LINTED [empty loop body]*/ 1064 } 1065 } 1066 *s2 = '\0'; 1067 if (mkentry(buf, dp->d_ino, ap) == FAIL) 1068 return (-1); 1069 return (0); 1070 } 1071 1072 1073 /* 1074 * Resolve a "complex" pathname (as generated by myname()) into 1075 * a file descriptor and a relative path. The file descriptor 1076 * will reference the hidden directory containing the attribute 1077 * named by the relative path. If the provided path is not 1078 * complex, the returned file descriptor will be AT_FDCWD and rpath 1079 * will equal path. 1080 * 1081 * This function is intended to be used to transform a complex 1082 * pathname into a pair of handles that can be used to actually 1083 * manipulate the named file. Since extended attributes have 1084 * an independant name space, a file descriptor for a directory 1085 * in the attribute name space is necessary to actually manipulate 1086 * the attribute file (via the path-relative xxxat() system calls 1087 * or a call to fchdir()). 1088 * 1089 * In the event of an error, the returned file descriptor will be 1090 * -1. It is expected that callers will either check for this 1091 * condition directly, or attempt to use the descriptor, fail, and 1092 * generate an appropriate context-specific error message. 1093 * 1094 * This function is pretty much a no-op for "simple" (non-attribute) 1095 * paths. 1096 */ 1097 void 1098 resolve(char *path, int *fd, char **rpath) 1099 { 1100 int tfd; 1101 1102 *fd = tfd = AT_FDCWD; 1103 *rpath = path; 1104 path = *rpath + strlen(*rpath) +1; 1105 while (*path != '\0' && 1106 (*fd = openat64(tfd, *rpath, O_RDONLY)) > 0) { 1107 if (tfd != AT_FDCWD) 1108 (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