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(uint32_t 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 < 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, uint32_t 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 < 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 } 991 (void) endmntent(pp); 992 } /* end of if(access()) */ 993 } /* end of if(install_root) */ 994 995 /* This next one may look stupid, but it can really happen. */ 996 if (fs_tab_used <= 0) { 997 progerr(ERR_MNT_NOMOUNTS); 998 return (1); 999 } 1000 1001 /* 1002 * Now that we have the complete list of mounted (or virtually 1003 * mounted) filesystems, we sort the mountpoints in reverse order 1004 * based on the length of the 'mount point' name. 1005 */ 1006 qsort(fs_tab, fs_tab_used, sizeof (struct fstable *), fs_tab_ent_comp); 1007 if (strcmp(fs_tab[fs_tab_used-1]->name, rn) != 0) { 1008 progerr(ERR_MNT_NOROOT, fs_tab[fs_tab_used-1]->name, rn, errno, 1009 strerror(errno)); 1010 return (1); 1011 } else { 1012 return (0); 1013 } 1014 } 1015 1016 /* 1017 * This function supports dryrun mode by allowing the filesystem table to be 1018 * directly loaded from the continuation file. 1019 */ 1020 int 1021 load_fsentry(struct fstable *fs_entry, char *name, char *fstype, 1022 char *remote_name) 1023 { 1024 struct fstable *nfte; 1025 1026 if ((nfte = fs_tab_init(name, fstype)) == NULL) 1027 return (1); 1028 1029 /* Grab the name and fstype from the new structure. */ 1030 fs_entry->name = nfte->name; 1031 fs_entry->fstype = nfte->fstype; 1032 1033 /* Copy the basic structure into place. */ 1034 (void) memcpy(nfte, fs_entry, sizeof (struct fstable)); 1035 1036 /* 1037 * Allocate space for the 'special' name. 1038 */ 1039 if ((nfte->remote_name = malloc(strlen(remote_name)+1)) == NULL) { 1040 progerr(ERR_MALLOC, "remote_name", errno, strerror(errno)); 1041 return (1); 1042 } 1043 1044 (void) strcpy(nfte->remote_name, remote_name); 1045 1046 return (0); 1047 } 1048 1049 /* 1050 * Given a path, return the table index of the filesystem the file apparently 1051 * resides on. This doesn't put any time into resolving filesystems that 1052 * refer to other filesystems. It just returns the entry containing this 1053 * path. 1054 */ 1055 uint32_t 1056 fsys(char *path) 1057 { 1058 register int i; 1059 char real_path[PATH_MAX]; 1060 char path_copy[PATH_MAX]; 1061 char *path2use; 1062 char *cp; 1063 int pathlen; 1064 boolean_t found = B_FALSE; 1065 1066 /* 1067 * The loop below represents our best effort to identify real path of 1068 * a file, which doesn't need to exist. realpath() returns error for 1069 * nonexistent path, therefore we need to cut off trailing components 1070 * of path until we get path which exists and can be resolved by 1071 * realpath(). Lookup of "/dir/symlink/nonexistent-file" would fail 1072 * to resolve symlink without this. 1073 */ 1074 (void) strlcpy(path_copy, path, PATH_MAX); 1075 for (cp = dirname(path_copy); strlen(cp) > 1; cp = dirname(cp)) { 1076 if (realpath(cp, real_path) != NULL) { 1077 found = B_TRUE; 1078 break; 1079 } else if (errno != ENOENT) 1080 break; 1081 } 1082 if (found) 1083 path2use = real_path; 1084 else 1085 /* fall back to original path in case of unexpected failure */ 1086 path2use = path; 1087 1088 pathlen = strlen(path2use); 1089 1090 /* 1091 * The following algorithm scans the list of attached file systems 1092 * for the one containing path. At this point the file names in 1093 * fs_tab[] are sorted by decreasing length to facilitate the scan. 1094 * The first for() scans past all the file system names too short to 1095 * contain path. The second for() does the actual string comparison. 1096 * It tests first to assure that the comparison is against a complete 1097 * token by assuring that the end of the filesystem name aligns with 1098 * the end of a token in path2use (ie: '/' or NULL) then it does a 1099 * string compare. -- JST 1100 */ 1101 1102 if (fs_tab_used == 0) { 1103 return (-1); 1104 } 1105 1106 for (i = 0; i < fs_tab_used; i++) 1107 if (fs_tab[i] == NULL) 1108 continue; 1109 else if (fs_tab[i]->namlen <= pathlen) 1110 break; 1111 for (; i < fs_tab_used; i++) { 1112 int fs_namelen; 1113 char term_char; 1114 1115 if (fs_tab[i] == NULL) 1116 continue; 1117 1118 fs_namelen = fs_tab[i]->namlen; 1119 term_char = path2use[fs_namelen]; 1120 1121 /* 1122 * If we're putting the file "/a/kernel" into the filesystem 1123 * "/a", then fs_namelen == 2 and term_char == '/'. If, we're 1124 * putting "/etc/termcap" into "/", fs_namelen == 1 and 1125 * term_char (unfortunately) == 'e'. In the case of 1126 * fs_namelen == 1, we check to make sure the filesystem is 1127 * "/" and if it is, we have a guaranteed fit, otherwise we 1128 * do the string compare. -- JST 1129 */ 1130 if ((fs_namelen == 1 && *(fs_tab[i]->name) == '/') || 1131 ((term_char == '/' || term_char == NULL) && 1132 strncmp(fs_tab[i]->name, path2use, fs_namelen) == 0)) { 1133 return (i); 1134 } 1135 } 1136 1137 /* 1138 * It only gets here if the root filesystem is fundamentally corrupt. 1139 * (This can happen!) 1140 */ 1141 progerr(ERR_FSYS_FELLOUT, path2use); 1142 1143 return (-1); 1144 } 1145 1146 /* 1147 * This function returns the entry in the fs_tab[] corresponding to the 1148 * actual filesystem of record. It won't return a loopback filesystem entry, 1149 * it will return the filesystem that the loopback filesystem is mounted 1150 * over. 1151 */ 1152 uint32_t 1153 resolved_fsys(char *path) 1154 { 1155 int i = -1; 1156 char path2use[PATH_MAX]; 1157 1158 (void) strcpy(path2use, path); 1159 1160 /* If this isn't a "real" filesystem, resolve the map. */ 1161 do { 1162 (void) strcpy(path2use, server_map(path2use, i)); 1163 i = fsys(path2use); 1164 } while (fs_tab[i]->srvr_map); 1165 1166 return (i); 1167 } 1168 1169 /* 1170 * This function returns the srvr_map status based upon the fs_tab entry 1171 * number. This tells us if the server path constructed from the package 1172 * install root is really the target filesystem. 1173 */ 1174 int 1175 use_srvr_map_n(uint32_t n) 1176 { 1177 return ((int)fs_tab[n]->srvr_map); 1178 } 1179 1180 /* 1181 * This function returns the mount status based upon the fs_tab entry 1182 * number. This tells us if there is any hope of gaining access 1183 * to this file system. 1184 */ 1185 int 1186 is_mounted_n(uint32_t n) 1187 { 1188 return ((int)fs_tab[n]->mounted); 1189 } 1190 1191 /* 1192 * is_fs_writeable_n - given an fstab index, return 1 1193 * if it's writeable, 0 if read-only. 1194 */ 1195 int 1196 is_fs_writeable_n(uint32_t n) 1197 { 1198 /* 1199 * If the write access permissions haven't been confirmed, do that 1200 * now. Note that the only reason we need to do the special check is 1201 * in the case of an NFS mount (remote) because we can't determine if 1202 * root has access in any other way. 1203 */ 1204 if (fs_tab[n]->remote && fs_tab[n]->mounted && 1205 !fs_tab[n]->write_tested) { 1206 if (fs_tab[n]->writeable && !really_write(fs_tab[n]->name)) 1207 fs_tab[n]->writeable = 0; /* not really */ 1208 1209 fs_tab[n]->write_tested = 1; /* confirmed */ 1210 } 1211 1212 return ((int)fs_tab[n]->writeable); 1213 } 1214 1215 /* 1216 * is_remote_fs_n - given an fstab index, return 1 1217 * if it's a remote filesystem, 0 if local. 1218 * 1219 * Note: Upon entry, a valid fsys() is required. 1220 */ 1221 int 1222 is_remote_fs_n(uint32_t n) 1223 { 1224 return ((int)fs_tab[n]->remote); 1225 } 1226 1227 /* index-driven is_served() */ 1228 int 1229 is_served_n(uint32_t n) 1230 { 1231 return ((int)fs_tab[n]->served); 1232 } 1233 1234 /* 1235 * This returns the number of blocks available on the indicated filesystem. 1236 * 1237 * Note: Upon entry, a valid fsys() is required. 1238 */ 1239 fsblkcnt_t 1240 get_blk_free_n(uint32_t n) 1241 { 1242 return (fs_tab[n]->bfree); 1243 } 1244 1245 /* 1246 * This returns the number of blocks being used on the indicated filesystem. 1247 * 1248 * Note: Upon entry, a valid fsys() is required. 1249 */ 1250 fsblkcnt_t 1251 get_blk_used_n(uint32_t n) 1252 { 1253 return (fs_tab[n]->bused); 1254 } 1255 1256 /* 1257 * This returns the number of inodes available on the indicated filesystem. 1258 * 1259 * Note: Upon entry, a valid fsys() is required. 1260 */ 1261 fsblkcnt_t 1262 get_inode_free_n(uint32_t n) 1263 { 1264 return (fs_tab[n]->ffree); 1265 } 1266 1267 /* 1268 * This returns the number of inodes being used on the indicated filesystem. 1269 * 1270 * Note: Upon entry, a valid fsys() is required. 1271 */ 1272 fsblkcnt_t 1273 get_inode_used_n(uint32_t n) 1274 { 1275 return (fs_tab[n]->fused); 1276 } 1277 1278 /* 1279 * Sets the number of blocks being used on the indicated filesystem. 1280 * 1281 * Note: Upon entry, a valid fsys() is required. 1282 */ 1283 void 1284 set_blk_used_n(uint32_t n, fsblkcnt_t value) 1285 { 1286 fs_tab[n]->bused = value; 1287 } 1288 1289 /* Get the filesystem block size. */ 1290 fsblkcnt_t 1291 get_blk_size_n(uint32_t n) 1292 { 1293 return (fs_tab[n]->bsize); 1294 } 1295 1296 /* Get the filesystem fragment size. */ 1297 fsblkcnt_t 1298 get_frag_size_n(uint32_t n) 1299 { 1300 return (fs_tab[n]->bsize); 1301 } 1302 1303 /* 1304 * This returns the name of the indicated filesystem. 1305 */ 1306 char * 1307 get_fs_name_n(uint32_t n) 1308 { 1309 if (fs_tab_used == 0) { 1310 return (NULL); 1311 } else if (n >= fs_tab_used) { 1312 return (NULL); 1313 } else { 1314 return (fs_tab[n]->name); 1315 } 1316 } 1317 1318 /* 1319 * This returns the remote name of the indicated filesystem. 1320 * 1321 * Note: Upon entry, a valid fsys() is required. 1322 */ 1323 char * 1324 get_source_name_n(uint32_t n) 1325 { 1326 return (fs_tab[n]->remote_name); 1327 } 1328 1329 /* 1330 * This function returns the srvr_map status based upon the path. 1331 */ 1332 int 1333 use_srvr_map(char *path, uint32_t *fsys_value) 1334 { 1335 if (*fsys_value == BADFSYS) 1336 *fsys_value = fsys(path); 1337 1338 return (use_srvr_map_n(*fsys_value)); 1339 } 1340 1341 /* 1342 * This function returns the mount status based upon the path. 1343 */ 1344 int 1345 is_mounted(char *path, uint32_t *fsys_value) 1346 { 1347 if (*fsys_value == BADFSYS) 1348 *fsys_value = fsys(path); 1349 1350 return (is_mounted_n(*fsys_value)); 1351 } 1352 1353 /* 1354 * is_fs_writeable - given a cfent entry, return 1 1355 * if it's writeable, 0 if read-only. 1356 * 1357 * Note: Upon exit, a valid fsys() is guaranteed. This is 1358 * an interface requirement. 1359 */ 1360 int 1361 is_fs_writeable(char *path, uint32_t *fsys_value) 1362 { 1363 if (*fsys_value == BADFSYS) 1364 *fsys_value = fsys(path); 1365 1366 return (is_fs_writeable_n(*fsys_value)); 1367 } 1368 1369 /* 1370 * is_remote_fs - given a cfent entry, return 1 1371 * if it's a remote filesystem, 0 if local. 1372 * 1373 * Also Note: Upon exit, a valid fsys() is guaranteed. This is 1374 * an interface requirement. 1375 */ 1376 int 1377 is_remote_fs(char *path, uint32_t *fsys_value) 1378 { 1379 if (*fsys_value == BADFSYS) 1380 *fsys_value = fsys(path); 1381 1382 return (is_remote_fs_n(*fsys_value)); 1383 } 1384 1385 /* 1386 * This function returns the served status of the filesystem. Served means a 1387 * client is getting this file from a server and it is not writeable by the 1388 * client. It has nothing to do with whether or not this particular operation 1389 * (eg: pkgadd or pkgrm) will be writing to it. 1390 */ 1391 int 1392 is_served(char *path, uint32_t *fsys_value) 1393 { 1394 if (*fsys_value == BADFSYS) 1395 *fsys_value = fsys(path); 1396 1397 return (is_served_n(*fsys_value)); 1398 } 1399 1400 /* 1401 * get_remote_path - given a filesystem table index, return the 1402 * path of the filesystem on the remote system. Otherwise, 1403 * return NULL if it's a local filesystem. 1404 */ 1405 char * 1406 get_remote_path(uint32_t n) 1407 { 1408 char *p; 1409 1410 if (!is_remote_fs_n(n)) 1411 return (NULL); /* local */ 1412 p = strchr(fs_tab[n]->remote_name, ':'); 1413 if (!p) 1414 p = fs_tab[n]->remote_name; /* Loopback */ 1415 else 1416 p++; /* remote */ 1417 return (p); 1418 } 1419 1420 /* 1421 * get_mount_point - given a filesystem table index, return the 1422 * path of the mount point. Otherwise, 1423 * return NULL if it's a local filesystem. 1424 */ 1425 char * 1426 get_mount_point(uint32_t n) 1427 { 1428 if (!is_remote_fs_n(n)) 1429 return (NULL); /* local */ 1430 return (fs_tab[n]->name); 1431 } 1432 1433 struct fstable * 1434 get_fs_entry(uint32_t n) 1435 { 1436 if (fs_tab_used == 0) { 1437 return (NULL); 1438 } else if (n >= fs_tab_used) { 1439 return (NULL); 1440 } else { 1441 return (fs_tab[n]); 1442 } 1443 }