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 }