1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * autod_mount.c 24*0Sstevel@tonic-gate * 25*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 26*0Sstevel@tonic-gate * Use is subject to license terms. 27*0Sstevel@tonic-gate */ 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 30*0Sstevel@tonic-gate 31*0Sstevel@tonic-gate #include <stdio.h> 32*0Sstevel@tonic-gate #include <ctype.h> 33*0Sstevel@tonic-gate #include <string.h> 34*0Sstevel@tonic-gate #include <syslog.h> 35*0Sstevel@tonic-gate #include <sys/types.h> 36*0Sstevel@tonic-gate #include <sys/stat.h> 37*0Sstevel@tonic-gate #include <sys/param.h> 38*0Sstevel@tonic-gate #include <errno.h> 39*0Sstevel@tonic-gate #include <pwd.h> 40*0Sstevel@tonic-gate #include <netinet/in.h> 41*0Sstevel@tonic-gate #include <netdb.h> 42*0Sstevel@tonic-gate #include <sys/tiuser.h> 43*0Sstevel@tonic-gate #include <locale.h> 44*0Sstevel@tonic-gate #include <stdlib.h> 45*0Sstevel@tonic-gate #include <unistd.h> 46*0Sstevel@tonic-gate #include <sys/mntent.h> 47*0Sstevel@tonic-gate #include <sys/mnttab.h> 48*0Sstevel@tonic-gate #include <sys/wait.h> 49*0Sstevel@tonic-gate #include <sys/mount.h> 50*0Sstevel@tonic-gate #include <sys/fs/autofs.h> 51*0Sstevel@tonic-gate #include <nfs/nfs.h> 52*0Sstevel@tonic-gate #include <thread.h> 53*0Sstevel@tonic-gate #include <limits.h> 54*0Sstevel@tonic-gate #include <assert.h> 55*0Sstevel@tonic-gate #include <fcntl.h> 56*0Sstevel@tonic-gate 57*0Sstevel@tonic-gate #include "automount.h" 58*0Sstevel@tonic-gate #include "replica.h" 59*0Sstevel@tonic-gate 60*0Sstevel@tonic-gate static int unmount_mntpnt(struct mnttab *); 61*0Sstevel@tonic-gate static int fork_exec(char *, char *, char **, int); 62*0Sstevel@tonic-gate static void remove_browse_options(char *); 63*0Sstevel@tonic-gate static int inherit_options(char *, char **); 64*0Sstevel@tonic-gate 65*0Sstevel@tonic-gate int 66*0Sstevel@tonic-gate do_mount1(mapname, key, subdir, mapopts, path, isdirect, alpp, cred) 67*0Sstevel@tonic-gate char *mapname; 68*0Sstevel@tonic-gate char *key; 69*0Sstevel@tonic-gate char *subdir; 70*0Sstevel@tonic-gate char *mapopts; 71*0Sstevel@tonic-gate char *path; 72*0Sstevel@tonic-gate uint_t isdirect; 73*0Sstevel@tonic-gate struct action_list **alpp; 74*0Sstevel@tonic-gate struct authunix_parms *cred; 75*0Sstevel@tonic-gate { 76*0Sstevel@tonic-gate struct mapline ml; 77*0Sstevel@tonic-gate struct mapent *me, *mapents = NULL; 78*0Sstevel@tonic-gate char mntpnt[MAXPATHLEN]; 79*0Sstevel@tonic-gate char spec_mntpnt[MAXPATHLEN]; 80*0Sstevel@tonic-gate int err = 0; 81*0Sstevel@tonic-gate char *private; /* fs specific data. eg prevhost in case of nfs */ 82*0Sstevel@tonic-gate int mount_ok = 0; 83*0Sstevel@tonic-gate ssize_t len; 84*0Sstevel@tonic-gate action_list *alp, *prev, *tmp; 85*0Sstevel@tonic-gate char root[MAXPATHLEN]; 86*0Sstevel@tonic-gate int overlay = 1; 87*0Sstevel@tonic-gate char next_subdir[MAXPATHLEN]; 88*0Sstevel@tonic-gate bool_t mount_access = TRUE; 89*0Sstevel@tonic-gate bool_t iswildcard; 90*0Sstevel@tonic-gate bool_t isrestricted = hasrestrictopt(mapopts); 91*0Sstevel@tonic-gate char *stack[STACKSIZ]; 92*0Sstevel@tonic-gate char **stkptr = stack; 93*0Sstevel@tonic-gate 94*0Sstevel@tonic-gate retry: 95*0Sstevel@tonic-gate iswildcard = FALSE; 96*0Sstevel@tonic-gate 97*0Sstevel@tonic-gate /* initialize the stack of open files for this thread */ 98*0Sstevel@tonic-gate stack_op(INIT, NULL, stack, &stkptr); 99*0Sstevel@tonic-gate 100*0Sstevel@tonic-gate err = getmapent(key, mapname, &ml, stack, &stkptr, &iswildcard, 101*0Sstevel@tonic-gate isrestricted); 102*0Sstevel@tonic-gate if (err == 0) { 103*0Sstevel@tonic-gate mapents = parse_entry(key, mapname, mapopts, &ml, 104*0Sstevel@tonic-gate subdir, isdirect, mount_access); 105*0Sstevel@tonic-gate } 106*0Sstevel@tonic-gate 107*0Sstevel@tonic-gate if (trace > 1) { 108*0Sstevel@tonic-gate struct mapfs *mfs; 109*0Sstevel@tonic-gate trace_prt(1, " do_mount1:\n"); 110*0Sstevel@tonic-gate for (me = mapents; me; me = me->map_next) { 111*0Sstevel@tonic-gate trace_prt(1, " (%s,%s)\t%s%s%s\n", 112*0Sstevel@tonic-gate me->map_fstype ? me->map_fstype : "", 113*0Sstevel@tonic-gate me->map_mounter ? me->map_mounter : "", 114*0Sstevel@tonic-gate path ? path : "", 115*0Sstevel@tonic-gate me->map_root ? me->map_root : "", 116*0Sstevel@tonic-gate me->map_mntpnt ? me->map_mntpnt : ""); 117*0Sstevel@tonic-gate trace_prt(0, "\t\t-%s\n", 118*0Sstevel@tonic-gate me->map_mntopts ? me->map_mntopts : ""); 119*0Sstevel@tonic-gate 120*0Sstevel@tonic-gate for (mfs = me->map_fs; mfs; mfs = mfs->mfs_next) 121*0Sstevel@tonic-gate trace_prt(0, "\t\t%s:%s\tpenalty=%d\n", 122*0Sstevel@tonic-gate mfs->mfs_host ? mfs->mfs_host: "", 123*0Sstevel@tonic-gate mfs->mfs_dir ? mfs->mfs_dir : "", 124*0Sstevel@tonic-gate mfs->mfs_penalty); 125*0Sstevel@tonic-gate } 126*0Sstevel@tonic-gate } 127*0Sstevel@tonic-gate 128*0Sstevel@tonic-gate *alpp = NULL; 129*0Sstevel@tonic-gate 130*0Sstevel@tonic-gate /* 131*0Sstevel@tonic-gate * Each mapent in the list describes a mount to be done. 132*0Sstevel@tonic-gate * Normally there's just a single entry, though in the 133*0Sstevel@tonic-gate * case of /net mounts there may be many entries, that 134*0Sstevel@tonic-gate * must be mounted as a hierarchy. For each mount the 135*0Sstevel@tonic-gate * automountd must make sure the required mountpoint 136*0Sstevel@tonic-gate * exists and invoke the appropriate mount command for 137*0Sstevel@tonic-gate * the fstype. 138*0Sstevel@tonic-gate */ 139*0Sstevel@tonic-gate private = ""; 140*0Sstevel@tonic-gate for (me = mapents; me && !err; me = me->map_next) { 141*0Sstevel@tonic-gate len = snprintf(mntpnt, sizeof (mntpnt), "%s%s%s", path, 142*0Sstevel@tonic-gate mapents->map_root, me->map_mntpnt); 143*0Sstevel@tonic-gate 144*0Sstevel@tonic-gate if (len >= sizeof (mntpnt)) { 145*0Sstevel@tonic-gate free_mapent(mapents); 146*0Sstevel@tonic-gate return (ENAMETOOLONG); 147*0Sstevel@tonic-gate } 148*0Sstevel@tonic-gate /* 149*0Sstevel@tonic-gate * remove trailing /'s from mountpoint to avoid problems 150*0Sstevel@tonic-gate * stating a directory with two or more trailing slashes. 151*0Sstevel@tonic-gate * This will let us mount directories from machines 152*0Sstevel@tonic-gate * which export with two or more slashes (apollo for instance). 153*0Sstevel@tonic-gate */ 154*0Sstevel@tonic-gate len -= 1; 155*0Sstevel@tonic-gate while (mntpnt[len] == '/') 156*0Sstevel@tonic-gate mntpnt[len--] = '\0'; 157*0Sstevel@tonic-gate 158*0Sstevel@tonic-gate (void) strcpy(spec_mntpnt, mntpnt); 159*0Sstevel@tonic-gate 160*0Sstevel@tonic-gate if (isrestricted && 161*0Sstevel@tonic-gate inherit_options(mapopts, &me->map_mntopts) != 0) { 162*0Sstevel@tonic-gate syslog(LOG_ERR, "malloc of options failed"); 163*0Sstevel@tonic-gate free_mapent(mapents); 164*0Sstevel@tonic-gate return (EAGAIN); 165*0Sstevel@tonic-gate } 166*0Sstevel@tonic-gate 167*0Sstevel@tonic-gate if (strcmp(me->map_fstype, MNTTYPE_NFS) == 0) { 168*0Sstevel@tonic-gate remove_browse_options(me->map_mntopts); 169*0Sstevel@tonic-gate err = 170*0Sstevel@tonic-gate mount_nfs(me, spec_mntpnt, private, overlay, cred); 171*0Sstevel@tonic-gate /* 172*0Sstevel@tonic-gate * We must retry if we don't have access to the 173*0Sstevel@tonic-gate * root file system and there are other 174*0Sstevel@tonic-gate * following mapents. The reason we can't 175*0Sstevel@tonic-gate * continue because the rest of the mapent list 176*0Sstevel@tonic-gate * depends on whether mount_access is TRUE or FALSE. 177*0Sstevel@tonic-gate */ 178*0Sstevel@tonic-gate if (err == NFSERR_ACCES && me->map_next != NULL) { 179*0Sstevel@tonic-gate /* 180*0Sstevel@tonic-gate * don't expect mount_access to be 181*0Sstevel@tonic-gate * FALSE here, but we do a check 182*0Sstevel@tonic-gate * anyway. 183*0Sstevel@tonic-gate */ 184*0Sstevel@tonic-gate if (mount_access == TRUE) { 185*0Sstevel@tonic-gate mount_access = FALSE; 186*0Sstevel@tonic-gate err = 0; 187*0Sstevel@tonic-gate free_mapent(mapents); 188*0Sstevel@tonic-gate goto retry; 189*0Sstevel@tonic-gate } 190*0Sstevel@tonic-gate } 191*0Sstevel@tonic-gate mount_ok = !err; 192*0Sstevel@tonic-gate } else if (strcmp(me->map_fstype, MNTTYPE_AUTOFS) == 0) { 193*0Sstevel@tonic-gate if (isdirect) { 194*0Sstevel@tonic-gate len = strlcpy(root, path, sizeof (root)); 195*0Sstevel@tonic-gate } else { 196*0Sstevel@tonic-gate len = snprintf(root, sizeof (root), "%s/%s", 197*0Sstevel@tonic-gate path, key); 198*0Sstevel@tonic-gate } 199*0Sstevel@tonic-gate if (len >= sizeof (root)) { 200*0Sstevel@tonic-gate free_mapent(mapents); 201*0Sstevel@tonic-gate return (ENAMETOOLONG); 202*0Sstevel@tonic-gate } 203*0Sstevel@tonic-gate 204*0Sstevel@tonic-gate alp = (action_list *)malloc(sizeof (action_list)); 205*0Sstevel@tonic-gate if (alp == NULL) { 206*0Sstevel@tonic-gate syslog(LOG_ERR, "malloc of alp failed"); 207*0Sstevel@tonic-gate continue; 208*0Sstevel@tonic-gate } 209*0Sstevel@tonic-gate memset(alp, 0, sizeof (action_list)); 210*0Sstevel@tonic-gate 211*0Sstevel@tonic-gate /* 212*0Sstevel@tonic-gate * get the next subidr, but only if its a modified 213*0Sstevel@tonic-gate * or faked autofs mount 214*0Sstevel@tonic-gate */ 215*0Sstevel@tonic-gate if (me->map_modified || me->map_faked) { 216*0Sstevel@tonic-gate len = snprintf(next_subdir, 217*0Sstevel@tonic-gate sizeof (next_subdir), "%s%s", subdir, 218*0Sstevel@tonic-gate me->map_mntpnt); 219*0Sstevel@tonic-gate } else { 220*0Sstevel@tonic-gate next_subdir[0] = '\0'; 221*0Sstevel@tonic-gate len = 0; 222*0Sstevel@tonic-gate } 223*0Sstevel@tonic-gate 224*0Sstevel@tonic-gate if (trace > 2) 225*0Sstevel@tonic-gate trace_prt(1, " root=%s\t next_subdir=%s\n", 226*0Sstevel@tonic-gate root, next_subdir); 227*0Sstevel@tonic-gate if (len < sizeof (next_subdir)) { 228*0Sstevel@tonic-gate err = mount_autofs(me, spec_mntpnt, alp, 229*0Sstevel@tonic-gate root, next_subdir, key); 230*0Sstevel@tonic-gate } else { 231*0Sstevel@tonic-gate err = ENAMETOOLONG; 232*0Sstevel@tonic-gate } 233*0Sstevel@tonic-gate if (err == 0) { 234*0Sstevel@tonic-gate /* 235*0Sstevel@tonic-gate * append to action list 236*0Sstevel@tonic-gate */ 237*0Sstevel@tonic-gate mount_ok++; 238*0Sstevel@tonic-gate if (*alpp == NULL) 239*0Sstevel@tonic-gate *alpp = alp; 240*0Sstevel@tonic-gate else { 241*0Sstevel@tonic-gate for (tmp = *alpp; tmp != NULL; 242*0Sstevel@tonic-gate tmp = tmp->next) 243*0Sstevel@tonic-gate prev = tmp; 244*0Sstevel@tonic-gate prev->next = alp; 245*0Sstevel@tonic-gate } 246*0Sstevel@tonic-gate } else { 247*0Sstevel@tonic-gate free(alp); 248*0Sstevel@tonic-gate mount_ok = 0; 249*0Sstevel@tonic-gate } 250*0Sstevel@tonic-gate } else if (strcmp(me->map_fstype, MNTTYPE_LOFS) == 0) { 251*0Sstevel@tonic-gate remove_browse_options(me->map_mntopts); 252*0Sstevel@tonic-gate err = loopbackmount(me->map_fs->mfs_dir, spec_mntpnt, 253*0Sstevel@tonic-gate me->map_mntopts, overlay); 254*0Sstevel@tonic-gate mount_ok = !err; 255*0Sstevel@tonic-gate } else { 256*0Sstevel@tonic-gate remove_browse_options(me->map_mntopts); 257*0Sstevel@tonic-gate err = mount_generic(me->map_fs->mfs_dir, 258*0Sstevel@tonic-gate me->map_fstype, me->map_mntopts, 259*0Sstevel@tonic-gate spec_mntpnt, overlay); 260*0Sstevel@tonic-gate mount_ok = !err; 261*0Sstevel@tonic-gate } 262*0Sstevel@tonic-gate } 263*0Sstevel@tonic-gate if (mapents) 264*0Sstevel@tonic-gate free_mapent(mapents); 265*0Sstevel@tonic-gate 266*0Sstevel@tonic-gate /* 267*0Sstevel@tonic-gate * If an error occurred, 268*0Sstevel@tonic-gate * the filesystem doesn't exist, or could not be 269*0Sstevel@tonic-gate * mounted. Return EACCES to autofs indicating that 270*0Sstevel@tonic-gate * the mountpoint can not be accessed if this is not 271*0Sstevel@tonic-gate * a wildcard access. If it is a wildcard access we 272*0Sstevel@tonic-gate * return ENOENT since the lookup that triggered 273*0Sstevel@tonic-gate * this mount request will fail and the entry will not 274*0Sstevel@tonic-gate * be available. 275*0Sstevel@tonic-gate */ 276*0Sstevel@tonic-gate if (mount_ok) { 277*0Sstevel@tonic-gate /* 278*0Sstevel@tonic-gate * No error occurred, return 0 to indicate success. 279*0Sstevel@tonic-gate */ 280*0Sstevel@tonic-gate err = 0; 281*0Sstevel@tonic-gate } else { 282*0Sstevel@tonic-gate /* 283*0Sstevel@tonic-gate * The filesystem does not exist or could not be mounted. 284*0Sstevel@tonic-gate * Return ENOENT if the lookup was triggered by a wildcard 285*0Sstevel@tonic-gate * access. Wildcard entries only exist if they can be 286*0Sstevel@tonic-gate * mounted. They can not be listed otherwise (through 287*0Sstevel@tonic-gate * a readdir(2)). 288*0Sstevel@tonic-gate * Return EACCES if the lookup was not triggered by a 289*0Sstevel@tonic-gate * wildcard access. Map entries that are explicitly defined 290*0Sstevel@tonic-gate * in maps are visible via readdir(2), therefore we return 291*0Sstevel@tonic-gate * EACCES to indicate that the entry exists, but the directory 292*0Sstevel@tonic-gate * can not be opened. This is the same behavior of a Unix 293*0Sstevel@tonic-gate * directory that exists, but has its execute bit turned off. 294*0Sstevel@tonic-gate * The directory is there, but the user does not have access 295*0Sstevel@tonic-gate * to it. 296*0Sstevel@tonic-gate */ 297*0Sstevel@tonic-gate if (iswildcard) 298*0Sstevel@tonic-gate err = ENOENT; 299*0Sstevel@tonic-gate else 300*0Sstevel@tonic-gate err = EACCES; 301*0Sstevel@tonic-gate } 302*0Sstevel@tonic-gate return (err); 303*0Sstevel@tonic-gate } 304*0Sstevel@tonic-gate 305*0Sstevel@tonic-gate #define ARGV_MAX 16 306*0Sstevel@tonic-gate #define VFS_PATH "/usr/lib/fs" 307*0Sstevel@tonic-gate 308*0Sstevel@tonic-gate int 309*0Sstevel@tonic-gate mount_generic(special, fstype, opts, mntpnt, overlay) 310*0Sstevel@tonic-gate char *special, *fstype, *opts, *mntpnt; 311*0Sstevel@tonic-gate int overlay; 312*0Sstevel@tonic-gate { 313*0Sstevel@tonic-gate struct mnttab m; 314*0Sstevel@tonic-gate struct stat stbuf; 315*0Sstevel@tonic-gate int i, res; 316*0Sstevel@tonic-gate char *newargv[ARGV_MAX]; 317*0Sstevel@tonic-gate 318*0Sstevel@tonic-gate if (trace > 1) { 319*0Sstevel@tonic-gate trace_prt(1, " mount: %s %s %s %s\n", 320*0Sstevel@tonic-gate special, mntpnt, fstype, opts); 321*0Sstevel@tonic-gate } 322*0Sstevel@tonic-gate 323*0Sstevel@tonic-gate if (stat(mntpnt, &stbuf) < 0) { 324*0Sstevel@tonic-gate syslog(LOG_ERR, "Couldn't stat %s: %m", mntpnt); 325*0Sstevel@tonic-gate return (ENOENT); 326*0Sstevel@tonic-gate } 327*0Sstevel@tonic-gate 328*0Sstevel@tonic-gate i = 2; 329*0Sstevel@tonic-gate 330*0Sstevel@tonic-gate if (overlay) 331*0Sstevel@tonic-gate newargv[i++] = "-O"; 332*0Sstevel@tonic-gate 333*0Sstevel@tonic-gate /* 334*0Sstevel@tonic-gate * Use "quiet" option to suppress warnings about unsupported 335*0Sstevel@tonic-gate * mount options. 336*0Sstevel@tonic-gate */ 337*0Sstevel@tonic-gate newargv[i++] = "-q"; 338*0Sstevel@tonic-gate 339*0Sstevel@tonic-gate if (opts && *opts) { 340*0Sstevel@tonic-gate m.mnt_mntopts = opts; 341*0Sstevel@tonic-gate if (hasmntopt(&m, MNTOPT_RO) != NULL) 342*0Sstevel@tonic-gate newargv[i++] = "-r"; 343*0Sstevel@tonic-gate newargv[i++] = "-o"; 344*0Sstevel@tonic-gate newargv[i++] = opts; 345*0Sstevel@tonic-gate } 346*0Sstevel@tonic-gate newargv[i++] = "--"; 347*0Sstevel@tonic-gate newargv[i++] = special; 348*0Sstevel@tonic-gate newargv[i++] = mntpnt; 349*0Sstevel@tonic-gate newargv[i] = NULL; 350*0Sstevel@tonic-gate res = fork_exec(fstype, "mount", newargv, verbose); 351*0Sstevel@tonic-gate if (res == 0 && trace > 1) { 352*0Sstevel@tonic-gate if (stat(mntpnt, &stbuf) == 0) { 353*0Sstevel@tonic-gate trace_prt(1, " mount of %s dev=%x rdev=%x OK\n", 354*0Sstevel@tonic-gate mntpnt, stbuf.st_dev, stbuf.st_rdev); 355*0Sstevel@tonic-gate } else { 356*0Sstevel@tonic-gate trace_prt(1, " failed to stat %s\n", mntpnt); 357*0Sstevel@tonic-gate } 358*0Sstevel@tonic-gate } 359*0Sstevel@tonic-gate return (res); 360*0Sstevel@tonic-gate } 361*0Sstevel@tonic-gate 362*0Sstevel@tonic-gate static int 363*0Sstevel@tonic-gate fork_exec(fstype, cmd, newargv, console) 364*0Sstevel@tonic-gate char *fstype; 365*0Sstevel@tonic-gate char *cmd; 366*0Sstevel@tonic-gate char **newargv; 367*0Sstevel@tonic-gate int console; 368*0Sstevel@tonic-gate { 369*0Sstevel@tonic-gate char path[MAXPATHLEN]; 370*0Sstevel@tonic-gate int i; 371*0Sstevel@tonic-gate int stat_loc; 372*0Sstevel@tonic-gate int fd = 0; 373*0Sstevel@tonic-gate struct stat stbuf; 374*0Sstevel@tonic-gate int res; 375*0Sstevel@tonic-gate int child_pid; 376*0Sstevel@tonic-gate 377*0Sstevel@tonic-gate /* build the full path name of the fstype dependent command */ 378*0Sstevel@tonic-gate (void) sprintf(path, "%s/%s/%s", VFS_PATH, fstype, cmd); 379*0Sstevel@tonic-gate 380*0Sstevel@tonic-gate if (stat(path, &stbuf) != 0) { 381*0Sstevel@tonic-gate res = errno; 382*0Sstevel@tonic-gate return (res); 383*0Sstevel@tonic-gate } 384*0Sstevel@tonic-gate 385*0Sstevel@tonic-gate if (trace > 1) { 386*0Sstevel@tonic-gate trace_prt(1, " fork_exec: %s ", path); 387*0Sstevel@tonic-gate for (i = 2; newargv[i]; i++) 388*0Sstevel@tonic-gate trace_prt(0, "%s ", newargv[i]); 389*0Sstevel@tonic-gate trace_prt(0, "\n"); 390*0Sstevel@tonic-gate } 391*0Sstevel@tonic-gate 392*0Sstevel@tonic-gate 393*0Sstevel@tonic-gate newargv[1] = cmd; 394*0Sstevel@tonic-gate switch ((child_pid = fork1())) { 395*0Sstevel@tonic-gate case -1: 396*0Sstevel@tonic-gate syslog(LOG_ERR, "Cannot fork: %m"); 397*0Sstevel@tonic-gate return (errno); 398*0Sstevel@tonic-gate case 0: 399*0Sstevel@tonic-gate /* 400*0Sstevel@tonic-gate * Child 401*0Sstevel@tonic-gate */ 402*0Sstevel@tonic-gate (void) setsid(); 403*0Sstevel@tonic-gate fd = open(console ? "/dev/console" : "/dev/null", O_WRONLY); 404*0Sstevel@tonic-gate if (fd != -1) { 405*0Sstevel@tonic-gate (void) dup2(fd, 1); 406*0Sstevel@tonic-gate (void) dup2(fd, 2); 407*0Sstevel@tonic-gate (void) close(fd); 408*0Sstevel@tonic-gate } 409*0Sstevel@tonic-gate 410*0Sstevel@tonic-gate (void) execv(path, &newargv[1]); 411*0Sstevel@tonic-gate if (errno == EACCES) 412*0Sstevel@tonic-gate syslog(LOG_ERR, "exec %s: %m", path); 413*0Sstevel@tonic-gate 414*0Sstevel@tonic-gate _exit(errno); 415*0Sstevel@tonic-gate default: 416*0Sstevel@tonic-gate /* 417*0Sstevel@tonic-gate * Parent 418*0Sstevel@tonic-gate */ 419*0Sstevel@tonic-gate (void) waitpid(child_pid, &stat_loc, WUNTRACED); 420*0Sstevel@tonic-gate 421*0Sstevel@tonic-gate if (WIFEXITED(stat_loc)) { 422*0Sstevel@tonic-gate if (trace > 1) { 423*0Sstevel@tonic-gate trace_prt(1, 424*0Sstevel@tonic-gate " fork_exec: returns exit status %d\n", 425*0Sstevel@tonic-gate WEXITSTATUS(stat_loc)); 426*0Sstevel@tonic-gate } 427*0Sstevel@tonic-gate 428*0Sstevel@tonic-gate return (WEXITSTATUS(stat_loc)); 429*0Sstevel@tonic-gate } else 430*0Sstevel@tonic-gate if (WIFSIGNALED(stat_loc)) { 431*0Sstevel@tonic-gate if (trace > 1) { 432*0Sstevel@tonic-gate trace_prt(1, 433*0Sstevel@tonic-gate " fork_exec: returns signal status %d\n", 434*0Sstevel@tonic-gate WTERMSIG(stat_loc)); 435*0Sstevel@tonic-gate } 436*0Sstevel@tonic-gate } else { 437*0Sstevel@tonic-gate if (trace > 1) 438*0Sstevel@tonic-gate trace_prt(1, 439*0Sstevel@tonic-gate " fork_exec: returns unknown status\n"); 440*0Sstevel@tonic-gate } 441*0Sstevel@tonic-gate 442*0Sstevel@tonic-gate return (1); 443*0Sstevel@tonic-gate } 444*0Sstevel@tonic-gate } 445*0Sstevel@tonic-gate 446*0Sstevel@tonic-gate int 447*0Sstevel@tonic-gate do_unmount1(ur) 448*0Sstevel@tonic-gate umntrequest *ur; 449*0Sstevel@tonic-gate { 450*0Sstevel@tonic-gate 451*0Sstevel@tonic-gate struct mnttab m; 452*0Sstevel@tonic-gate int res = 0; 453*0Sstevel@tonic-gate 454*0Sstevel@tonic-gate m.mnt_special = ur->mntresource; 455*0Sstevel@tonic-gate m.mnt_mountp = ur->mntpnt; 456*0Sstevel@tonic-gate m.mnt_fstype = ur->fstype; 457*0Sstevel@tonic-gate m.mnt_mntopts = ur->mntopts; 458*0Sstevel@tonic-gate /* 459*0Sstevel@tonic-gate * Special case for NFS mounts. 460*0Sstevel@tonic-gate * Don't want to attempt unmounts from 461*0Sstevel@tonic-gate * a dead server. If any member of a 462*0Sstevel@tonic-gate * hierarchy belongs to a dead server 463*0Sstevel@tonic-gate * give up (try later). 464*0Sstevel@tonic-gate */ 465*0Sstevel@tonic-gate if (strcmp(ur->fstype, MNTTYPE_NFS) == 0) { 466*0Sstevel@tonic-gate struct replica *list; 467*0Sstevel@tonic-gate int i, n; 468*0Sstevel@tonic-gate bool_t pubopt = FALSE; 469*0Sstevel@tonic-gate int nfs_port; 470*0Sstevel@tonic-gate int got_port; 471*0Sstevel@tonic-gate 472*0Sstevel@tonic-gate /* 473*0Sstevel@tonic-gate * See if a port number was specified. If one was 474*0Sstevel@tonic-gate * specified that is too large to fit in 16 bits, truncate 475*0Sstevel@tonic-gate * the high-order bits (for historical compatibility). Use 476*0Sstevel@tonic-gate * zero to indicate "no port specified". 477*0Sstevel@tonic-gate */ 478*0Sstevel@tonic-gate got_port = nopt(&m, MNTOPT_PORT, &nfs_port); 479*0Sstevel@tonic-gate if (!got_port) 480*0Sstevel@tonic-gate nfs_port = 0; 481*0Sstevel@tonic-gate nfs_port &= USHRT_MAX; 482*0Sstevel@tonic-gate 483*0Sstevel@tonic-gate if (hasmntopt(&m, MNTOPT_PUBLIC)) 484*0Sstevel@tonic-gate pubopt = TRUE; 485*0Sstevel@tonic-gate 486*0Sstevel@tonic-gate list = parse_replica(ur->mntresource, &n); 487*0Sstevel@tonic-gate if (list == NULL) { 488*0Sstevel@tonic-gate if (n >= 0) 489*0Sstevel@tonic-gate syslog(LOG_ERR, "Memory allocation failed: %m"); 490*0Sstevel@tonic-gate res = 1; 491*0Sstevel@tonic-gate goto done; 492*0Sstevel@tonic-gate } 493*0Sstevel@tonic-gate 494*0Sstevel@tonic-gate for (i = 0; i < n; i++) { 495*0Sstevel@tonic-gate if (pingnfs(list[i].host, 1, NULL, 0, nfs_port, 496*0Sstevel@tonic-gate pubopt, list[i].path, NULL) != RPC_SUCCESS) { 497*0Sstevel@tonic-gate res = 1; 498*0Sstevel@tonic-gate free_replica(list, n); 499*0Sstevel@tonic-gate goto done; 500*0Sstevel@tonic-gate } 501*0Sstevel@tonic-gate } 502*0Sstevel@tonic-gate free_replica(list, n); 503*0Sstevel@tonic-gate } 504*0Sstevel@tonic-gate 505*0Sstevel@tonic-gate res = unmount_mntpnt(&m); 506*0Sstevel@tonic-gate 507*0Sstevel@tonic-gate done: return (res); 508*0Sstevel@tonic-gate } 509*0Sstevel@tonic-gate 510*0Sstevel@tonic-gate static int 511*0Sstevel@tonic-gate unmount_mntpnt(mnt) 512*0Sstevel@tonic-gate struct mnttab *mnt; 513*0Sstevel@tonic-gate { 514*0Sstevel@tonic-gate char *fstype = mnt->mnt_fstype; 515*0Sstevel@tonic-gate char *mountp = mnt->mnt_mountp; 516*0Sstevel@tonic-gate char *newargv[ARGV_MAX]; 517*0Sstevel@tonic-gate int res; 518*0Sstevel@tonic-gate 519*0Sstevel@tonic-gate if (strcmp(fstype, MNTTYPE_NFS) == 0) { 520*0Sstevel@tonic-gate res = nfsunmount(mnt); 521*0Sstevel@tonic-gate } else if (strcmp(fstype, MNTTYPE_LOFS) == 0) { 522*0Sstevel@tonic-gate if ((res = umount(mountp)) < 0) 523*0Sstevel@tonic-gate res = errno; 524*0Sstevel@tonic-gate } else { 525*0Sstevel@tonic-gate newargv[2] = mountp; 526*0Sstevel@tonic-gate newargv[3] = NULL; 527*0Sstevel@tonic-gate 528*0Sstevel@tonic-gate res = fork_exec(fstype, "umount", newargv, verbose); 529*0Sstevel@tonic-gate if (res == ENOENT) { 530*0Sstevel@tonic-gate /* 531*0Sstevel@tonic-gate * filesystem specific unmount command not found 532*0Sstevel@tonic-gate */ 533*0Sstevel@tonic-gate if ((res = umount(mountp)) < 0) 534*0Sstevel@tonic-gate res = errno; 535*0Sstevel@tonic-gate } 536*0Sstevel@tonic-gate } 537*0Sstevel@tonic-gate 538*0Sstevel@tonic-gate if (trace > 1) 539*0Sstevel@tonic-gate trace_prt(1, " unmount %s %s\n", 540*0Sstevel@tonic-gate mountp, res ? "failed" : "OK"); 541*0Sstevel@tonic-gate return (res); 542*0Sstevel@tonic-gate } 543*0Sstevel@tonic-gate 544*0Sstevel@tonic-gate /* 545*0Sstevel@tonic-gate * Remove the autofs specific options 'browse', 'nobrowse' and 546*0Sstevel@tonic-gate * 'restrict' from 'opts'. 547*0Sstevel@tonic-gate */ 548*0Sstevel@tonic-gate static void 549*0Sstevel@tonic-gate remove_browse_options(char *opts) 550*0Sstevel@tonic-gate { 551*0Sstevel@tonic-gate char *p, *pb; 552*0Sstevel@tonic-gate char buf[MAXOPTSLEN], new[MAXOPTSLEN]; 553*0Sstevel@tonic-gate char *placeholder; 554*0Sstevel@tonic-gate 555*0Sstevel@tonic-gate new[0] = '\0'; 556*0Sstevel@tonic-gate (void) strcpy(buf, opts); 557*0Sstevel@tonic-gate pb = buf; 558*0Sstevel@tonic-gate while (p = (char *)strtok_r(pb, ",", &placeholder)) { 559*0Sstevel@tonic-gate pb = NULL; 560*0Sstevel@tonic-gate if (strcmp(p, MNTOPT_NOBROWSE) != 0 && 561*0Sstevel@tonic-gate strcmp(p, MNTOPT_BROWSE) != 0 && 562*0Sstevel@tonic-gate strcmp(p, MNTOPT_RESTRICT) != 0) { 563*0Sstevel@tonic-gate if (new[0] != '\0') 564*0Sstevel@tonic-gate (void) strcat(new, ","); 565*0Sstevel@tonic-gate (void) strcat(new, p); 566*0Sstevel@tonic-gate } 567*0Sstevel@tonic-gate } 568*0Sstevel@tonic-gate (void) strcpy(opts, new); 569*0Sstevel@tonic-gate } 570*0Sstevel@tonic-gate 571*0Sstevel@tonic-gate static const char *restropts[] = { 572*0Sstevel@tonic-gate RESTRICTED_MNTOPTS 573*0Sstevel@tonic-gate }; 574*0Sstevel@tonic-gate #define NROPTS (sizeof (restropts)/sizeof (restropts[0])) 575*0Sstevel@tonic-gate 576*0Sstevel@tonic-gate static int 577*0Sstevel@tonic-gate inherit_options(char *opts, char **mapentopts) 578*0Sstevel@tonic-gate { 579*0Sstevel@tonic-gate int i; 580*0Sstevel@tonic-gate char *new; 581*0Sstevel@tonic-gate struct mnttab mtmap; 582*0Sstevel@tonic-gate struct mnttab mtopt; 583*0Sstevel@tonic-gate 584*0Sstevel@tonic-gate size_t len = strlen(*mapentopts); 585*0Sstevel@tonic-gate 586*0Sstevel@tonic-gate for (i = 0; i < NROPTS; i++) 587*0Sstevel@tonic-gate len += strlen(restropts[i]); 588*0Sstevel@tonic-gate 589*0Sstevel@tonic-gate /* "," for each new option plus the trailing NUL */ 590*0Sstevel@tonic-gate len += NROPTS + 1; 591*0Sstevel@tonic-gate 592*0Sstevel@tonic-gate new = malloc(len); 593*0Sstevel@tonic-gate if (new == 0) 594*0Sstevel@tonic-gate return (-1); 595*0Sstevel@tonic-gate 596*0Sstevel@tonic-gate (void) strcpy(new, *mapentopts); 597*0Sstevel@tonic-gate 598*0Sstevel@tonic-gate mtmap.mnt_mntopts = *mapentopts; 599*0Sstevel@tonic-gate mtopt.mnt_mntopts = opts; 600*0Sstevel@tonic-gate 601*0Sstevel@tonic-gate for (i = 0; i < NROPTS; i++) { 602*0Sstevel@tonic-gate if (hasmntopt(&mtopt, (char *)restropts[i]) != NULL && 603*0Sstevel@tonic-gate hasmntopt(&mtmap, (char *)restropts[i]) == NULL) { 604*0Sstevel@tonic-gate if (*new != '\0') 605*0Sstevel@tonic-gate (void) strcat(new, ","); 606*0Sstevel@tonic-gate (void) strcat(new, restropts[i]); 607*0Sstevel@tonic-gate } 608*0Sstevel@tonic-gate } 609*0Sstevel@tonic-gate free(*mapentopts); 610*0Sstevel@tonic-gate *mapentopts = new; 611*0Sstevel@tonic-gate return (0); 612*0Sstevel@tonic-gate } 613*0Sstevel@tonic-gate 614*0Sstevel@tonic-gate bool_t 615*0Sstevel@tonic-gate hasrestrictopt(char *opts) 616*0Sstevel@tonic-gate { 617*0Sstevel@tonic-gate struct mnttab mt; 618*0Sstevel@tonic-gate 619*0Sstevel@tonic-gate mt.mnt_mntopts = opts; 620*0Sstevel@tonic-gate 621*0Sstevel@tonic-gate return (hasmntopt(&mt, MNTOPT_RESTRICT) != NULL); 622*0Sstevel@tonic-gate } 623