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