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