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)) == NULL)
 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()
 319 {
 320         int     errcode;
 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()
 439 {
 440         int     errcode;
 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 == NULL) &&
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 }