1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 28 /* 29 * System includes 30 */ 31 32 #include <stdio.h> 33 #include <limits.h> 34 #include <errno.h> 35 #include <stdlib.h> 36 #include <unistd.h> 37 #include <string.h> 38 #include <wait.h> 39 #include <signal.h> 40 #include <malloc.h> 41 #include <sys/types.h> 42 #include <sys/mount.h> 43 #include <sys/stat.h> 44 #include <fcntl.h> 45 #include <sys/systeminfo.h> 46 #include <pkgstrct.h> 47 #include <pkginfo.h> 48 #include <locale.h> 49 #include <libintl.h> 50 51 #include <sys/mnttab.h> 52 #include <sys/mntent.h> 53 #include <sys/vfstab.h> 54 55 /* 56 * consolidation pkg command library includes 57 */ 58 59 #include <pkglib.h> 60 61 /* 62 * local pkg command library includes 63 */ 64 65 #include "install.h" 66 #include "libinst.h" 67 #include "libadm.h" 68 #include "messages.h" 69 70 extern char **environ; 71 72 static int match_mount; /* This holds the mount of interest. */ 73 74 int fs_tab_used = 0; 75 int fs_tab_alloc = 0; 76 static int fs_list = -1; 77 78 struct fstable **fs_tab = NULL; 79 80 #define PKGDBROOT "/var/sadm" 81 #define MOUNT "/sbin/mount" 82 #define UMOUNT "/sbin/umount" 83 84 #define setmntent fopen 85 #define endmntent fclose 86 #define MOUNT_TABLE MNTTAB 87 88 /* returned by already_mounted() */ 89 #define MNT_NOT 0 90 #define MNT_EXACT 1 91 #define MNT_AVAIL 2 92 93 /* used with is_remote_src() */ 94 #define NOT_REMOTE 0 95 #define REAL_REMOTE 1 96 #define SELF_SERVE 2 97 98 /* 99 * Due to /etc/mnttab files containing entries for multiple nfs hosts 100 * HOST_NM_LN needs to be accommodating. The recommended value in the sysinfo 101 * man page of 257 needs to be expanded. See bugid 4076513. 102 * 1024 chars is defined in the mnttab.h header as the max size of an entry. 103 */ 104 105 #define HOST_NM_LN MNT_LINE_MAX 106 107 /* These cachefs definitions should be in mntent.h. Maybe some day. */ 108 #define MNTTYPE_CFS "cachefs" 109 #define MNTOPT_BACKFSTYPE "backfstype" 110 #define MNTTYPE_AUTO "autofs" 111 112 /* 113 * Utilities for getting filesystem information from the mount table. 114 * 115 * Note: vanilla SVr4 code (pkginstall/dockspace.c) used the output from 116 * popen() on the "/etc/mount" command. However, we need to get more 117 * information about mounted filesystems, so we use the C interfaces to 118 * the mount table, which also happens to be much faster than running 119 * another process. Since several of the pkg commands need access to the 120 * the code has been placed here, to be included in the libinst library. 121 */ 122 123 #define ALLOC_CHUNK 30 124 125 /* 126 * fs_tab_ent_comp - compare fstable entries first by length in reverse 127 * order, then alphabetically. 128 */ 129 static int 130 fs_tab_ent_comp(const void *e1, const void *e2) 131 { 132 struct fstable *fs1 = *((struct fstable **)e1); 133 struct fstable *fs2 = *((struct fstable **)e2); 134 135 if (fs1->namlen == fs2->namlen) 136 return (strcmp(fs1->name, fs2->name)); 137 else 138 return (fs2->namlen - fs1->namlen); 139 } 140 141 /* 142 * This determines if the source of the mount is from another host. If it's 143 * from this host, then it might be writable. This returns NOT_REMOTE if it's 144 * pure local, REAL_REMOTE if it's being served from another host and 145 * SELF_SERVE if it's being served by the current host. 146 */ 147 static int 148 is_remote_src(char *source) 149 { 150 static char host_name[HOST_NM_LN]; 151 char source_host[HOST_NM_LN], *src_ptr, *src_host_ptr; 152 static int hn_len; 153 154 if (hn_len == 0) { 155 /* Find out what host this is. */ 156 (void) sysinfo(SI_HOSTNAME, host_name, HOST_NM_LN); 157 hn_len = strlen(host_name); 158 } 159 160 if (source[0] == '/') 161 return (NOT_REMOTE); /* No server name, so it's local. */ 162 163 if (strchr(source, ':') == NULL) 164 return (NOT_REMOTE); /* it's a floppy disk or something */ 165 166 src_ptr = source; 167 src_host_ptr = source_host; 168 169 /* Scan to the end of the hostname (find the ":"). */ 170 while (*src_ptr != ':') 171 *src_host_ptr++ = *src_ptr++; 172 *src_host_ptr = '\0'; 173 174 /* Multiple hosts: failover with multiple servers; this is remote. */ 175 if (strchr(source_host, ',') != NULL) 176 return (REAL_REMOTE); 177 178 if (strncmp(source, host_name, hn_len) == 0 && 179 *(source+hn_len) == ':' || is_local_host(source_host)) 180 return (SELF_SERVE); /* Exporting from itself, it's local. */ 181 182 return (REAL_REMOTE); 183 } 184 185 /* 186 * This determines if an apparently writeable filesystem is really writeable 187 * or if it's been shared over the network with root-restrictive options. 188 */ 189 static int 190 really_write(char *mountpt) 191 { 192 char testfile[PATH_MAX]; 193 int fd, retval = 0; 194 struct stat status; 195 196 (void) snprintf(testfile, sizeof (testfile), "%s/testXXXXXX", mountpt); 197 198 if (mktemp(testfile) == NULL) 199 return (0); /* may as well be read-only */ 200 /* LINTED do not use creat(); use open(path,... */ 201 else if ((fd = creat(testfile, 0777)) == -1) 202 return (0); /* can't write */ 203 else if (fstat(fd, &status) == -1) 204 retval = 0; /* may as well be read-only */ 205 else if (status.st_uid != 0) 206 retval = 0; /* too many restrictions */ 207 else 208 retval = 1; 209 210 (void) close(fd); 211 (void) unlink(testfile); 212 213 return (retval); 214 } 215 216 /* This returns the hostname portion of a remote path. */ 217 char * 218 get_server_host(short n) 219 { 220 static char hostname[HOST_NM_LN], *host_end; 221 222 if (fs_tab_used == 0) { 223 return ("unknown source"); 224 } 225 226 if (n >= 0 && n < fs_tab_used) { 227 (void) strcpy(hostname, fs_tab[n]->remote_name); 228 if ((host_end = strchr(hostname, ':')) == NULL) { 229 if ((strcmp(fs_tab[n]->fstype, MNTTYPE_AUTO)) == NULL) 230 return ("automounter"); 231 else 232 return (fs_tab[n]->fstype); 233 } else { 234 *host_end = '\0'; 235 return (hostname); 236 } 237 } 238 239 return ("unknown source"); 240 } 241 242 /* 243 * This pulls the path out of a hostpath which may be of the form host:path 244 * where path is an absolute path. NOTE: If path turns out to be relative, 245 * this returns NULL. 246 */ 247 static char * 248 path_part(char *hostpath) 249 { 250 char *host_end; 251 252 if ((host_end = strchr(hostpath, ':')) == NULL && hostpath[0] == '/') 253 return (hostpath); /* It's already legit. */ 254 255 if (*(host_end+1) == '/') 256 return (host_end+1); /* Here's the path part. */ 257 258 return (NULL); 259 } 260 261 /* 262 * This scans the filesystems already mounted to see if this remote mount is 263 * already in place on the server. This scans the fs_tab for a remote_name 264 * exactly matching the client's. It stores the current entry number 265 * corresponding to this mount in the static match_mount. 266 * 267 * Returns: 268 * MNT_NOT Couldn't find it. 269 * MNT_EXACT This has actually been manually mounted for us 270 * MNT_AVAIL This is mounted for the server, but needs to be 271 * loopback mounted from the client's perspective. 272 */ 273 static int 274 already_mounted(struct vfstab *vfs, int is_local_host, char *client_path, 275 char *host_path) 276 { 277 int i; 278 279 match_mount = -1; 280 281 if (fs_tab_used == 0) { 282 return (MNT_NOT); 283 } 284 285 for (i = 0; i < fs_tab_used; i++) { 286 /* 287 * Determine if this has been manually mounted exactly as we 288 * require. Begin by finding a mount on our current 289 * mountpoint. 290 */ 291 if (strcmp(fs_tab[i]->name, client_path) == 0) { 292 /* 293 * Now see if it is really the same mount. This isn't 294 * smart enough to find mounts on top of mounts, but 295 * assuming there is no conspiracy to fool this 296 * function, it will be good enough. 297 */ 298 if (is_local_host && 299 strcmp(fs_tab[i]->remote_name, host_path) == 0) { 300 match_mount = i; 301 return (MNT_EXACT); 302 } 303 } 304 305 /* Determine if this mount is available to the server. */ 306 if (strcmp(fs_tab[i]->remote_name, vfs->vfs_special) == 0) { 307 match_mount = i; 308 return (MNT_AVAIL); 309 } 310 } 311 return (MNT_NOT); 312 } 313 314 /* 315 * This function unmounts all of the loopback mounts created for the client. 316 * If no client stuff is mounted, this is completely benign, it finds that 317 * nothing is mounted up and returns. It returns "1" for unmounted everything 318 * OK and "0" for failure. 319 */ 320 int 321 unmount_client() 322 { 323 int errcode; 324 int exit_no; 325 int n; 326 int retcode = 1; 327 int status; 328 pid_t pid; 329 pid_t pid_return; 330 331 if (fs_tab_used == 0) { 332 return (1); 333 } 334 335 for (n = 0; n < fs_tab_used-1; n++) { 336 /* If the filesystem is mounted and this utility did it ... */ 337 if (fs_tab[n]->cl_mounted && fs_tab[n]->srvr_map) { 338 char *arg[3]; 339 340 /* create arglist for umount command */ 341 342 arg[0] = UMOUNT; 343 arg[1] = fs_tab[n]->name; 344 arg[2] = (char *)NULL; 345 346 /* flush standard i/o before creating new process */ 347 348 (void) fflush(stderr); 349 (void) fflush(stdout); 350 351 /* 352 * create new process to execute command in; 353 * vfork is being used to avoid duplicating the parents 354 * memory space - this means that the child process may 355 * not modify any of the parents memory including the 356 * standard i/o descriptors - all the child can do is 357 * adjust interrupts and open files as a prelude to a 358 * call to exec(). 359 */ 360 361 pid = vfork(); 362 if (pid < 0) { 363 /* fork failed! */ 364 365 logerr(WRN_BAD_FORK, errno, strerror(errno)); 366 retcode = 0; 367 } else if (pid > 0) { 368 /* 369 * this is the parent process 370 */ 371 372 status = 0; 373 pid_return = waitpid(pid, &status, 0); 374 375 if (pid_return != pid) { 376 logerr(WRN_BAD_WAIT, pid, pid_return, 377 (unsigned long)status, errno, 378 strerror(errno)); 379 retcode = 0; 380 } 381 382 /* 383 * If the child was stopped or killed by a 384 * signal or exied with any code but 0, we 385 * assume the mount has failed. 386 */ 387 388 if (!WIFEXITED(status) || 389 (errcode = WEXITSTATUS(status))) { 390 retcode = 0; 391 logerr(WRN_FSTAB_UMOUNT, 392 fs_tab[n]->name, errcode); 393 } else { 394 fs_tab[n]->cl_mounted = 0; 395 } 396 } else { 397 /* 398 * this is the child process 399 */ 400 401 int i; 402 403 /* reset any signals to default */ 404 405 for (i = 0; i < NSIG; i++) { 406 (void) sigset(i, SIG_DFL); 407 } 408 409 /* 410 * Redirect output to /dev/null because the 411 * umount error message may be confusing to 412 * the user. 413 */ 414 415 i = open("/dev/null", O_WRONLY); 416 if (i >= 0) { 417 dup2(2, STDERR_FILENO); 418 } 419 420 /* close all file descriptors except stdio */ 421 422 closefrom(3); 423 424 exit_no = execve(arg[0], arg, environ); 425 _exit(exit_no); 426 } 427 } 428 } 429 430 return (retcode); 431 } 432 433 /* 434 * This function creates the necessary loopback mounts to emulate the client 435 * configuration with respect to the server. If this is being run on a 436 * standalone or the installation is actually to the local system, this call 437 * is benign since srvr_map won't be set anywhere. It returns "1" for mounted 438 * everything OK and "0" for failure. 439 */ 440 int 441 mount_client() 442 { 443 int errcode; 444 int exit_no; 445 int n; 446 int retcode = 1; 447 int status; 448 pid_t pid; 449 pid_t pid_return; 450 451 if (fs_tab_used == 0) { 452 return (1); 453 } 454 455 for (n = fs_tab_used-1; n >= 0; n--) { 456 /* 457 * If the filesystem is mounted (meaning available) and the 458 * apparent filesystem can be mapped to a local filesystem 459 * AND the local filesystem is not the same as the target 460 * filesystem, mount it. 461 */ 462 if (fs_tab[n]->mounted && fs_tab[n]->srvr_map) { 463 char *arg[6]; 464 465 /* create arglist for mount command */ 466 467 arg[0] = MOUNT; 468 arg[1] = "-F"; 469 arg[2] = "lofs"; 470 arg[3] = fs_tab[n]->remote_name; 471 arg[4] = fs_tab[n]->name; 472 arg[5] = (char *)NULL; 473 474 /* flush standard i/o before creating new process */ 475 476 (void) fflush(stderr); 477 (void) fflush(stdout); 478 479 /* 480 * create new process to execute command in; 481 * vfork is being used to avoid duplicating the parents 482 * memory space - this means that the child process may 483 * not modify any of the parents memory including the 484 * standard i/o descriptors - all the child can do is 485 * adjust interrupts and open files as a prelude to a 486 * call to exec(). 487 */ 488 489 pid = vfork(); 490 if (pid < 0) { 491 /* fork failed! */ 492 493 logerr(WRN_BAD_FORK, errno, strerror(errno)); 494 retcode = 0; 495 } else if (pid > 0) { 496 /* 497 * this is the parent process 498 */ 499 500 pid_return = waitpid(pid, &status, 0); 501 502 if (pid_return != pid) { 503 logerr(WRN_BAD_WAIT, pid, pid_return, 504 (unsigned long)status, errno, 505 strerror(errno)); 506 retcode = 0; 507 } 508 509 /* 510 * If the child was stopped or killed by a 511 * signal or exied with any code but 0, we 512 * assume the mount has failed. 513 */ 514 515 if (!WIFEXITED(status) || 516 (errcode = WEXITSTATUS(status))) { 517 retcode = 0; 518 fs_tab[n]->mnt_failed = 1; 519 logerr(WRN_FSTAB_MOUNT, 520 fs_tab[n]->name, errcode); 521 } else { 522 fs_tab[n]->cl_mounted = 1; 523 } 524 } else { 525 /* 526 * this is the child process 527 */ 528 529 int i; 530 531 /* reset all signals to default */ 532 533 for (i = 0; i < NSIG; i++) { 534 (void) sigset(i, SIG_DFL); 535 } 536 537 /* 538 * Redirect output to /dev/null because the 539 * mount error message may be confusing to 540 * the user. 541 */ 542 543 i = open("/dev/null", O_WRONLY); 544 if (i >= 0) { 545 dup2(i, STDERR_FILENO); 546 } 547 548 /* close all file descriptors except stdio */ 549 550 closefrom(3); 551 552 exit_no = execve(arg[0], arg, environ); 553 _exit(exit_no); 554 /*NOTREACHED*/ 555 } 556 } 557 } 558 return (retcode); 559 } 560 561 /* 562 * This function maps path, on a loopback filesystem, back to the real server 563 * filesystem. fsys_value is the fs_tab[] entry to which the loopback'd path is 564 * mapped. This returns a pointer to a static area. If the result is needed 565 * for further processing, it should be strdup()'d or something. 566 */ 567 char * 568 server_map(char *path, short fsys_value) 569 { 570 static char server_construction[PATH_MAX]; 571 572 if (fs_tab_used == 0) { 573 (void) strcpy(server_construction, path); 574 } else if (fsys_value >= 0 && fsys_value < fs_tab_used) { 575 (void) snprintf(server_construction, 576 sizeof (server_construction), 577 "%s%s", fs_tab[fsys_value]->remote_name, 578 path+strlen(fs_tab[fsys_value]->name)); 579 } else { 580 (void) strcpy(server_construction, path); 581 } 582 583 return (server_construction); 584 } 585 586 /* This function sets up the standard parts of the fs_tab. */ 587 static struct fstable * 588 fs_tab_init(char *mountp, char *fstype) 589 { 590 struct fstable *nfte; 591 592 /* Create the array if necessary. */ 593 if (fs_list == -1) { 594 fs_list = ar_create(ALLOC_CHUNK, 595 (unsigned)sizeof (struct fstable), 596 "filesystem mount data"); 597 if (fs_list == -1) { 598 progerr(ERR_MALLOC, "fs_list", errno, strerror(errno)); 599 return (NULL); 600 } 601 } 602 603 /* 604 * Allocate an fstable entry for this mnttab entry. 605 */ 606 if ((nfte = *(struct fstable **)ar_next_avail(fs_list)) 607 == NULL) { 608 progerr(ERR_MALLOC, "nfte", errno, strerror(errno)); 609 return (NULL); 610 } 611 612 /* 613 * Point fs_tab at the head of the array again, since it may have 614 * moved due to realloc in ar_next_avail(). If ar_next_avail() realizes 615 * that there is no more room to grow the array, it reallocates the 616 * array. Because we stored pointer to that array in fs_tab, we need 617 * to make sure that it is updated as well. 618 */ 619 if ((fs_tab = (struct fstable **)ar_get_head(fs_list)) == NULL) { 620 progerr(ERR_NOTABLE, "mount", MOUNT_TABLE, strerror(errno)); 621 return (NULL); 622 } 623 624 /* 625 * Get the length of the 'mount point' name. 626 */ 627 nfte->namlen = strlen(mountp); 628 /* 629 * Allocate space for the 'mount point' name. 630 */ 631 if ((nfte->name = malloc(nfte->namlen+1)) == NULL) { 632 progerr(ERR_MALLOC, "name", errno, strerror(errno)); 633 return (NULL); 634 } 635 (void) strcpy(nfte->name, mountp); 636 637 if ((nfte->fstype = malloc(strlen(fstype)+1)) == NULL) { 638 progerr(ERR_MALLOC, "fstype", errno, strerror(errno)); 639 return (NULL); 640 } 641 (void) strcpy(nfte->fstype, fstype); 642 643 fs_tab_used++; 644 645 return (nfte); 646 } 647 648 /* This function frees all memory associated with the filesystem table. */ 649 void 650 fs_tab_free(void) 651 { 652 int n; 653 654 if (fs_tab_used == 0) { 655 return; 656 } 657 658 for (n = 0; n < fs_tab_used; n++) { 659 free(fs_tab[n]->fstype); 660 free(fs_tab[n]->name); 661 free(fs_tab[n]->remote_name); 662 } 663 664 ar_free(fs_list); 665 } 666 667 /* This function scans a string of mount options for a specific keyword. */ 668 static int 669 hasopt(char *options, char *keyword) 670 { 671 char vfs_options[VFS_LINE_MAX], *optptr; 672 673 if (!options) { 674 (void) strcpy(vfs_options, "ro"); 675 } else { 676 (void) strcpy(vfs_options, options); 677 } 678 679 while (optptr = strrchr(vfs_options, ',')) { 680 *optptr++ = '\0'; 681 682 if (strcmp(optptr, keyword) == 0) 683 return (1); 684 } 685 686 /* Now deal with the remainder. */ 687 if (strcmp(vfs_options, keyword) == 0) 688 return (1); 689 690 return (0); 691 } 692 693 /* 694 * This function constructs a new filesystem table (fs_tab[]) entry based on 695 * an /etc/mnttab entry. When it returns, the new entry has been inserted 696 * into fs_tab[]. 697 */ 698 static int 699 construct_mt(struct mnttab *mt) 700 { 701 struct fstable *nfte; 702 703 /* 704 * Initialize fstable structure and make the standard entries. 705 */ 706 if ((nfte = fs_tab_init(mt->mnt_mountp, mt->mnt_fstype)) == NULL) 707 return (1); 708 709 /* 710 * See if this is served from another host. 711 * Testing the type is cheap; finding the hostname is not. 712 * At this point, we're using the REAL mnttab; since we're not 713 * allowed to mount ourself with "NFS", "NFS" must be remote. 714 * The automount will translate "nfs:self" to a lofs mount. 715 */ 716 if (strcmp(mt->mnt_fstype, MNTTYPE_AUTO) == 0 || 717 strcmp(mt->mnt_fstype, MNTTYPE_NFS) == 0 || 718 is_remote_src(mt->mnt_special) == REAL_REMOTE) 719 nfte->remote = 1; 720 else 721 nfte->remote = 0; 722 723 /* It's mounted now (by definition), so we don't have to remap it. */ 724 nfte->srvr_map = 0; 725 nfte->mounted = 1; 726 727 nfte->remote_name = strdup(mt->mnt_special); 728 729 /* 730 * This checks the mount commands which establish the most 731 * basic level of access. Later further tests may be 732 * necessary to fully qualify this. We set this bit 733 * preliminarily because we have access to the mount data 734 * now. 735 */ 736 nfte->writeable = 0; /* Assume read-only. */ 737 if (hasmntopt(mt, MNTOPT_RO) == NULL) { 738 nfte->writeable = 1; 739 if (!(nfte->remote)) 740 /* 741 * There's no network involved, so this 742 * assessment is confirmed. 743 */ 744 nfte->write_tested = 1; 745 } else 746 /* read-only is read-only */ 747 nfte->write_tested = 1; 748 749 /* Is this coming to us from a server? */ 750 if (nfte->remote && !(nfte->writeable)) 751 nfte->served = 1; 752 753 return (0); 754 } 755 756 /* 757 * This function modifies an existing fs_tab[] entry. It was found mounted up 758 * exactly the way we would have mounted it in mount_client() only at the 759 * time we didn't know it was for the client. Now we do, so we're setting the 760 * various permissions to conform to the client view. 761 */ 762 static void 763 mod_existing(struct vfstab *vfsent, int fstab_entry, int is_remote) 764 { 765 /* 766 * Establish whether the client will see this as served. 767 */ 768 if (is_remote && hasopt(vfsent->vfs_mntopts, MNTOPT_RO)) 769 fs_tab[fstab_entry]->served = 1; 770 771 fs_tab[fstab_entry]->cl_mounted = 1; 772 } 773 774 /* 775 * This function constructs a new fs_tab[] entry based on 776 * an /etc/vfstab entry. When it returns, the new entry has been inserted 777 * into fstab[]. 778 */ 779 static int 780 construct_vfs(struct vfstab *vfsent, char *client_path, char *link_name, 781 int is_remote, int mnt_stat) 782 { 783 int use_link; 784 struct fstable *nfte; 785 786 if ((nfte = fs_tab_init(client_path, vfsent->vfs_fstype)) == NULL) 787 return (1); 788 789 nfte->remote = (is_remote == REAL_REMOTE); 790 791 /* 792 * The file system mounted on the client may or may not be writeable. 793 * So we hand it over to fsys() to evaluate. This will have the same 794 * read/write attributes as the corresponding mounted filesystem. 795 */ 796 use_link = 0; 797 if (nfte->remote) { 798 /* 799 * Deal here with mount points actually on a system remote 800 * from the server. 801 */ 802 if (mnt_stat == MNT_NOT) { 803 /* 804 * This filesystem isn't in the current mount table 805 * meaning it isn't mounted, the current host can't 806 * write to it and there's no point to mapping it for 807 * the server. 808 */ 809 link_name = NULL; 810 nfte->mounted = 0; 811 nfte->srvr_map = 0; 812 nfte->writeable = 0; 813 } else { /* It's MNT_AVAIL. */ 814 /* 815 * This filesystem is associated with a current 816 * mountpoint. Since it's mounted, it needs to be 817 * remapped and it is writable if the real mounted 818 * filesystem is writeable. 819 */ 820 use_link = 1; 821 link_name = strdup(fs_tab[match_mount]->name); 822 nfte->mounted = 1; 823 nfte->srvr_map = 1; 824 nfte->writeable = fs_tab[match_mount]->writeable; 825 nfte->write_tested = fs_tab[match_mount]->write_tested; 826 } 827 } else { /* local filesystem */ 828 use_link = 1; 829 nfte->mounted = 1; 830 nfte->srvr_map = 1; 831 nfte->writeable = fs_tab[fsys(link_name)]->writeable; 832 nfte->write_tested = 1; 833 } 834 835 /* 836 * Now we establish whether the client will see this as served. 837 */ 838 if (is_remote && hasopt(vfsent->vfs_mntopts, MNTOPT_RO)) 839 nfte->served = 1; 840 841 if (use_link) { 842 nfte->remote_name = link_name; 843 } else { 844 nfte->remote_name = strdup(vfsent->vfs_special); 845 } 846 847 return (0); 848 } 849 850 /* 851 * get_mntinfo - get the mount table, now dynamically allocated. Returns 0 if 852 * no problem and 1 if there's a fatal error. 853 */ 854 int 855 get_mntinfo(int map_client, char *vfstab_file) 856 { 857 static char *rn = "/"; 858 FILE *pp; 859 struct mnttab mtbuf; 860 struct mnttab *mt = &mtbuf; 861 char *install_root; 862 int is_remote; 863 864 /* 865 * Open the mount table for the current host and establish a global 866 * table that holds data about current mount status. 867 */ 868 if ((pp = setmntent(MOUNT_TABLE, "r")) == NULL) { 869 progerr(ERR_NOTABLE, "mount", MOUNT_TABLE, strerror(errno)); 870 return (1); 871 } 872 873 /* 874 * First, review the mounted filesystems on the managing host. This 875 * may also be the target host but we haven't decided that for sure 876 * yet. 877 */ 878 while (!getmntent(pp, mt)) 879 if (construct_mt(mt)) 880 return (1); 881 882 (void) endmntent(pp); 883 884 /* 885 * Now, we see if this installation is to a client. If it is, we scan 886 * the client's vfstab to determine what filesystems are 887 * inappropriate to write to. This simply adds the vfstab entries 888 * representing what will be remote file systems for the client. 889 * Everything that isn't remote to the client is already accounted 890 * for in the fs_tab[] so far. If the remote filesystem is really on 891 * this server, we will write through to the server from this client. 892 */ 893 install_root = get_inst_root(); 894 if (install_root && strcmp(install_root, "/") != 0 && map_client) { 895 /* OK, this is a legitimate remote client. */ 896 struct vfstab vfsbuf; 897 struct vfstab *vfs = &vfsbuf; 898 char VFS_TABLE[PATH_MAX]; 899 900 /* 901 * Since we use the fsys() function later, and it depends on 902 * an ordered list, we have to sort the list here. 903 */ 904 qsort(fs_tab, fs_tab_used, 905 sizeof (struct fstable *), fs_tab_ent_comp); 906 907 /* 908 * Here's where the vfstab for the target is. If we can get 909 * to it, we'll scan it for what the client will see as 910 * remote filesystems, otherwise, we'll just skip this. 911 */ 912 if (vfstab_file) { 913 (void) snprintf(VFS_TABLE, sizeof (VFS_TABLE), "%s", 914 vfstab_file); 915 } else { 916 (void) snprintf(VFS_TABLE, sizeof (VFS_TABLE), "%s%s", 917 install_root, VFSTAB); 918 } 919 920 if (access(VFS_TABLE, R_OK) == 0) { 921 char *link_name; 922 923 /* 924 * Open the vfs table for the target host. 925 */ 926 if ((pp = setmntent(VFS_TABLE, "r")) == NULL) { 927 progerr(ERR_NOTABLE, "vfs", VFS_TABLE, 928 strerror(errno)); 929 return (1); 930 } 931 932 /* Do this for each entry in the vfstab. */ 933 while (!getvfsent(pp, vfs)) { 934 char client_mountp[PATH_MAX]; 935 int mnt_stat; 936 937 /* 938 * We put it into the fs table if it's 939 * remote mounted (even from this server) or 940 * loopback mounted from the client's point 941 * of view. 942 */ 943 if (!(is_remote = 944 is_remote_src(vfs->vfs_special)) && 945 strcmp(vfs->vfs_fstype, MNTTYPE_LOFS) != 946 0) 947 continue; /* not interesting */ 948 949 /* 950 * Construct client_mountp by prepending the 951 * install_root to the 'mount point' name. 952 */ 953 if (strcmp(vfs->vfs_mountp, "/") == 0) { 954 (void) strcpy(client_mountp, 955 install_root); 956 } else { 957 (void) snprintf(client_mountp, 958 sizeof (client_mountp), "%s%s", 959 install_root, vfs->vfs_mountp); 960 } 961 962 /* 963 * We also skip the entry if the vfs_special 964 * path and the client_path are the same. 965 * There's no need to mount it, it's just a 966 * cachefs optimization that mounts a 967 * directory over itself from this server. 968 */ 969 if ((is_remote == SELF_SERVE) && 970 strcmp(path_part(vfs->vfs_special), 971 client_mountp) == 0) 972 continue; 973 974 /* Determine if this is already mounted. */ 975 link_name = strdup(path_part(vfs->vfs_special)); 976 mnt_stat = already_mounted(vfs, 977 (is_remote != REAL_REMOTE), client_mountp, 978 link_name); 979 980 if (mnt_stat == MNT_EXACT) { 981 mod_existing(vfs, match_mount, 982 is_remote); 983 } else { /* MNT_NOT */ 984 if (construct_vfs(vfs, client_mountp, 985 link_name, is_remote, mnt_stat)) 986 return (1); 987 } 988 } 989 (void) endmntent(pp); 990 } /* end of if(access()) */ 991 } /* end of if(install_root) */ 992 993 /* This next one may look stupid, but it can really happen. */ 994 if (fs_tab_used <= 0) { 995 progerr(ERR_MNT_NOMOUNTS); 996 return (1); 997 } 998 999 /* 1000 * Now that we have the complete list of mounted (or virtually 1001 * mounted) filesystems, we sort the mountpoints in reverse order 1002 * based on the length of the 'mount point' name. 1003 */ 1004 qsort(fs_tab, fs_tab_used, sizeof (struct fstable *), fs_tab_ent_comp); 1005 if (strcmp(fs_tab[fs_tab_used-1]->name, rn) != 0) { 1006 progerr(ERR_MNT_NOROOT, fs_tab[fs_tab_used-1]->name, rn, errno, 1007 strerror(errno)); 1008 return (1); 1009 } else { 1010 return (0); 1011 } 1012 } 1013 1014 /* 1015 * This function supports dryrun mode by allowing the filesystem table to be 1016 * directly loaded from the continuation file. 1017 */ 1018 int 1019 load_fsentry(struct fstable *fs_entry, char *name, char *fstype, 1020 char *remote_name) 1021 { 1022 struct fstable *nfte; 1023 1024 if ((nfte = fs_tab_init(name, fstype)) == NULL) 1025 return (1); 1026 1027 /* Grab the name and fstype from the new structure. */ 1028 fs_entry->name = nfte->name; 1029 fs_entry->fstype = nfte->fstype; 1030 1031 /* Copy the basic structure into place. */ 1032 (void) memcpy(nfte, fs_entry, sizeof (struct fstable)); 1033 1034 /* 1035 * Allocate space for the 'special' name. 1036 */ 1037 if ((nfte->remote_name = malloc(strlen(remote_name)+1)) == NULL) { 1038 progerr(ERR_MALLOC, "remote_name", errno, strerror(errno)); 1039 return (1); 1040 } 1041 1042 (void) strcpy(nfte->remote_name, remote_name); 1043 1044 return (0); 1045 } 1046 1047 /* 1048 * Given a path, return the table index of the filesystem the file apparently 1049 * resides on. This doesn't put any time into resolving filesystems that 1050 * refer to other filesystems. It just returns the entry containing this 1051 * path. 1052 */ 1053 short 1054 fsys(char *path) 1055 { 1056 register int i; 1057 char real_path[PATH_MAX]; 1058 char *path2use = NULL; 1059 char *cp = NULL; 1060 int pathlen; 1061 1062 path2use = path; 1063 1064 real_path[0] = '\0'; 1065 1066 (void) realpath(path, real_path); 1067 1068 if (real_path[0]) { 1069 cp = strstr(path, real_path); 1070 if (cp != path || cp == NULL) 1071 path2use = real_path; 1072 } 1073 1074 pathlen = strlen(path2use); 1075 1076 /* 1077 * The following algorithm scans the list of attached file systems 1078 * for the one containing path. At this point the file names in 1079 * fs_tab[] are sorted by decreasing length to facilitate the scan. 1080 * The first for() scans past all the file system names too short to 1081 * contain path. The second for() does the actual string comparison. 1082 * It tests first to assure that the comparison is against a complete 1083 * token by assuring that the end of the filesystem name aligns with 1084 * the end of a token in path2use (ie: '/' or NULL) then it does a 1085 * string compare. -- JST 1086 */ 1087 1088 if (fs_tab_used == 0) { 1089 return (-1); 1090 } 1091 1092 for (i = 0; i < fs_tab_used; i++) 1093 if (fs_tab[i] == NULL) 1094 continue; 1095 else if (fs_tab[i]->namlen <= pathlen) 1096 break; 1097 for (; i < fs_tab_used; i++) { 1098 int fs_namelen; 1099 char term_char; 1100 1101 if (fs_tab[i] == NULL) 1102 continue; 1103 1104 fs_namelen = fs_tab[i]->namlen; 1105 term_char = path2use[fs_namelen]; 1106 1107 /* 1108 * If we're putting the file "/a/kernel" into the filesystem 1109 * "/a", then fs_namelen == 2 and term_char == '/'. If, we're 1110 * putting "/etc/termcap" into "/", fs_namelen == 1 and 1111 * term_char (unfortunately) == 'e'. In the case of 1112 * fs_namelen == 1, we check to make sure the filesystem is 1113 * "/" and if it is, we have a guaranteed fit, otherwise we 1114 * do the string compare. -- JST 1115 */ 1116 if ((fs_namelen == 1 && *(fs_tab[i]->name) == '/') || 1117 ((term_char == '/' || term_char == NULL) && 1118 strncmp(fs_tab[i]->name, path2use, fs_namelen) == 0)) 1119 return (i); 1120 } 1121 1122 /* 1123 * It only gets here if the root filesystem is fundamentally corrupt. 1124 * (This can happen!) 1125 */ 1126 progerr(ERR_FSYS_FELLOUT, path2use); 1127 1128 return (-1); 1129 } 1130 1131 /* 1132 * This function returns the entry in the fs_tab[] corresponding to the 1133 * actual filesystem of record. It won't return a loopback filesystem entry, 1134 * it will return the filesystem that the loopback filesystem is mounted 1135 * over. 1136 */ 1137 short 1138 resolved_fsys(char *path) 1139 { 1140 int i = -1; 1141 char path2use[PATH_MAX]; 1142 1143 (void) strcpy(path2use, path); 1144 1145 /* If this isn't a "real" filesystem, resolve the map. */ 1146 do { 1147 (void) strcpy(path2use, server_map(path2use, i)); 1148 i = fsys(path2use); 1149 } while (fs_tab[i]->srvr_map); 1150 1151 return (i); 1152 } 1153 1154 /* 1155 * This function returns the srvr_map status based upon the fs_tab entry 1156 * number. This tells us if the server path constructed from the package 1157 * install root is really the target filesystem. 1158 */ 1159 int 1160 use_srvr_map_n(short n) 1161 { 1162 return ((int)fs_tab[n]->srvr_map); 1163 } 1164 1165 /* 1166 * This function returns the mount status based upon the fs_tab entry 1167 * number. This tells us if there is any hope of gaining access 1168 * to this file system. 1169 */ 1170 int 1171 is_mounted_n(short n) 1172 { 1173 return ((int)fs_tab[n]->mounted); 1174 } 1175 1176 /* 1177 * is_fs_writeable_n - given an fstab index, return 1 1178 * if it's writeable, 0 if read-only. 1179 */ 1180 int 1181 is_fs_writeable_n(short n) 1182 { 1183 /* 1184 * If the write access permissions haven't been confirmed, do that 1185 * now. Note that the only reason we need to do the special check is 1186 * in the case of an NFS mount (remote) because we can't determine if 1187 * root has access in any other way. 1188 */ 1189 if (fs_tab[n]->remote && fs_tab[n]->mounted && 1190 !fs_tab[n]->write_tested) { 1191 if (fs_tab[n]->writeable && !really_write(fs_tab[n]->name)) 1192 fs_tab[n]->writeable = 0; /* not really */ 1193 1194 fs_tab[n]->write_tested = 1; /* confirmed */ 1195 } 1196 1197 return ((int)fs_tab[n]->writeable); 1198 } 1199 1200 /* 1201 * is_remote_fs_n - given an fstab index, return 1 1202 * if it's a remote filesystem, 0 if local. 1203 * 1204 * Note: Upon entry, a valid fsys() is required. 1205 */ 1206 int 1207 is_remote_fs_n(short n) 1208 { 1209 return ((int)fs_tab[n]->remote); 1210 } 1211 1212 /* index-driven is_served() */ 1213 int 1214 is_served_n(short n) 1215 { 1216 return ((int)fs_tab[n]->served); 1217 } 1218 1219 /* 1220 * This returns the number of blocks available on the indicated filesystem. 1221 * 1222 * Note: Upon entry, a valid fsys() is required. 1223 */ 1224 fsblkcnt_t 1225 get_blk_free_n(short n) 1226 { 1227 return (fs_tab[n]->bfree); 1228 } 1229 1230 /* 1231 * This returns the number of blocks being used on the indicated filesystem. 1232 * 1233 * Note: Upon entry, a valid fsys() is required. 1234 */ 1235 fsblkcnt_t 1236 get_blk_used_n(short n) 1237 { 1238 return (fs_tab[n]->bused); 1239 } 1240 1241 /* 1242 * This returns the number of inodes available on the indicated filesystem. 1243 * 1244 * Note: Upon entry, a valid fsys() is required. 1245 */ 1246 fsblkcnt_t 1247 get_inode_free_n(short n) 1248 { 1249 return (fs_tab[n]->ffree); 1250 } 1251 1252 /* 1253 * This returns the number of inodes being used on the indicated filesystem. 1254 * 1255 * Note: Upon entry, a valid fsys() is required. 1256 */ 1257 fsblkcnt_t 1258 get_inode_used_n(short n) 1259 { 1260 return (fs_tab[n]->fused); 1261 } 1262 1263 /* 1264 * Sets the number of blocks being used on the indicated filesystem. 1265 * 1266 * Note: Upon entry, a valid fsys() is required. 1267 */ 1268 void 1269 set_blk_used_n(short n, fsblkcnt_t value) 1270 { 1271 fs_tab[n]->bused = value; 1272 } 1273 1274 /* Get the filesystem block size. */ 1275 fsblkcnt_t 1276 get_blk_size_n(short n) 1277 { 1278 return (fs_tab[n]->bsize); 1279 } 1280 1281 /* Get the filesystem fragment size. */ 1282 fsblkcnt_t 1283 get_frag_size_n(short n) 1284 { 1285 return (fs_tab[n]->bsize); 1286 } 1287 1288 /* 1289 * This returns the name of the indicated filesystem. 1290 */ 1291 char * 1292 get_fs_name_n(short n) 1293 { 1294 if (fs_tab_used == 0) { 1295 return (NULL); 1296 } else if (n >= fs_tab_used) { 1297 return (NULL); 1298 } else { 1299 return (fs_tab[n]->name); 1300 } 1301 } 1302 1303 /* 1304 * This returns the remote name of the indicated filesystem. 1305 * 1306 * Note: Upon entry, a valid fsys() is required. 1307 */ 1308 char * 1309 get_source_name_n(short n) 1310 { 1311 return (fs_tab[n]->remote_name); 1312 } 1313 1314 /* 1315 * This function returns the srvr_map status based upon the path. 1316 */ 1317 int 1318 use_srvr_map(char *path, short *fsys_value) 1319 { 1320 if (*fsys_value == BADFSYS) 1321 *fsys_value = fsys(path); 1322 1323 return (use_srvr_map_n(*fsys_value)); 1324 } 1325 1326 /* 1327 * This function returns the mount status based upon the path. 1328 */ 1329 int 1330 is_mounted(char *path, short *fsys_value) 1331 { 1332 if (*fsys_value == BADFSYS) 1333 *fsys_value = fsys(path); 1334 1335 return (is_mounted_n(*fsys_value)); 1336 } 1337 1338 /* 1339 * is_fs_writeable - given a cfent entry, return 1 1340 * if it's writeable, 0 if read-only. 1341 * 1342 * Note: Upon exit, a valid fsys() is guaranteed. This is 1343 * an interface requirement. 1344 */ 1345 int 1346 is_fs_writeable(char *path, short *fsys_value) 1347 { 1348 if (*fsys_value == BADFSYS) 1349 *fsys_value = fsys(path); 1350 1351 return (is_fs_writeable_n(*fsys_value)); 1352 } 1353 1354 /* 1355 * is_remote_fs - given a cfent entry, return 1 1356 * if it's a remote filesystem, 0 if local. 1357 * 1358 * Also Note: Upon exit, a valid fsys() is guaranteed. This is 1359 * an interface requirement. 1360 */ 1361 int 1362 is_remote_fs(char *path, short *fsys_value) 1363 { 1364 if (*fsys_value == BADFSYS) 1365 *fsys_value = fsys(path); 1366 1367 return (is_remote_fs_n(*fsys_value)); 1368 } 1369 1370 /* 1371 * This function returns the served status of the filesystem. Served means a 1372 * client is getting this file from a server and it is not writeable by the 1373 * client. It has nothing to do with whether or not this particular operation 1374 * (eg: pkgadd or pkgrm) will be writing to it. 1375 */ 1376 int 1377 is_served(char *path, short *fsys_value) 1378 { 1379 if (*fsys_value == BADFSYS) 1380 *fsys_value = fsys(path); 1381 1382 return (is_served_n(*fsys_value)); 1383 } 1384 1385 /* 1386 * get_remote_path - given a filesystem table index, return the 1387 * path of the filesystem on the remote system. Otherwise, 1388 * return NULL if it's a local filesystem. 1389 */ 1390 char * 1391 get_remote_path(short n) 1392 { 1393 char *p; 1394 1395 if (!is_remote_fs_n(n)) 1396 return (NULL); /* local */ 1397 p = strchr(fs_tab[n]->remote_name, ':'); 1398 if (!p) 1399 p = fs_tab[n]->remote_name; /* Loopback */ 1400 else 1401 p++; /* remote */ 1402 return (p); 1403 } 1404 1405 /* 1406 * get_mount_point - given a filesystem table index, return the 1407 * path of the mount point. Otherwise, 1408 * return NULL if it's a local filesystem. 1409 */ 1410 char * 1411 get_mount_point(short n) 1412 { 1413 if (!is_remote_fs_n(n)) 1414 return (NULL); /* local */ 1415 return (fs_tab[n]->name); 1416 } 1417 1418 struct fstable * 1419 get_fs_entry(short n) 1420 { 1421 if (fs_tab_used == 0) { 1422 return (NULL); 1423 } else if (n >= fs_tab_used) { 1424 return (NULL); 1425 } else { 1426 return (fs_tab[n]); 1427 } 1428 } 1429