1 /* 2 * Copyright (c) 1990 Jan-Simon Pendry 3 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine 4 * Copyright (c) 1990 The Regents of the University of California. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Jan-Simon Pendry at Imperial College, London. 9 * 10 * %sccs.include.redist.c% 11 * 12 * @(#)afs_ops.c 5.3 (Berkeley) 05/12/91 13 * 14 * $Id: afs_ops.c,v 5.2.1.9 91/05/07 22:17:40 jsp Alpha $ 15 * 16 */ 17 18 #include "am.h" 19 20 #define NFS 21 #define NFSCLIENT 22 23 #include <sys/stat.h> 24 #ifdef NFS_3 25 typedef nfs_fh fhandle_t; 26 #endif /* NFS_3 */ 27 #ifdef NFS_HDR 28 #include NFS_HDR 29 #endif /* NFS_HDR */ 30 #include <sys/mount.h> 31 #include "mount.h" 32 33 /* 34 * Automount file system 35 * Direct file system 36 * Root file system 37 * Top-level file system 38 */ 39 40 /* 41 * Interval between forced retries of a mount. 42 */ 43 #define RETRY_INTERVAL 2 44 45 /* 46 * AFS needs nothing in particular. 47 */ 48 static char *afs_match P((am_opts *fo)); 49 static char *afs_match(fo) 50 am_opts *fo; 51 { 52 char *p = fo->opt_rfs; 53 if (!fo->opt_rfs) { 54 plog(XLOG_USER, "auto: no mount point named (rfs:=)"); 55 return 0; 56 } 57 if (!fo->opt_fs) { 58 plog(XLOG_USER, "auto: no map named (fs:=)"); 59 return 0; 60 } 61 /* 62 * Swap round fs:= and rfs:= options 63 * ... historical (jsp) 64 */ 65 fo->opt_rfs = fo->opt_fs; 66 fo->opt_fs = p; 67 /* 68 * mtab entry turns out to be the name of the mount map 69 */ 70 return strdup(fo->opt_rfs ? fo->opt_rfs : "."); 71 } 72 73 /* 74 * Mount an automounter directory. 75 * The automounter is connected into the system 76 * as a user-level NFS server. mount_toplvl constructs 77 * the necessary NFS parameters to be given to the 78 * kernel so that it will talk back to us. 79 */ 80 static int mount_toplvl P((char *dir, char *opts)); 81 static int mount_toplvl(dir, opts) 82 char *dir; 83 char *opts; 84 { 85 struct nfs_args nfs_args; 86 struct mntent mnt; 87 int retry; 88 struct sockaddr_in sin; 89 unsigned short port; 90 int flags; 91 extern nfs_fh *root_fh(); 92 nfs_fh *fhp; 93 char fs_hostname[MAXHOSTNAMELEN+MAXPATHLEN+1]; 94 95 MTYPE_TYPE type = MOUNT_TYPE_NFS; 96 97 bzero((voidp) &nfs_args, sizeof(nfs_args)); /* Paranoid */ 98 99 mnt.mnt_dir = dir; 100 mnt.mnt_fsname = pid_fsname; 101 mnt.mnt_type = MNTTYPE_AUTO; 102 mnt.mnt_opts = opts; 103 mnt.mnt_freq = 0; 104 mnt.mnt_passno = 0; 105 106 retry = hasmntval(&mnt, "retry"); 107 if (retry <= 0) 108 retry = 2; /* XXX */ 109 110 /* 111 * get fhandle of remote path for automount point 112 */ 113 114 fhp = root_fh(dir); 115 if (!fhp) { 116 plog(XLOG_FATAL, "Can't find root file handle for %s", dir); 117 return EINVAL; 118 } 119 120 NFS_FH_DREF(nfs_args.fh, (NFS_FH_TYPE) fhp); 121 122 /* 123 * Create sockaddr to point to the local machine. 127.0.0.1 124 * is not used since that will not work in HP-UX clusters and 125 * this is no more expensive. 126 */ 127 bzero((voidp) &sin, sizeof(sin)); 128 sin.sin_family = AF_INET; 129 sin.sin_addr = myipaddr; 130 if (port = hasmntval(&mnt, "port")) { 131 sin.sin_port = htons(port); 132 } else { 133 plog(XLOG_ERROR, "no port number specified for %s", dir); 134 return EINVAL; 135 } 136 137 /* 138 * set mount args 139 */ 140 NFS_SA_DREF(nfs_args, &sin); 141 142 /* 143 * Make a ``hostname'' string for the kernel 144 */ 145 #ifndef HOSTNAMESZ 146 #define SHORT_MOUNT_NAME 147 #endif /* HOSTNAMESZ */ 148 #ifdef SHORT_MOUNT_NAME 149 sprintf(fs_hostname, "amd:%d", foreground ? mypid : getppid()); 150 #else 151 sprintf(fs_hostname, "pid%d@%s:%s", foreground ? mypid : getppid(), hostname, dir); 152 #endif /* SHORT_MOUNT_NAME */ 153 nfs_args.hostname = fs_hostname; 154 nfs_args.flags |= NFSMNT_HOSTNAME; 155 #ifdef HOSTNAMESZ 156 /* 157 * Most kernels have a name length restriction. 158 */ 159 if (strlen(fs_hostname) >= HOSTNAMESZ) 160 strcpy(fs_hostname + HOSTNAMESZ - 3, ".."); 161 #endif /* HOSTNAMESZ */ 162 163 /* 164 * Parse a subset of the standard nfs options. The 165 * others are probably irrelevant for this application 166 */ 167 if (nfs_args.timeo = hasmntval(&mnt, "timeo")) 168 nfs_args.flags |= NFSMNT_TIMEO; 169 170 if (nfs_args.retrans = hasmntval(&mnt, "retrans")) 171 nfs_args.flags |= NFSMNT_RETRANS; 172 173 #ifdef NFSMNT_BIODS 174 if (nfs_args.biods = hasmntval(&mnt, "biods")) 175 nfs_args.flags |= NFSMNT_BIODS; 176 177 #endif /* NFSMNT_BIODS */ 178 179 #if defined(NFSMNT_ACREGMIN) && defined(NFSMNT_ACREGMAX) 180 /* 181 * Don't cache attributes - they are changing under 182 * the kernel's feet... 183 */ 184 nfs_args.acregmin = nfs_args.acregmax = 1; 185 nfs_args.flags |= NFSMNT_ACREGMIN|NFSMNT_ACREGMAX; 186 #endif /* defined(NFSMNT_ACREGMIN) && defined(NFSMNT_ACREGMAX) */ 187 /* 188 * These two are constructed internally by the calling routine 189 */ 190 if (hasmntopt(&mnt, MNTOPT_SOFT) != NULL) 191 nfs_args.flags |= NFSMNT_SOFT; 192 193 #ifdef MNTOPT_INTR 194 if (hasmntopt(&mnt, MNTOPT_INTR) != NULL) 195 nfs_args.flags |= NFSMNT_INT; 196 #endif /* MNTOPT_INTR */ 197 198 flags = compute_mount_flags(&mnt); 199 #ifdef ULTRIX_HACK 200 nfs_args.gfs_flags = flags; 201 flags &= M_RDONLY; 202 if (flags & M_RDONLY) 203 nfs_args.flags |= NFSMNT_RONLY; 204 #endif /* ULTRIX_HACK */ 205 return mount_fs(&mnt, flags, (caddr_t) &nfs_args, retry, type); 206 } 207 208 static void afs_mkcacheref P((mntfs *mf)); 209 static void afs_mkcacheref(mf) 210 mntfs *mf; 211 { 212 /* 213 * Build a new map cache for this node, or re-use 214 * an existing cache for the same map. 215 */ 216 char *cache; 217 if (mf->mf_fo && mf->mf_fo->opt_cache) 218 cache = mf->mf_fo->opt_cache; 219 else 220 cache = "none"; 221 mf->mf_private = (voidp) mapc_find(mf->mf_info, cache); 222 mf->mf_prfree = mapc_free; 223 } 224 225 /* 226 * Mount the root... 227 */ 228 static int root_mount P((am_node *mp)); 229 static int root_mount(mp) 230 am_node *mp; 231 { 232 mntfs *mf = mp->am_mnt; 233 234 mf->mf_mount = strealloc(mf->mf_mount, pid_fsname); 235 mf->mf_private = (voidp) mapc_find(mf->mf_info, ""); 236 mf->mf_prfree = mapc_free; 237 238 return 0; 239 } 240 241 /* 242 * Mount a sub-mount 243 */ 244 static int afs_mount P((am_node *mp)); 245 static int afs_mount(mp) 246 am_node *mp; 247 { 248 mntfs *mf = mp->am_mnt; 249 250 /* 251 * Pseudo-directories are used to provide some structure 252 * to the automounted directories instead 253 * of putting them all in the top-level automount directory. 254 * 255 * Here, just increment the parent's link count. 256 */ 257 mp->am_parent->am_fattr.nlink++; 258 /* 259 * Info field of . means use parent's info field. 260 * Historical - not documented. 261 */ 262 if (mf->mf_info[0] == '.' && mf->mf_info[1] == '\0') 263 mf->mf_info = strealloc(mf->mf_info, mp->am_parent->am_mnt->mf_info); 264 /* 265 * Compute prefix: 266 * 267 * If there is an option prefix then use that else 268 * If the parent had a prefix then use that with name 269 * of this node appended else 270 * Use the name of this node. 271 * 272 * That means if you want no prefix you must say so 273 * in the map. 274 */ 275 if (mf->mf_fo->opt_pref) { 276 /* 277 * the prefix specified as an option 278 */ 279 mp->am_pref = strdup(mf->mf_fo->opt_pref); 280 } else { 281 /* 282 * else the parent's prefix 283 * followed by the name 284 * followed by / 285 */ 286 char *ppref = mp->am_parent->am_pref; 287 if (ppref == 0) 288 ppref = ""; 289 mp->am_pref = str3cat((char *) 0, ppref, mp->am_name, "/"); 290 } 291 292 /* 293 * Attach a map cache 294 */ 295 afs_mkcacheref(mf); 296 297 return 0; 298 } 299 300 /* 301 * Mount the top-level 302 */ 303 static int toplvl_mount P((am_node *mp)); 304 static int toplvl_mount(mp) 305 am_node *mp; 306 { 307 mntfs *mf = mp->am_mnt; 308 struct stat stb; 309 char opts[256]; 310 int error; 311 char *mnttype; 312 313 /* 314 * Mounting the automounter. 315 * Make sure the mount directory exists, construct 316 * the mount options and call the mount_toplvl routine. 317 */ 318 319 if (stat(mp->am_path, &stb) < 0) { 320 return errno; 321 } else if ((stb.st_mode & S_IFMT) != S_IFDIR) { 322 plog(XLOG_WARNING, "%s is not a directory", mp->am_path); 323 return ENOTDIR; 324 } 325 326 if (mf->mf_ops == &toplvl_ops) mnttype = "indirect"; 327 else if (mf->mf_ops == &dfs_ops) mnttype = "direct"; 328 #ifdef HAS_UNION_FS 329 else if (mf->mf_ops == &union_ops) mnttype = "union"; 330 #endif 331 else mnttype = "auto"; 332 333 /* 334 * Construct some mount options 335 */ 336 sprintf(opts, 337 #ifdef MNTOPT_INTR 338 "%s,%s,%s=%d,%s=%d,%s=%d,%s", 339 MNTOPT_INTR, 340 #else 341 "%s,%s=%d,%s=%d,%s=%d,%s", 342 #endif /* MNTOPT_INTR */ 343 "rw", 344 "port", nfs_port, 345 "timeo", afs_timeo, 346 "retrans", afs_retrans, 347 mnttype); 348 349 error = mount_toplvl(mf->mf_mount, opts); 350 if (error) { 351 errno = error; 352 plog(XLOG_FATAL, "mount_toplvl: %m"); 353 return error; 354 } 355 356 return 0; 357 } 358 359 static void toplvl_mounted P((mntfs *mf)); 360 static void toplvl_mounted(mf) 361 mntfs *mf; 362 { 363 afs_mkcacheref(mf); 364 } 365 366 #ifdef HAS_UNION_FS 367 /* 368 * Create a reference to a union'ed entry 369 */ 370 static int create_union_node P((char *dir, voidp arg)); 371 static int create_union_node(dir, arg) 372 char *dir; 373 voidp arg; 374 { 375 if (strcmp(dir, "/defaults") != 0) { 376 int error = 0; 377 (void) toplvl_ops.lookuppn(arg, dir, &error, VLOOK_CREATE); 378 if (error > 0) { 379 errno = error; /* XXX */ 380 plog(XLOG_ERROR, "Could not mount %s: %m", dir); 381 } 382 return error; 383 } 384 return 0; 385 } 386 387 static void union_mounted P((mntfs *mf)); 388 static void union_mounted(mf) 389 mntfs *mf; 390 { 391 int i; 392 393 afs_mkcacheref(mf); 394 395 /* 396 * Having made the union mount point, 397 * populate all the entries... 398 */ 399 for (i = 0; i <= last_used_map; i++) { 400 am_node *mp = exported_ap[i]; 401 if (mp && mp->am_mnt == mf) { 402 /* return value from create_union_node is ignored by mapc_keyiter */ 403 (void) mapc_keyiter((mnt_map *) mp->am_mnt->mf_private, 404 (void (*)P((char*,void*))) create_union_node, mp); 405 break; 406 } 407 } 408 409 #ifdef notdef 410 /* 411 * would be nice to flush most of the cache, but we need to 412 * keep the wildcard and /defaults entries... 413 */ 414 mapc_free(mf->mf_private); 415 mf->mf_private = (voidp) mapc_find(mf->mf_info, "inc"); 416 /* mapc_add_kv(mf->mf_private, strdup("/defaults"), 417 strdup("type:=link;opts:=nounmount;sublink:=${key}")); */ 418 #endif 419 } 420 #endif /* HAS_UNION_FS */ 421 422 /* 423 * Unmount an automount sub-node 424 */ 425 static int afs_umount P((am_node *mp)); 426 static int afs_umount(mp) 427 am_node *mp; 428 { 429 return 0; 430 } 431 432 /* 433 * Unmount a top-level automount node 434 */ 435 static int toplvl_umount P((am_node *mp)); 436 static int toplvl_umount(mp) 437 am_node *mp; 438 { 439 int error; 440 441 struct stat stb; 442 again: 443 /* 444 * The lstat is needed if this mount is type=direct. 445 * When that happens, the kernel cache gets confused 446 * between the underlying type (dir) and the mounted 447 * type (link) and so needs to be re-synced before 448 * the unmount. This is all because the unmount system 449 * call follows links and so can't actually unmount 450 * a link (stupid!). It was noted that doing an ls -ld 451 * of the mount point to see why things were not working 452 * actually fixed the problem - so simulate an ls -ld here. 453 */ 454 if (lstat(mp->am_path, &stb) < 0) { 455 #ifdef DEBUG 456 dlog("lstat(%s): %m", mp->am_path); 457 #endif /* DEBUG */ 458 } 459 error = UMOUNT_FS(mp->am_path); 460 if (error == EBUSY) { 461 plog(XLOG_WARNING, "afs_unmount retrying %s in 1s", mp->am_path); 462 sleep(1); /* XXX */ 463 goto again; 464 } 465 466 return error; 467 } 468 469 /* 470 * Unmount an automount node 471 */ 472 static void afs_umounted P((am_node *mp)); 473 static void afs_umounted(mp) 474 am_node *mp; 475 { 476 /* 477 * If this is a pseudo-directory then just adjust the link count 478 * in the parent, otherwise call the generic unmount routine 479 */ 480 if (mp->am_parent && mp->am_parent->am_parent) 481 --mp->am_parent->am_fattr.nlink; 482 } 483 484 /* 485 * Mounting a file system may take a significant period of time. The 486 * problem is that if this is done in the main process thread then 487 * the entire automounter could be blocked, possibly hanging lots of 488 * processes on the system. Instead we use a continuation scheme to 489 * allow mounts to be attempted in a sub-process. When the sub-process 490 * exits we pick up the exit status (by convention a UN*X error number) 491 * and continue in a notifier. The notifier gets handed a data structure 492 * and can then determine whether the mount was successful or not. If 493 * not, it updates the data structure and tries again until there are no 494 * more ways to try the mount, or some other permanent error occurs. 495 * In the mean time no RPC reply is sent, even after the mount is succesful. 496 * We rely on the RPC retry mechanism to resend the lookup request which 497 * can then be handled. 498 */ 499 500 501 struct continuation { 502 char **ivec; /* Current mount info */ 503 am_node *mp; /* Node we are trying to mount */ 504 char *key; /* Map key */ 505 char *info; /* Info string */ 506 char **xivec; /* Saved strsplit vector */ 507 char *auto_opts; /* Automount options */ 508 am_opts fs_opts; /* Filesystem options */ 509 char *def_opts; /* Default automount options */ 510 int retry; /* Try again? */ 511 int tried; /* Have we tried any yet? */ 512 time_t start; /* Time we started this mount */ 513 int callout; /* Callout identifier */ 514 }; 515 516 #define IN_PROGRESS(cp) ((cp)->mp->am_mnt->mf_flags & MFF_MOUNTING) 517 518 /* 519 * Discard an old continuation 520 */ 521 static void free_continuation P((struct continuation *cp)); 522 static void free_continuation(cp) 523 struct continuation *cp; 524 { 525 if (cp->callout) 526 untimeout(cp->callout); 527 free((voidp) cp->key); 528 free((voidp) cp->xivec); 529 free((voidp) cp->info); 530 free((voidp) cp->auto_opts); 531 free((voidp) cp->def_opts); 532 free_opts(&cp->fs_opts); 533 free((voidp) cp); 534 } 535 536 static int afs_bgmount P((struct continuation*, int)); 537 538 /* 539 * Discard the underlying mount point and replace 540 * with a reference to an error filesystem. 541 */ 542 static void assign_error_mntfs P((am_node *mp)); 543 static void assign_error_mntfs(mp) 544 am_node *mp; 545 { 546 if (mp->am_error > 0) { 547 /* 548 * Save the old error code 549 */ 550 int error = mp->am_error; 551 if (error <= 0) 552 error = mp->am_mnt->mf_error; 553 /* 554 * Discard the old filesystem 555 */ 556 free_mntfs(mp->am_mnt); 557 /* 558 * Allocate a new error reference 559 */ 560 mp->am_mnt = new_mntfs(); 561 /* 562 * Put back the error code 563 */ 564 mp->am_mnt->mf_error = error; 565 mp->am_mnt->mf_flags |= MFF_ERROR; 566 /* 567 * Zero the error in the mount point 568 */ 569 mp->am_error = 0; 570 } 571 } 572 573 /* 574 * The continuation function. This is called by 575 * the task notifier when a background mount attempt 576 * completes. 577 */ 578 static void afs_cont P((int rc, int term, voidp closure)); 579 static void afs_cont(rc, term, closure) 580 int rc; 581 int term; 582 voidp closure; 583 { 584 struct continuation *cp = (struct continuation *) closure; 585 mntfs *mf = cp->mp->am_mnt; 586 587 /* 588 * Definitely not trying to mount at the moment 589 */ 590 mf->mf_flags &= ~MFF_MOUNTING; 591 /* 592 * While we are mounting - try to avoid race conditions 593 */ 594 new_ttl(cp->mp); 595 596 /* 597 * Wakeup anything waiting for this mount 598 */ 599 wakeup((voidp) mf); 600 601 /* 602 * Check for termination signal or exit status... 603 */ 604 if (rc || term) { 605 if (term) { 606 /* 607 * Not sure what to do for an error code. 608 */ 609 mf->mf_error = EIO; /* XXX ? */ 610 mf->mf_flags |= MFF_ERROR; 611 plog(XLOG_ERROR, "mount for %s got signal %d", cp->mp->am_path, term); 612 } else { 613 /* 614 * Check for exit status... 615 */ 616 mf->mf_error = rc; 617 mf->mf_flags |= MFF_ERROR; 618 errno = rc; /* XXX */ 619 plog(XLOG_ERROR, "%s: mount (afs_cont): %m", cp->mp->am_path); 620 } 621 622 /* 623 * If we get here then that attempt didn't work, so 624 * move the info vector pointer along by one and 625 * call the background mount routine again 626 */ 627 amd_stats.d_merr++; 628 cp->ivec++; 629 (void) afs_bgmount(cp, 0); 630 assign_error_mntfs(cp->mp); 631 } else { 632 /* 633 * The mount worked. 634 */ 635 am_mounted(cp->mp); 636 free_continuation(cp); 637 } 638 639 reschedule_timeout_mp(); 640 } 641 642 /* 643 * Retry a mount 644 */ 645 /*ARGSUSED*/ 646 static void afs_retry P((int rc, int term, voidp closure)); 647 static void afs_retry(rc, term, closure) 648 int rc; 649 int term; 650 voidp closure; 651 { 652 struct continuation *cp = (struct continuation *) closure; 653 int error = 0; 654 655 #ifdef DEBUG 656 dlog("Commencing retry for mount of %s", cp->mp->am_path); 657 #endif /* DEBUG */ 658 659 new_ttl(cp->mp); 660 661 if ((cp->start + ALLOWED_MOUNT_TIME) < clocktime()) { 662 /* 663 * The entire mount has timed out. 664 * Set the error code and skip past 665 * all the info vectors so that 666 * afs_bgmount will not have any more 667 * ways to try the mount, so causing 668 * an error. 669 */ 670 plog(XLOG_INFO, "mount of \"%s\" has timed out", cp->mp->am_path); 671 error = ETIMEDOUT; 672 while (*cp->ivec) 673 cp->ivec++; 674 } 675 676 if (error || !IN_PROGRESS(cp)) { 677 (void) afs_bgmount(cp, error); 678 } 679 reschedule_timeout_mp(); 680 } 681 682 /* 683 * Try to mount a file system. Can be called 684 * directly or in a sub-process by run_task 685 */ 686 static int try_mount P((voidp mvp)); 687 static int try_mount(mvp) 688 voidp mvp; 689 { 690 /* 691 * Mount it! 692 */ 693 int error; 694 am_node *mp = (am_node *) mvp; 695 mntfs *mf = mp->am_mnt; 696 697 /* 698 * If the directory is not yet made and 699 * it needs to be made, then make it! 700 * This may be run in a backgroun process 701 * in which case the flag setting won't be 702 * noticed later - but it is set anyway 703 * just after run_task is called. It 704 * should probably go away totally... 705 */ 706 if (!(mf->mf_flags & MFF_MKMNT) && mf->mf_ops->fs_flags & FS_MKMNT) { 707 error = mkdirs(mf->mf_mount, 0555); 708 if (!error) 709 mf->mf_flags |= MFF_MKMNT; 710 } 711 712 error = mount_node(mp); 713 #ifdef DEBUG 714 if (error > 0) { 715 errno = error; 716 dlog("afs call to mount_node failed: %m"); 717 } 718 #endif /* DEBUG */ 719 return error; 720 } 721 722 /* 723 * Pick a file system to try mounting and 724 * do that in the background if necessary 725 * 726 For each location: 727 if it is new -defaults then 728 extract and process 729 continue; 730 fi 731 if it is a cut then 732 if a location has been tried then 733 break; 734 fi 735 continue; 736 fi 737 parse mount location 738 discard previous mount location if required 739 find matching mounted filesystem 740 if not applicable then 741 this_error = No such file or directory 742 continue 743 fi 744 if the filesystem failed to be mounted then 745 this_error = error from filesystem 746 elif the filesystem is mounting or unmounting then 747 this_error = -1 748 elif the fileserver is down then 749 this_error = -1 750 elif the filesystem is already mounted 751 this_error = 0 752 break 753 fi 754 if no error on this mount then 755 this_error = initialise mount point 756 fi 757 if no error on this mount and mount is delayed then 758 this_error = -1 759 fi 760 if this_error < 0 then 761 retry = true 762 fi 763 if no error on this mount then 764 make mount point if required 765 fi 766 if no error on this mount then 767 if mount in background then 768 run mount in background 769 return -1 770 else 771 this_error = mount in foreground 772 fi 773 fi 774 if an error occured on this mount then 775 update stats 776 save error in mount point 777 fi 778 endfor 779 */ 780 781 static int afs_bgmount P((struct continuation *cp, int mpe)); 782 static int afs_bgmount(cp, mpe) 783 struct continuation *cp; 784 int mpe; 785 { 786 mntfs *mf = cp->mp->am_mnt; /* Current mntfs */ 787 mntfs *mf_retry = 0; /* First mntfs which needed retrying */ 788 int this_error = -1; /* Per-mount error */ 789 int hard_error = -1; 790 int mp_error = mpe; 791 792 /* 793 * Try to mount each location. 794 * At the end: 795 * hard_error == 0 indicates something was mounted. 796 * hard_error > 0 indicates everything failed with a hard error 797 * hard_error < 0 indicates nothing could be mounted now 798 */ 799 for (; this_error && *cp->ivec; cp->ivec++) { 800 am_ops *p; 801 am_node *mp = cp->mp; 802 char *link_dir; 803 int dont_retry; 804 805 if (hard_error < 0) 806 hard_error = this_error; 807 808 this_error = -1; 809 810 if (**cp->ivec == '-') { 811 /* 812 * Pick up new defaults 813 */ 814 if (cp->auto_opts && *cp->auto_opts) 815 cp->def_opts = str3cat(cp->def_opts, cp->auto_opts, ";", *cp->ivec+1); 816 else 817 cp->def_opts = strealloc(cp->def_opts, *cp->ivec+1); 818 #ifdef DEBUG 819 dlog("Setting def_opts to \"%s\"", cp->def_opts); 820 #endif /* DEBUG */ 821 continue; 822 } 823 824 /* 825 * If a mount has been attempted, and we find 826 * a cut then don't try any more locations. 827 */ 828 if (strcmp(*cp->ivec, "/") == 0 || strcmp(*cp->ivec, "||") == 0) { 829 if (cp->tried) { 830 #ifdef DEBUG 831 dlog("Cut: not trying any more locations for %s", 832 mp->am_path); 833 #endif /* DEBUG */ 834 break; 835 } 836 continue; 837 } 838 839 #ifdef SUNOS4_COMPAT 840 #ifdef nomore 841 /* 842 * By default, you only get this bit on SunOS4. 843 * If you want this anyway, then define SUNOS4_COMPAT 844 * in the relevant "os-blah.h" file. 845 * 846 * We make the observation that if the local key line contains 847 * no '=' signs then either it is sick, or it is a SunOS4-style 848 * "host:fs[:link]" line. In the latter case the am_opts field 849 * is also assumed to be in old-style, so you can't mix & match. 850 * You can use ${} expansions for the fs and link bits though... 851 * 852 * Actually, this doesn't really cover all the possibilities for 853 * the latest SunOS automounter and it is debatable whether there 854 * is any point bothering. 855 */ 856 if (strchr(*cp->ivec, '=') == 0) 857 p = sunos4_match(&cp->fs_opts, *cp->ivec, cp->def_opts, mp->am_path, cp->key, mp->am_parent->am_mnt->mf_info); 858 else 859 #endif 860 #endif /* SUNOS4_COMPAT */ 861 p = ops_match(&cp->fs_opts, *cp->ivec, cp->def_opts, mp->am_path, cp->key, mp->am_parent->am_mnt->mf_info); 862 863 /* 864 * Find a mounted filesystem for this node. 865 */ 866 mp->am_mnt = mf = realloc_mntfs(mf, p, &cp->fs_opts, cp->fs_opts.opt_fs, 867 cp->fs_opts.fs_mtab, cp->auto_opts, cp->fs_opts.opt_opts); 868 869 p = mf->mf_ops; 870 #ifdef DEBUG 871 dlog("Got a hit with %s", p->fs_type); 872 #endif /* DEBUG */ 873 /* 874 * Note whether this is a real mount attempt 875 */ 876 if (p == &efs_ops) { 877 plog(XLOG_MAP, "Map entry %s for %s failed to match", *cp->ivec, mp->am_path); 878 if (this_error <= 0) 879 this_error = ENOENT; 880 continue; 881 } else { 882 if (cp->fs_opts.fs_mtab) { 883 plog(XLOG_MAP, "Trying mount of %s on %s fstype %s", 884 cp->fs_opts.fs_mtab, mp->am_path, p->fs_type); 885 } 886 cp->tried = TRUE; 887 } 888 889 this_error = 0; 890 dont_retry = FALSE; 891 892 if (mp->am_link) { 893 free(mp->am_link); 894 mp->am_link = 0; 895 } 896 897 link_dir = mf->mf_fo->opt_sublink; 898 899 if (link_dir && *link_dir) { 900 if (*link_dir == '/') { 901 mp->am_link = strdup(link_dir); 902 } else { 903 mp->am_link = str3cat((char *) 0, 904 mf->mf_fo->opt_fs, "/", link_dir); 905 normalize_slash(mp->am_link); 906 } 907 } 908 909 if (mf->mf_error > 0) { 910 this_error = mf->mf_error; 911 } else if (mf->mf_flags & (MFF_MOUNTING|MFF_UNMOUNTING)) { 912 /* 913 * Still mounting - retry later 914 */ 915 #ifdef DEBUG 916 dlog("Duplicate pending mount fstype %s", p->fs_type); 917 #endif /* DEBUG */ 918 this_error = -1; 919 } else if (FSRV_ISDOWN(mf->mf_server)) { 920 /* 921 * Would just mount from the same place 922 * as a hung mount - so give up 923 */ 924 #ifdef DEBUG 925 dlog("%s is already hung - giving up", mf->mf_mount); 926 #endif /* DEBUG */ 927 mp_error = EWOULDBLOCK; 928 dont_retry = TRUE; 929 this_error = -1; 930 } else if (mf->mf_flags & MFF_MOUNTED) { 931 #ifdef DEBUG 932 dlog("duplicate mount of \"%s\" ...", mf->mf_info); 933 #endif /* DEBUG */ 934 /* 935 * Just call mounted() 936 */ 937 am_mounted(mp); 938 939 this_error = 0; 940 break; 941 } 942 943 /* 944 * Will usually need to play around with the mount nodes 945 * file attribute structure. This must be done here. 946 * Try and get things initialised, even if the fileserver 947 * is not known to be up. In the common case this will 948 * progress things faster. 949 */ 950 if (!this_error) { 951 /* 952 * Fill in attribute fields. 953 */ 954 if (mf->mf_ops->fs_flags & FS_DIRECTORY) 955 mk_fattr(mp, NFDIR); 956 else 957 mk_fattr(mp, NFLNK); 958 959 mp->am_fattr.fileid = mp->am_gen; 960 961 if (p->fs_init) 962 this_error = (*p->fs_init)(mf); 963 } 964 965 /* 966 * Make sure the fileserver is UP before doing any more work 967 */ 968 if (!FSRV_ISUP(mf->mf_server)) { 969 #ifdef DEBUG 970 dlog("waiting for server %s to become available", mf->mf_server->fs_host); 971 #endif 972 this_error = -1; 973 } 974 975 if (!this_error && mf->mf_fo->opt_delay) { 976 /* 977 * If there is a delay timer on the mount 978 * then don't try to mount if the timer 979 * has not expired. 980 */ 981 int i = atoi(mf->mf_fo->opt_delay); 982 if (i > 0 && clocktime() < (cp->start + i)) { 983 #ifdef DEBUG 984 dlog("Mount of %s delayed by %ds", mf->mf_mount, i - clocktime() + cp->start); 985 #endif /* DEBUG */ 986 this_error = -1; 987 } 988 } 989 990 if (this_error < 0 && !dont_retry) { 991 if (!mf_retry) 992 mf_retry = dup_mntfs(mf); 993 cp->retry = TRUE; 994 } 995 996 if (!this_error) 997 if (p->fs_flags & FS_MBACKGROUND) { 998 mf->mf_flags |= MFF_MOUNTING; /*XXX*/ 999 #ifdef DEBUG 1000 dlog("backgrounding mount of \"%s\"", mf->mf_mount); 1001 #endif /* DEBUG */ 1002 if (cp->callout) { 1003 untimeout(cp->callout); 1004 cp->callout = 0; 1005 } 1006 run_task(try_mount, (voidp) mp, afs_cont, (voidp) cp); 1007 mf->mf_flags |= MFF_MKMNT; /* XXX */ 1008 if (mf_retry) free_mntfs(mf_retry); 1009 return -1; 1010 } else { 1011 #ifdef DEBUG 1012 dlog("foreground mount of \"%s\" ...", mf->mf_info); 1013 #endif /* DEBUG */ 1014 this_error = try_mount((voidp) mp); 1015 if (this_error < 0) { 1016 if (!mf_retry) 1017 mf_retry = dup_mntfs(mf); 1018 cp->retry = TRUE; 1019 } 1020 } 1021 1022 if (this_error >= 0) { 1023 if (this_error > 0) { 1024 amd_stats.d_merr++; 1025 if (mf != mf_retry) { 1026 mf->mf_error = this_error; 1027 mf->mf_flags |= MFF_ERROR; 1028 } 1029 } 1030 /* 1031 * Wakeup anything waiting for this mount 1032 */ 1033 wakeup((voidp) mf); 1034 } 1035 } 1036 1037 if (this_error && cp->retry) { 1038 free_mntfs(mf); 1039 mf = cp->mp->am_mnt = mf_retry; 1040 /* 1041 * Not retrying again (so far) 1042 */ 1043 cp->retry = FALSE; 1044 cp->tried = FALSE; 1045 /* 1046 * Start at the beginning. 1047 * Rewind the location vector and 1048 * reset the default options. 1049 */ 1050 cp->ivec = cp->xivec; 1051 cp->def_opts = strealloc(cp->def_opts, cp->auto_opts); 1052 /* 1053 * Arrange that afs_bgmount is called 1054 * after anything else happens. 1055 */ 1056 #ifdef DEBUG 1057 dlog("Arranging to retry mount of %s", cp->mp->am_path); 1058 #endif /* DEBUG */ 1059 sched_task(afs_retry, (voidp) cp, (voidp) mf); 1060 if (cp->callout) 1061 untimeout(cp->callout); 1062 cp->callout = timeout(RETRY_INTERVAL, wakeup, (voidp) mf); 1063 1064 cp->mp->am_ttl = clocktime() + RETRY_INTERVAL; 1065 1066 /* 1067 * Not done yet - so don't return anything 1068 */ 1069 return -1; 1070 } 1071 1072 if (hard_error < 0 || this_error == 0) 1073 hard_error = this_error; 1074 1075 /* 1076 * Discard handle on duff filesystem. 1077 * This should never happen since it 1078 * should be caught by the case above. 1079 */ 1080 if (mf_retry) { 1081 if (hard_error) 1082 plog(XLOG_ERROR, "discarding a retry mntfs for %s", mf_retry->mf_mount); 1083 free_mntfs(mf_retry); 1084 } 1085 1086 /* 1087 * If we get here, then either the mount succeeded or 1088 * there is no more mount information available. 1089 */ 1090 if (hard_error < 0 && mp_error) 1091 hard_error = cp->mp->am_error = mp_error; 1092 if (hard_error > 0) { 1093 /* 1094 * Set a small(ish) timeout on an error node if 1095 * the error was not a time out. 1096 */ 1097 switch (hard_error) { 1098 case ETIMEDOUT: 1099 case EWOULDBLOCK: 1100 cp->mp->am_timeo = 5; 1101 break; 1102 default: 1103 cp->mp->am_timeo = 17; 1104 break; 1105 } 1106 cp->mp->am_timeo_w = 0; 1107 } 1108 1109 /* 1110 * Make sure that the error value in the mntfs has a 1111 * reasonable value. 1112 */ 1113 if (mf->mf_error < 0) { 1114 mf->mf_error = hard_error; 1115 if (hard_error) 1116 mf->mf_flags |= MFF_ERROR; 1117 } 1118 1119 /* 1120 * In any case we don't need the continuation any more 1121 */ 1122 free_continuation(cp); 1123 1124 return hard_error; 1125 } 1126 1127 /* 1128 * Automount interface to RPC lookup routine 1129 */ 1130 static am_node *afs_lookuppn P((am_node *mp, char *fname, int *error_return, int op)); 1131 static am_node *afs_lookuppn(mp, fname, error_return, op) 1132 am_node *mp; 1133 char *fname; 1134 int *error_return; 1135 int op; 1136 { 1137 #define ereturn(x) { *error_return = x; return 0; } 1138 1139 /* 1140 * Find the corresponding entry and return 1141 * the file handle for it. 1142 */ 1143 am_node *ap, *new_mp, *ap_hung; 1144 char *info; /* Mount info - where to get the file system */ 1145 char **ivec, **xivec; /* Split version of info */ 1146 char *auto_opts; /* Automount options */ 1147 int error = 0; /* Error so far */ 1148 char path_name[MAXPATHLEN]; /* General path name buffer */ 1149 char *pfname; /* Path for database lookup */ 1150 struct continuation *cp; /* Continuation structure if we need to mount */ 1151 int in_progress = 0; /* # of (un)mount in progress */ 1152 char *dflts; 1153 mntfs *mf; 1154 1155 #ifdef DEBUG 1156 dlog("in afs_lookuppn"); 1157 #endif /* DEBUG */ 1158 1159 /* 1160 * If the server is shutting down 1161 * then don't return information 1162 * about the mount point. 1163 */ 1164 if (amd_state == Finishing) { 1165 #ifdef DEBUG 1166 if ((mf = mp->am_mnt) == 0 || mf->mf_ops == &dfs_ops) 1167 dlog("%s mount ignored - going down", fname); 1168 else 1169 dlog("%s/%s mount ignored - going down", mp->am_path, fname); 1170 #endif /* DEBUG */ 1171 ereturn(ENOENT); 1172 } 1173 1174 /* 1175 * Handle special case of "." and ".." 1176 */ 1177 if (fname[0] == '.') { 1178 if (fname[1] == '\0') 1179 return mp; /* "." is the current node */ 1180 if (fname[1] == '.' && fname[2] == '\0') { 1181 if (mp->am_parent) { 1182 #ifdef DEBUG 1183 dlog(".. in %s gives %s", mp->am_path, mp->am_parent->am_path); 1184 #endif /* DEBUG */ 1185 return mp->am_parent; /* ".." is the parent node */ 1186 } 1187 ereturn(ESTALE); 1188 } 1189 } 1190 1191 /* 1192 * Check for valid key name. 1193 * If it is invalid then pretend it doesn't exist. 1194 */ 1195 if (!valid_key(fname)) { 1196 plog(XLOG_WARNING, "Key \"%s\" contains a disallowed character", fname); 1197 ereturn(ENOENT); 1198 } 1199 1200 /* 1201 * Expand key name. 1202 * fname is now a private copy. 1203 */ 1204 fname = expand_key(fname); 1205 1206 for (ap_hung = 0, ap = mp->am_child; ap; ap = ap->am_osib) { 1207 /* 1208 * Otherwise search children of this node 1209 */ 1210 if (FSTREQ(ap->am_name, fname)) { 1211 mf = ap->am_mnt; 1212 if (ap->am_error) { 1213 error = ap->am_error; 1214 continue; 1215 } 1216 1217 /* 1218 * If the error code is undefined then it must be 1219 * in progress. 1220 */ 1221 if (mf->mf_error < 0) 1222 goto in_progrss; 1223 1224 /* 1225 * Check for a hung node 1226 */ 1227 if (FSRV_ISDOWN(mf->mf_server)) { 1228 ap_hung = ap; 1229 continue; 1230 } 1231 1232 /* 1233 * If there was a previous error with this node 1234 * then return that error code. 1235 */ 1236 if (mf->mf_flags & MFF_ERROR) { 1237 error = mf->mf_error; 1238 continue; 1239 } 1240 1241 if (!(mf->mf_flags & MFF_MOUNTED) /*|| (mf->mf_flags & MFF_UNMOUNTING)*/) { 1242 in_progrss: 1243 /* 1244 * If the fs is not mounted or it is unmounting then there 1245 * is a background (un)mount in progress. In this case 1246 * we just drop the RPC request (return nil) and 1247 * wait for a retry, by which time the (un)mount may 1248 * have completed. 1249 */ 1250 #ifdef DEBUG 1251 dlog("ignoring mount of %s in %s -- in progress", 1252 fname, mf->mf_mount); 1253 #endif /* DEBUG */ 1254 in_progress++; 1255 continue; 1256 } 1257 1258 /* 1259 * Otherwise we have a hit: return the current mount point. 1260 */ 1261 #ifdef DEBUG 1262 dlog("matched %s in %s", fname, ap->am_path); 1263 #endif /* DEBUG */ 1264 free(fname); 1265 return ap; 1266 } 1267 } 1268 1269 if (in_progress) { 1270 #ifdef DEBUG 1271 dlog("Waiting while %d mount(s) in progress", in_progress); 1272 #endif /* DEBUG */ 1273 free(fname); 1274 ereturn(-1); 1275 } 1276 1277 /* 1278 * If an error occured then return it. 1279 */ 1280 if (error) { 1281 #ifdef DEBUG 1282 errno = error; /* XXX */ 1283 dlog("Returning error: %m", error); 1284 #endif /* DEBUG */ 1285 free(fname); 1286 ereturn(error); 1287 } 1288 1289 /* 1290 * If doing a delete then don't create again! 1291 */ 1292 switch (op) { 1293 case VLOOK_DELETE: 1294 ereturn(ENOENT); 1295 break; 1296 1297 case VLOOK_CREATE: 1298 break; 1299 1300 default: 1301 plog(XLOG_FATAL, "Unknown op to afs_lookuppn: 0x%x", op); 1302 ereturn(EINVAL); 1303 break; 1304 } 1305 1306 /* 1307 * If the server is going down then just return, 1308 * don't try to mount any more file systems 1309 */ 1310 if ((int)amd_state >= (int)Finishing) { 1311 #ifdef DEBUG 1312 dlog("not found - server going down anyway"); 1313 #endif /* DEBUG */ 1314 free(fname); 1315 ereturn(ENOENT); 1316 } 1317 1318 /* 1319 * If we get there then this is a reference to an, 1320 * as yet, unknown name so we need to search the mount 1321 * map for it. 1322 */ 1323 if (mp->am_pref) { 1324 sprintf(path_name, "%s%s", mp->am_pref, fname); 1325 pfname = path_name; 1326 } else { 1327 pfname = fname; 1328 } 1329 1330 mf = mp->am_mnt; 1331 1332 #ifdef DEBUG 1333 dlog("will search map info in %s to find %s", mf->mf_info, pfname); 1334 #endif /* DEBUG */ 1335 /* 1336 * Consult the oracle for some mount information. 1337 * info is malloc'ed and belongs to this routine. 1338 * It ends up being free'd in free_continuation(). 1339 * 1340 * Note that this may return -1 indicating that information 1341 * is not yet available. 1342 */ 1343 error = mapc_search((mnt_map*) mf->mf_private, pfname, &info); 1344 if (error) { 1345 if (error > 0) 1346 plog(XLOG_MAP, "No map entry for %s", pfname); 1347 else 1348 plog(XLOG_MAP, "Waiting on map entry for %s", pfname); 1349 free(fname); 1350 ereturn(error); 1351 } 1352 1353 #ifdef DEBUG 1354 dlog("mount info is %s", info); 1355 #endif /* DEBUG */ 1356 1357 /* 1358 * Split info into an argument vector. 1359 * The vector is malloc'ed and belongs to 1360 * this routine. It is free'd in free_continuation() 1361 */ 1362 xivec = ivec = strsplit(info, ' ', '\"'); 1363 1364 /* 1365 * Default error code... 1366 */ 1367 if (ap_hung) 1368 error = EWOULDBLOCK; 1369 else 1370 error = ENOENT; 1371 1372 /* 1373 * Allocate a new map 1374 */ 1375 new_mp = exported_ap_alloc(); 1376 if (new_mp == 0) { 1377 free((voidp) xivec); 1378 free((voidp) info); 1379 free((voidp) fname); 1380 ereturn(ENOSPC); 1381 } 1382 1383 if (mf->mf_auto) 1384 auto_opts = mf->mf_auto; 1385 else 1386 auto_opts = ""; 1387 1388 auto_opts = strdup(auto_opts); 1389 1390 #ifdef DEBUG 1391 dlog("searching for /defaults entry"); 1392 #endif /* DEBUG */ 1393 if (mapc_search((mnt_map*) mf->mf_private, "/defaults", &dflts) == 0) { 1394 char *dfl; 1395 char **rvec; 1396 #ifdef DEBUG 1397 dlog("/defaults gave %s", dflts); 1398 #endif /* DEBUG */ 1399 if (*dflts == '-') 1400 dfl = dflts+1; 1401 else 1402 dfl = dflts; 1403 1404 /* 1405 * Chop the defaults up 1406 */ 1407 rvec = strsplit(dfl, ' ', '\"'); 1408 /* 1409 * Extract first value 1410 */ 1411 dfl = rvec[0]; 1412 1413 /* 1414 * Log error if there were other values 1415 */ 1416 if (rvec[1]) { 1417 #ifdef DEBUG 1418 dlog("/defaults chopped into %s", dfl); 1419 #endif /* DEBUG */ 1420 plog(XLOG_USER, "More than a single value for /defaults in %s", mf->mf_info); 1421 } 1422 1423 /* 1424 * Don't need info vector any more 1425 */ 1426 free((voidp) rvec); 1427 1428 /* 1429 * If there were any values at all... 1430 */ 1431 if (dfl) { 1432 /* 1433 * Prepend to existing defaults if they exist, 1434 * otherwise just use these defaults. 1435 */ 1436 if (*auto_opts && *dfl) { 1437 char *nopts = (char *) xmalloc(strlen(auto_opts)+strlen(dfl)+2); 1438 sprintf(nopts, "%s;%s", dfl, auto_opts); 1439 free(auto_opts); 1440 auto_opts = nopts; 1441 } else if (*dfl) { 1442 auto_opts = strealloc(auto_opts, dfl); 1443 } 1444 } 1445 free(dflts); 1446 } 1447 1448 /* 1449 * Fill it in 1450 */ 1451 init_map(new_mp, fname); 1452 1453 /* 1454 * Put it in the table 1455 */ 1456 insert_am(new_mp, mp); 1457 1458 /* 1459 * Fill in some other fields, 1460 * path and mount point. 1461 * 1462 * bugfix: do not prepend old am_path if direct map 1463 * <wls@astro.umd.edu> William Sebok 1464 */ 1465 new_mp->am_path = str3cat(new_mp->am_path, 1466 mf->mf_ops == &dfs_ops ? "" : mp->am_path, 1467 *fname == '/' ? "" : "/", fname); 1468 1469 #ifdef DEBUG 1470 dlog("setting path to %s", new_mp->am_path); 1471 #endif /* DEBUG */ 1472 1473 /* 1474 * Take private copy of pfname 1475 */ 1476 pfname = strdup(pfname); 1477 1478 /* 1479 * Construct a continuation 1480 */ 1481 cp = ALLOC(continuation); 1482 cp->mp = new_mp; 1483 cp->xivec = xivec; 1484 cp->ivec = ivec; 1485 cp->info = info; 1486 cp->key = pfname; 1487 cp->auto_opts = auto_opts; 1488 cp->retry = FALSE; 1489 cp->tried = FALSE; 1490 cp->start = clocktime(); 1491 cp->def_opts = strdup(auto_opts); 1492 bzero((voidp) &cp->fs_opts, sizeof(cp->fs_opts)); 1493 1494 /* 1495 * Try and mount the file system 1496 * If this succeeds immediately (possible 1497 * for a ufs file system) then return 1498 * the attributes, otherwise just 1499 * return an error. 1500 */ 1501 error = afs_bgmount(cp, error); 1502 reschedule_timeout_mp(); 1503 if (!error) { 1504 free(fname); 1505 return new_mp; 1506 } 1507 1508 assign_error_mntfs(cp->mp); 1509 1510 free(fname); 1511 1512 ereturn(error); 1513 #undef ereturn 1514 } 1515 1516 /* 1517 * Locate next node in sibling list which is mounted 1518 * and is not an error node. 1519 */ 1520 static am_node *next_nonerror_node P((am_node *xp)); 1521 static am_node *next_nonerror_node(xp) 1522 am_node *xp; 1523 { 1524 mntfs *mf; 1525 1526 /* 1527 * Bug report (7/12/89) from Rein Tollevik <rein@ifi.uio.no> 1528 * Fixes a race condition when mounting direct automounts. 1529 * Also fixes a problem when doing a readdir on a directory 1530 * containing hung automounts. 1531 */ 1532 while (xp && 1533 (!(mf = xp->am_mnt) || /* No mounted filesystem */ 1534 mf->mf_error != 0 || /* There was a mntfs error */ 1535 xp->am_error != 0 || /* There was a mount error */ 1536 !(mf->mf_flags & MFF_MOUNTED) || /* The fs is not mounted */ 1537 (mf->mf_server->fs_flags & FSF_DOWN)) /* The fs may be down */ 1538 ) 1539 xp = xp->am_osib; 1540 1541 return xp; 1542 } 1543 1544 static int afs_readdir P((am_node *mp, nfscookie cookie, struct dirlist *dp, struct entry *ep, int count)); 1545 static int afs_readdir(mp, cookie, dp, ep, count) 1546 am_node *mp; 1547 nfscookie cookie; 1548 struct dirlist *dp; 1549 struct entry *ep; 1550 int count; 1551 { 1552 unsigned int gen = *(unsigned int*) cookie; 1553 am_node *xp; 1554 1555 dp->eof = FALSE; 1556 1557 if (gen == 0) { 1558 /* 1559 * In the default instance (which is used to 1560 * start a search) we return "." and "..". 1561 * 1562 * This assumes that the count is big enough 1563 * to allow both "." and ".." to be returned in 1564 * a single packet. If it isn't (which would 1565 * be fairly unbelievable) then tough. 1566 */ 1567 #ifdef DEBUG 1568 dlog("default search"); 1569 #endif /* DEBUG */ 1570 xp = next_nonerror_node(mp->am_child); 1571 dp->entries = ep; 1572 1573 /* construct "." */ 1574 ep[0].fileid = mp->am_gen; 1575 ep[0].name = "."; 1576 ep[0].nextentry = &ep[1]; 1577 *(unsigned int *) ep[0].cookie = 0; 1578 1579 /* construct ".." */ 1580 if (mp->am_parent) 1581 ep[1].fileid = mp->am_parent->am_gen; 1582 else 1583 ep[1].fileid = mp->am_gen; 1584 ep[1].name = ".."; 1585 ep[1].nextentry = 0; 1586 *(unsigned int *) ep[1].cookie = 1587 xp ? xp->am_gen : ~(unsigned int)0; 1588 1589 if (!xp) dp->eof = TRUE; 1590 return 0; 1591 } 1592 1593 #ifdef DEBUG 1594 dlog("real child"); 1595 #endif /* DEBUG */ 1596 1597 if (gen == ~(unsigned int)0) { 1598 #ifdef DEBUG 1599 dlog("End of readdir in %s", mp->am_path); 1600 #endif /* DEBUG */ 1601 dp->eof = TRUE; 1602 dp->entries = 0; 1603 return 0; 1604 } 1605 1606 xp = mp->am_child; 1607 while (xp && xp->am_gen != gen) 1608 xp = xp->am_osib; 1609 1610 if (xp) { 1611 int nbytes = count / 2; /* conservative */ 1612 int todo = MAX_READDIR_ENTRIES; 1613 dp->entries = ep; 1614 do { 1615 am_node *xp_next = next_nonerror_node(xp->am_osib); 1616 1617 if (xp_next) { 1618 *(unsigned int *) ep->cookie = xp_next->am_gen; 1619 } else { 1620 *(unsigned int *) ep->cookie = ~(unsigned int)0; 1621 dp->eof = TRUE; 1622 } 1623 1624 ep->fileid = xp->am_gen; 1625 ep->name = xp->am_name; 1626 nbytes -= sizeof(*ep) + strlen(xp->am_name) + 1; 1627 1628 xp = xp_next; 1629 1630 if (nbytes > 0 && !dp->eof && todo > 1) { 1631 ep->nextentry = ep + 1; 1632 ep++; 1633 --todo; 1634 } else { 1635 todo = 0; 1636 } 1637 } while (todo > 0); 1638 1639 ep->nextentry = 0; 1640 1641 return 0; 1642 } 1643 1644 return ESTALE; 1645 1646 } 1647 1648 static am_node *dfs_readlink P((am_node *mp, int *error_return)); 1649 static am_node *dfs_readlink(mp, error_return) 1650 am_node *mp; 1651 int *error_return; 1652 { 1653 am_node *xp; 1654 int rc = 0; 1655 1656 xp = next_nonerror_node(mp->am_child); 1657 if (!xp) { 1658 if (!mp->am_mnt->mf_private) 1659 afs_mkcacheref(mp->am_mnt); /* XXX */ 1660 xp = afs_lookuppn(mp, mp->am_path+1, &rc, VLOOK_CREATE); 1661 } 1662 1663 if (xp) { 1664 new_ttl(xp); /* (7/12/89) from Rein Tollevik */ 1665 return xp; 1666 } 1667 if (amd_state == Finishing) 1668 rc = ENOENT; 1669 *error_return = rc; 1670 return 0; 1671 } 1672 1673 /* 1674 * Ops structure 1675 */ 1676 am_ops root_ops = { 1677 "root", 1678 0, /* root_match */ 1679 0, /* root_init */ 1680 root_mount, 1681 0, 1682 afs_umount, 1683 0, 1684 afs_lookuppn, 1685 afs_readdir, 1686 0, /* root_readlink */ 1687 0, /* root_mounted */ 1688 0, /* root_umounted */ 1689 find_afs_srvr, 1690 FS_NOTIMEOUT|FS_AMQINFO|FS_DIRECTORY 1691 }; 1692 1693 am_ops afs_ops = { 1694 "auto", 1695 afs_match, 1696 0, /* afs_init */ 1697 afs_mount, 1698 0, 1699 afs_umount, 1700 0, 1701 afs_lookuppn, 1702 afs_readdir, 1703 0, /* afs_readlink */ 1704 0, /* afs_mounted */ 1705 afs_umounted, 1706 find_afs_srvr, 1707 FS_AMQINFO|FS_DIRECTORY 1708 }; 1709 1710 am_ops toplvl_ops = { 1711 "toplvl", 1712 afs_match, 1713 0, /* afs_init */ 1714 toplvl_mount, 1715 0, 1716 toplvl_umount, 1717 0, 1718 afs_lookuppn, 1719 afs_readdir, 1720 0, /* toplvl_readlink */ 1721 toplvl_mounted, 1722 0, /* toplvl_umounted */ 1723 find_afs_srvr, 1724 FS_MKMNT|FS_NOTIMEOUT|FS_BACKGROUND|FS_AMQINFO|FS_DIRECTORY 1725 }; 1726 1727 am_ops dfs_ops = { 1728 "direct", 1729 afs_match, 1730 0, /* dfs_init */ 1731 toplvl_mount, 1732 0, 1733 toplvl_umount, 1734 0, 1735 efs_lookuppn, 1736 efs_readdir, 1737 dfs_readlink, 1738 toplvl_mounted, 1739 0, /* afs_umounted */ 1740 find_afs_srvr, 1741 FS_MKMNT|FS_NOTIMEOUT|FS_BACKGROUND|FS_AMQINFO 1742 }; 1743 1744 #ifdef HAS_UNION_FS 1745 am_ops union_ops = { 1746 "union", 1747 afs_match, 1748 0, /* afs_init */ 1749 toplvl_mount, 1750 0, 1751 toplvl_umount, 1752 0, 1753 afs_lookuppn, 1754 afs_readdir, 1755 0, /* toplvl_readlink */ 1756 union_mounted, 1757 0, /* toplvl_umounted */ 1758 find_afs_srvr, 1759 FS_MKMNT|FS_NOTIMEOUT|FS_BACKGROUND|FS_AMQINFO|FS_DIRECTORY 1760 }; 1761 #endif /* HAS_UNION_FS */ 1762