1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include <stdio.h> 30*7c478bd9Sstevel@tonic-gate #include <stdarg.h> 31*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 32*7c478bd9Sstevel@tonic-gate #include <unistd.h> 33*7c478bd9Sstevel@tonic-gate #include <libintl.h> 34*7c478bd9Sstevel@tonic-gate #include <string.h> 35*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 36*7c478bd9Sstevel@tonic-gate #include <errno.h> 37*7c478bd9Sstevel@tonic-gate #include <syslog.h> 38*7c478bd9Sstevel@tonic-gate #include <alloca.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/vfstab.h> 40*7c478bd9Sstevel@tonic-gate #include <sys/mnttab.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/mntent.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/mount.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/filio.h> 44*7c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_filio.h> 45*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 46*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 47*7c478bd9Sstevel@tonic-gate #include <zone.h> 48*7c478bd9Sstevel@tonic-gate #include <signal.h> 49*7c478bd9Sstevel@tonic-gate #include <strings.h> 50*7c478bd9Sstevel@tonic-gate #include "fslib.h" 51*7c478bd9Sstevel@tonic-gate 52*7c478bd9Sstevel@tonic-gate /* LINTLIBRARY */ 53*7c478bd9Sstevel@tonic-gate 54*7c478bd9Sstevel@tonic-gate #define BUFLEN 256 55*7c478bd9Sstevel@tonic-gate 56*7c478bd9Sstevel@tonic-gate #define TIME_MAX 16 57*7c478bd9Sstevel@tonic-gate 58*7c478bd9Sstevel@tonic-gate /* 59*7c478bd9Sstevel@tonic-gate * Reads all of the entries from the in-kernel mnttab, and returns the 60*7c478bd9Sstevel@tonic-gate * linked list of the entries. 61*7c478bd9Sstevel@tonic-gate */ 62*7c478bd9Sstevel@tonic-gate mntlist_t * 63*7c478bd9Sstevel@tonic-gate fsgetmntlist(void) 64*7c478bd9Sstevel@tonic-gate { 65*7c478bd9Sstevel@tonic-gate FILE *mfp; 66*7c478bd9Sstevel@tonic-gate mntlist_t *mntl; 67*7c478bd9Sstevel@tonic-gate char buf[BUFLEN]; 68*7c478bd9Sstevel@tonic-gate 69*7c478bd9Sstevel@tonic-gate if ((mfp = fopen(MNTTAB, "r")) == NULL) { 70*7c478bd9Sstevel@tonic-gate (void) snprintf(buf, BUFLEN, "fsgetmntlist: fopen %s", MNTTAB); 71*7c478bd9Sstevel@tonic-gate perror(buf); 72*7c478bd9Sstevel@tonic-gate return (NULL); 73*7c478bd9Sstevel@tonic-gate } 74*7c478bd9Sstevel@tonic-gate 75*7c478bd9Sstevel@tonic-gate mntl = fsmkmntlist(mfp); 76*7c478bd9Sstevel@tonic-gate 77*7c478bd9Sstevel@tonic-gate (void) fclose(mfp); 78*7c478bd9Sstevel@tonic-gate return (mntl); 79*7c478bd9Sstevel@tonic-gate } 80*7c478bd9Sstevel@tonic-gate 81*7c478bd9Sstevel@tonic-gate 82*7c478bd9Sstevel@tonic-gate static struct extmnttab zmnttab = { 0 }; 83*7c478bd9Sstevel@tonic-gate 84*7c478bd9Sstevel@tonic-gate struct extmnttab * 85*7c478bd9Sstevel@tonic-gate fsdupmnttab(struct extmnttab *mnt) 86*7c478bd9Sstevel@tonic-gate { 87*7c478bd9Sstevel@tonic-gate struct extmnttab *new; 88*7c478bd9Sstevel@tonic-gate 89*7c478bd9Sstevel@tonic-gate new = (struct extmnttab *)malloc(sizeof (*new)); 90*7c478bd9Sstevel@tonic-gate if (new == NULL) 91*7c478bd9Sstevel@tonic-gate goto alloc_failed; 92*7c478bd9Sstevel@tonic-gate 93*7c478bd9Sstevel@tonic-gate *new = zmnttab; 94*7c478bd9Sstevel@tonic-gate /* 95*7c478bd9Sstevel@tonic-gate * Allocate an extra byte for the mountpoint 96*7c478bd9Sstevel@tonic-gate * name in case a space needs to be added. 97*7c478bd9Sstevel@tonic-gate */ 98*7c478bd9Sstevel@tonic-gate new->mnt_mountp = (char *)malloc(strlen(mnt->mnt_mountp) + 2); 99*7c478bd9Sstevel@tonic-gate if (new->mnt_mountp == NULL) 100*7c478bd9Sstevel@tonic-gate goto alloc_failed; 101*7c478bd9Sstevel@tonic-gate (void) strcpy(new->mnt_mountp, mnt->mnt_mountp); 102*7c478bd9Sstevel@tonic-gate 103*7c478bd9Sstevel@tonic-gate if ((new->mnt_special = strdup(mnt->mnt_special)) == NULL) 104*7c478bd9Sstevel@tonic-gate goto alloc_failed; 105*7c478bd9Sstevel@tonic-gate 106*7c478bd9Sstevel@tonic-gate if ((new->mnt_fstype = strdup(mnt->mnt_fstype)) == NULL) 107*7c478bd9Sstevel@tonic-gate goto alloc_failed; 108*7c478bd9Sstevel@tonic-gate 109*7c478bd9Sstevel@tonic-gate if (mnt->mnt_mntopts != NULL) 110*7c478bd9Sstevel@tonic-gate if ((new->mnt_mntopts = strdup(mnt->mnt_mntopts)) == NULL) 111*7c478bd9Sstevel@tonic-gate goto alloc_failed; 112*7c478bd9Sstevel@tonic-gate 113*7c478bd9Sstevel@tonic-gate if (mnt->mnt_time != NULL) 114*7c478bd9Sstevel@tonic-gate if ((new->mnt_time = strdup(mnt->mnt_time)) == NULL) 115*7c478bd9Sstevel@tonic-gate goto alloc_failed; 116*7c478bd9Sstevel@tonic-gate 117*7c478bd9Sstevel@tonic-gate new->mnt_major = mnt->mnt_major; 118*7c478bd9Sstevel@tonic-gate new->mnt_minor = mnt->mnt_minor; 119*7c478bd9Sstevel@tonic-gate return (new); 120*7c478bd9Sstevel@tonic-gate 121*7c478bd9Sstevel@tonic-gate alloc_failed: 122*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("fsdupmnttab: Out of memory\n")); 123*7c478bd9Sstevel@tonic-gate fsfreemnttab(new); 124*7c478bd9Sstevel@tonic-gate return (NULL); 125*7c478bd9Sstevel@tonic-gate } 126*7c478bd9Sstevel@tonic-gate 127*7c478bd9Sstevel@tonic-gate /* 128*7c478bd9Sstevel@tonic-gate * Free a single mnttab structure 129*7c478bd9Sstevel@tonic-gate */ 130*7c478bd9Sstevel@tonic-gate void 131*7c478bd9Sstevel@tonic-gate fsfreemnttab(struct extmnttab *mnt) 132*7c478bd9Sstevel@tonic-gate { 133*7c478bd9Sstevel@tonic-gate 134*7c478bd9Sstevel@tonic-gate if (mnt) { 135*7c478bd9Sstevel@tonic-gate if (mnt->mnt_special) 136*7c478bd9Sstevel@tonic-gate free(mnt->mnt_special); 137*7c478bd9Sstevel@tonic-gate if (mnt->mnt_mountp) 138*7c478bd9Sstevel@tonic-gate free(mnt->mnt_mountp); 139*7c478bd9Sstevel@tonic-gate if (mnt->mnt_fstype) 140*7c478bd9Sstevel@tonic-gate free(mnt->mnt_fstype); 141*7c478bd9Sstevel@tonic-gate if (mnt->mnt_mntopts) 142*7c478bd9Sstevel@tonic-gate free(mnt->mnt_mntopts); 143*7c478bd9Sstevel@tonic-gate if (mnt->mnt_time) 144*7c478bd9Sstevel@tonic-gate free(mnt->mnt_time); 145*7c478bd9Sstevel@tonic-gate free(mnt); 146*7c478bd9Sstevel@tonic-gate } 147*7c478bd9Sstevel@tonic-gate } 148*7c478bd9Sstevel@tonic-gate 149*7c478bd9Sstevel@tonic-gate void 150*7c478bd9Sstevel@tonic-gate fsfreemntlist(mntlist_t *mntl) 151*7c478bd9Sstevel@tonic-gate { 152*7c478bd9Sstevel@tonic-gate mntlist_t *mntl_tmp; 153*7c478bd9Sstevel@tonic-gate 154*7c478bd9Sstevel@tonic-gate while (mntl) { 155*7c478bd9Sstevel@tonic-gate fsfreemnttab(mntl->mntl_mnt); 156*7c478bd9Sstevel@tonic-gate mntl_tmp = mntl; 157*7c478bd9Sstevel@tonic-gate mntl = mntl->mntl_next; 158*7c478bd9Sstevel@tonic-gate free(mntl_tmp); 159*7c478bd9Sstevel@tonic-gate } 160*7c478bd9Sstevel@tonic-gate } 161*7c478bd9Sstevel@tonic-gate 162*7c478bd9Sstevel@tonic-gate /* 163*7c478bd9Sstevel@tonic-gate * Read the mnttab file and return it as a list of mnttab structs. 164*7c478bd9Sstevel@tonic-gate * Returns NULL if there was a memory failure. 165*7c478bd9Sstevel@tonic-gate */ 166*7c478bd9Sstevel@tonic-gate mntlist_t * 167*7c478bd9Sstevel@tonic-gate fsmkmntlist(FILE *mfp) 168*7c478bd9Sstevel@tonic-gate { 169*7c478bd9Sstevel@tonic-gate struct extmnttab mnt; 170*7c478bd9Sstevel@tonic-gate mntlist_t *mhead, *mtail; 171*7c478bd9Sstevel@tonic-gate int ret; 172*7c478bd9Sstevel@tonic-gate 173*7c478bd9Sstevel@tonic-gate mhead = mtail = NULL; 174*7c478bd9Sstevel@tonic-gate 175*7c478bd9Sstevel@tonic-gate resetmnttab(mfp); 176*7c478bd9Sstevel@tonic-gate while ((ret = getextmntent(mfp, &mnt, sizeof (struct extmnttab))) 177*7c478bd9Sstevel@tonic-gate != -1) { 178*7c478bd9Sstevel@tonic-gate mntlist_t *mp; 179*7c478bd9Sstevel@tonic-gate 180*7c478bd9Sstevel@tonic-gate if (ret != 0) /* bad entry */ 181*7c478bd9Sstevel@tonic-gate continue; 182*7c478bd9Sstevel@tonic-gate 183*7c478bd9Sstevel@tonic-gate mp = (mntlist_t *)malloc(sizeof (*mp)); 184*7c478bd9Sstevel@tonic-gate if (mp == NULL) 185*7c478bd9Sstevel@tonic-gate goto alloc_failed; 186*7c478bd9Sstevel@tonic-gate if (mhead == NULL) 187*7c478bd9Sstevel@tonic-gate mhead = mp; 188*7c478bd9Sstevel@tonic-gate else 189*7c478bd9Sstevel@tonic-gate mtail->mntl_next = mp; 190*7c478bd9Sstevel@tonic-gate mtail = mp; 191*7c478bd9Sstevel@tonic-gate mp->mntl_next = NULL; 192*7c478bd9Sstevel@tonic-gate mp->mntl_flags = 0; 193*7c478bd9Sstevel@tonic-gate if ((mp->mntl_mnt = fsdupmnttab(&mnt)) == NULL) 194*7c478bd9Sstevel@tonic-gate goto alloc_failed; 195*7c478bd9Sstevel@tonic-gate } 196*7c478bd9Sstevel@tonic-gate return (mhead); 197*7c478bd9Sstevel@tonic-gate 198*7c478bd9Sstevel@tonic-gate alloc_failed: 199*7c478bd9Sstevel@tonic-gate fsfreemntlist(mhead); 200*7c478bd9Sstevel@tonic-gate return (NULL); 201*7c478bd9Sstevel@tonic-gate } 202*7c478bd9Sstevel@tonic-gate 203*7c478bd9Sstevel@tonic-gate /* 204*7c478bd9Sstevel@tonic-gate * Return the last entry that matches mntin's special 205*7c478bd9Sstevel@tonic-gate * device and/or mountpt. 206*7c478bd9Sstevel@tonic-gate * Helps to be robust here, so we check for NULL pointers. 207*7c478bd9Sstevel@tonic-gate */ 208*7c478bd9Sstevel@tonic-gate mntlist_t * 209*7c478bd9Sstevel@tonic-gate fsgetmlast(mntlist_t *ml, struct mnttab *mntin) 210*7c478bd9Sstevel@tonic-gate { 211*7c478bd9Sstevel@tonic-gate mntlist_t *delete = NULL; 212*7c478bd9Sstevel@tonic-gate 213*7c478bd9Sstevel@tonic-gate for (; ml; ml = ml->mntl_next) { 214*7c478bd9Sstevel@tonic-gate if (mntin->mnt_mountp && mntin->mnt_special) { 215*7c478bd9Sstevel@tonic-gate /* 216*7c478bd9Sstevel@tonic-gate * match if and only if both are equal. 217*7c478bd9Sstevel@tonic-gate */ 218*7c478bd9Sstevel@tonic-gate if ((strcmp(ml->mntl_mnt->mnt_mountp, 219*7c478bd9Sstevel@tonic-gate mntin->mnt_mountp) == 0) && 220*7c478bd9Sstevel@tonic-gate (strcmp(ml->mntl_mnt->mnt_special, 221*7c478bd9Sstevel@tonic-gate mntin->mnt_special) == 0)) 222*7c478bd9Sstevel@tonic-gate delete = ml; 223*7c478bd9Sstevel@tonic-gate } else if (mntin->mnt_mountp) { 224*7c478bd9Sstevel@tonic-gate if (strcmp(ml->mntl_mnt->mnt_mountp, 225*7c478bd9Sstevel@tonic-gate mntin->mnt_mountp) == 0) 226*7c478bd9Sstevel@tonic-gate delete = ml; 227*7c478bd9Sstevel@tonic-gate } else if (mntin->mnt_special) { 228*7c478bd9Sstevel@tonic-gate if (strcmp(ml->mntl_mnt->mnt_special, 229*7c478bd9Sstevel@tonic-gate mntin->mnt_special) == 0) 230*7c478bd9Sstevel@tonic-gate delete = ml; 231*7c478bd9Sstevel@tonic-gate } 232*7c478bd9Sstevel@tonic-gate } 233*7c478bd9Sstevel@tonic-gate return (delete); 234*7c478bd9Sstevel@tonic-gate } 235*7c478bd9Sstevel@tonic-gate 236*7c478bd9Sstevel@tonic-gate 237*7c478bd9Sstevel@tonic-gate /* 238*7c478bd9Sstevel@tonic-gate * Returns the mountlevel of the pathname in cp. As examples, 239*7c478bd9Sstevel@tonic-gate * / => 1, /bin => 2, /bin/ => 2, ////bin////ls => 3, sdf => 0, etc... 240*7c478bd9Sstevel@tonic-gate */ 241*7c478bd9Sstevel@tonic-gate int 242*7c478bd9Sstevel@tonic-gate fsgetmlevel(char *cp) 243*7c478bd9Sstevel@tonic-gate { 244*7c478bd9Sstevel@tonic-gate int mlevel; 245*7c478bd9Sstevel@tonic-gate char *cp1; 246*7c478bd9Sstevel@tonic-gate 247*7c478bd9Sstevel@tonic-gate if (cp == NULL || *cp == NULL || *cp != '/') 248*7c478bd9Sstevel@tonic-gate return (0); /* this should never happen */ 249*7c478bd9Sstevel@tonic-gate 250*7c478bd9Sstevel@tonic-gate mlevel = 1; /* root (/) is the minimal case */ 251*7c478bd9Sstevel@tonic-gate 252*7c478bd9Sstevel@tonic-gate for (cp1 = cp + 1; *cp1; cp++, cp1++) 253*7c478bd9Sstevel@tonic-gate if (*cp == '/' && *cp1 != '/') /* "///" counts as 1 */ 254*7c478bd9Sstevel@tonic-gate mlevel++; 255*7c478bd9Sstevel@tonic-gate 256*7c478bd9Sstevel@tonic-gate return (mlevel); 257*7c478bd9Sstevel@tonic-gate } 258*7c478bd9Sstevel@tonic-gate 259*7c478bd9Sstevel@tonic-gate /* 260*7c478bd9Sstevel@tonic-gate * Returns non-zero if string s is a member of the strings in ps. 261*7c478bd9Sstevel@tonic-gate */ 262*7c478bd9Sstevel@tonic-gate int 263*7c478bd9Sstevel@tonic-gate fsstrinlist(const char *s, const char **ps) 264*7c478bd9Sstevel@tonic-gate { 265*7c478bd9Sstevel@tonic-gate const char *cp; 266*7c478bd9Sstevel@tonic-gate cp = *ps; 267*7c478bd9Sstevel@tonic-gate while (cp) { 268*7c478bd9Sstevel@tonic-gate if (strcmp(s, cp) == 0) 269*7c478bd9Sstevel@tonic-gate return (1); 270*7c478bd9Sstevel@tonic-gate ps++; 271*7c478bd9Sstevel@tonic-gate cp = *ps; 272*7c478bd9Sstevel@tonic-gate } 273*7c478bd9Sstevel@tonic-gate return (0); 274*7c478bd9Sstevel@tonic-gate } 275*7c478bd9Sstevel@tonic-gate 276*7c478bd9Sstevel@tonic-gate static char *empty_opt_vector[] = { 277*7c478bd9Sstevel@tonic-gate NULL 278*7c478bd9Sstevel@tonic-gate }; 279*7c478bd9Sstevel@tonic-gate /* 280*7c478bd9Sstevel@tonic-gate * Compare the mount options that were requested by the caller to 281*7c478bd9Sstevel@tonic-gate * the options actually supported by the file system. If any requested 282*7c478bd9Sstevel@tonic-gate * options are not supported, print a warning message. 283*7c478bd9Sstevel@tonic-gate * 284*7c478bd9Sstevel@tonic-gate * WARNING: this function modifies the string pointed to by 285*7c478bd9Sstevel@tonic-gate * the requested_opts argument. 286*7c478bd9Sstevel@tonic-gate * 287*7c478bd9Sstevel@tonic-gate * Arguments: 288*7c478bd9Sstevel@tonic-gate * requested_opts - the string containing the requested options. 289*7c478bd9Sstevel@tonic-gate * actual_opts - the string returned by mount(2), which lists the 290*7c478bd9Sstevel@tonic-gate * options actually supported. It is normal for this 291*7c478bd9Sstevel@tonic-gate * string to contain more options than the requested options. 292*7c478bd9Sstevel@tonic-gate * (The actual options may contain the default options, which 293*7c478bd9Sstevel@tonic-gate * may not have been included in the requested options.) 294*7c478bd9Sstevel@tonic-gate * special - device being mounted (only used in error messages). 295*7c478bd9Sstevel@tonic-gate * mountp - mount point (only used in error messages). 296*7c478bd9Sstevel@tonic-gate */ 297*7c478bd9Sstevel@tonic-gate void 298*7c478bd9Sstevel@tonic-gate cmp_requested_to_actual_options(char *requested_opts, char *actual_opts, 299*7c478bd9Sstevel@tonic-gate char *special, char *mountp) 300*7c478bd9Sstevel@tonic-gate { 301*7c478bd9Sstevel@tonic-gate char *option_ptr, *actopt, *equalptr; 302*7c478bd9Sstevel@tonic-gate int found; 303*7c478bd9Sstevel@tonic-gate char *actual_opt_hold, *bufp; 304*7c478bd9Sstevel@tonic-gate 305*7c478bd9Sstevel@tonic-gate if (requested_opts == NULL) 306*7c478bd9Sstevel@tonic-gate return; 307*7c478bd9Sstevel@tonic-gate 308*7c478bd9Sstevel@tonic-gate bufp = alloca(strlen(actual_opts) + 1); 309*7c478bd9Sstevel@tonic-gate 310*7c478bd9Sstevel@tonic-gate while (*requested_opts != '\0') { 311*7c478bd9Sstevel@tonic-gate (void) getsubopt(&requested_opts, empty_opt_vector, 312*7c478bd9Sstevel@tonic-gate &option_ptr); 313*7c478bd9Sstevel@tonic-gate 314*7c478bd9Sstevel@tonic-gate /* 315*7c478bd9Sstevel@tonic-gate * Truncate any "=<value>" string from the end of 316*7c478bd9Sstevel@tonic-gate * the option. 317*7c478bd9Sstevel@tonic-gate */ 318*7c478bd9Sstevel@tonic-gate if ((equalptr = strchr(option_ptr, '=')) != NULL) 319*7c478bd9Sstevel@tonic-gate *equalptr = '\0'; 320*7c478bd9Sstevel@tonic-gate 321*7c478bd9Sstevel@tonic-gate if (*option_ptr == '\0') 322*7c478bd9Sstevel@tonic-gate continue; 323*7c478bd9Sstevel@tonic-gate 324*7c478bd9Sstevel@tonic-gate /* 325*7c478bd9Sstevel@tonic-gate * Search for the requested option in the list of options 326*7c478bd9Sstevel@tonic-gate * actually supported. 327*7c478bd9Sstevel@tonic-gate */ 328*7c478bd9Sstevel@tonic-gate found = 0; 329*7c478bd9Sstevel@tonic-gate 330*7c478bd9Sstevel@tonic-gate /* 331*7c478bd9Sstevel@tonic-gate * Need to use a copy of actual_opts because getsubopt 332*7c478bd9Sstevel@tonic-gate * is destructive and we need to scan the actual_opts 333*7c478bd9Sstevel@tonic-gate * string more than once. 334*7c478bd9Sstevel@tonic-gate * 335*7c478bd9Sstevel@tonic-gate * We also need to reset actual_opt_hold to the 336*7c478bd9Sstevel@tonic-gate * beginning of the buffer because getsubopt changes 337*7c478bd9Sstevel@tonic-gate * actual_opt_hold (the pointer). 338*7c478bd9Sstevel@tonic-gate */ 339*7c478bd9Sstevel@tonic-gate actual_opt_hold = bufp; 340*7c478bd9Sstevel@tonic-gate if (actual_opts != NULL) 341*7c478bd9Sstevel@tonic-gate (void) strcpy(actual_opt_hold, actual_opts); 342*7c478bd9Sstevel@tonic-gate else 343*7c478bd9Sstevel@tonic-gate *actual_opt_hold = '\0'; 344*7c478bd9Sstevel@tonic-gate 345*7c478bd9Sstevel@tonic-gate while (*actual_opt_hold != '\0') { 346*7c478bd9Sstevel@tonic-gate (void) getsubopt(&actual_opt_hold, empty_opt_vector, 347*7c478bd9Sstevel@tonic-gate &actopt); 348*7c478bd9Sstevel@tonic-gate 349*7c478bd9Sstevel@tonic-gate /* Truncate the "=<value>", if any. */ 350*7c478bd9Sstevel@tonic-gate if ((equalptr = strchr(actopt, '=')) != NULL) 351*7c478bd9Sstevel@tonic-gate *equalptr = '\0'; 352*7c478bd9Sstevel@tonic-gate 353*7c478bd9Sstevel@tonic-gate if ((strcmp(option_ptr, actopt)) == 0) { 354*7c478bd9Sstevel@tonic-gate found = 1; 355*7c478bd9Sstevel@tonic-gate break; 356*7c478bd9Sstevel@tonic-gate } 357*7c478bd9Sstevel@tonic-gate } 358*7c478bd9Sstevel@tonic-gate 359*7c478bd9Sstevel@tonic-gate if (found == 0) { 360*7c478bd9Sstevel@tonic-gate /* 361*7c478bd9Sstevel@tonic-gate * That we're ignoring the option is always 362*7c478bd9Sstevel@tonic-gate * truthful; the old message that the option 363*7c478bd9Sstevel@tonic-gate * was unknown is often not correct. 364*7c478bd9Sstevel@tonic-gate */ 365*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 366*7c478bd9Sstevel@tonic-gate "mount: %s on %s - WARNING ignoring option " 367*7c478bd9Sstevel@tonic-gate "\"%s\"\n"), special, mountp, option_ptr); 368*7c478bd9Sstevel@tonic-gate } 369*7c478bd9Sstevel@tonic-gate } 370*7c478bd9Sstevel@tonic-gate } 371*7c478bd9Sstevel@tonic-gate /* 372*7c478bd9Sstevel@tonic-gate * FUNCTION: fsgetmaxphys(int *, int *) 373*7c478bd9Sstevel@tonic-gate * 374*7c478bd9Sstevel@tonic-gate * INPUT: int *maxphys - a pointer to an integer that will hold 375*7c478bd9Sstevel@tonic-gate * the value for the system maxphys value. 376*7c478bd9Sstevel@tonic-gate * int *error - 0 means completed successfully 377*7c478bd9Sstevel@tonic-gate * otherwise this indicates the errno value. 378*7c478bd9Sstevel@tonic-gate * 379*7c478bd9Sstevel@tonic-gate * RETURNS: int - 0 if maxphys not found 380*7c478bd9Sstevel@tonic-gate * - 1 if maxphys is found 381*7c478bd9Sstevel@tonic-gate */ 382*7c478bd9Sstevel@tonic-gate int 383*7c478bd9Sstevel@tonic-gate fsgetmaxphys(int *maxphys, int *error) { 384*7c478bd9Sstevel@tonic-gate 385*7c478bd9Sstevel@tonic-gate int gotit = 0; 386*7c478bd9Sstevel@tonic-gate int fp = open("/", O_RDONLY); 387*7c478bd9Sstevel@tonic-gate 388*7c478bd9Sstevel@tonic-gate *error = 0; 389*7c478bd9Sstevel@tonic-gate 390*7c478bd9Sstevel@tonic-gate /* 391*7c478bd9Sstevel@tonic-gate * For some reason cannot open root as read only. Need a valid file 392*7c478bd9Sstevel@tonic-gate * descriptor to call the ufs private ioctl. If this open failes, 393*7c478bd9Sstevel@tonic-gate * just assume we cannot get maxphys in this case. 394*7c478bd9Sstevel@tonic-gate */ 395*7c478bd9Sstevel@tonic-gate if (fp == -1) { 396*7c478bd9Sstevel@tonic-gate return (gotit); 397*7c478bd9Sstevel@tonic-gate } 398*7c478bd9Sstevel@tonic-gate 399*7c478bd9Sstevel@tonic-gate if (ioctl(fp, _FIOGETMAXPHYS, maxphys) == -1) { 400*7c478bd9Sstevel@tonic-gate *error = errno; 401*7c478bd9Sstevel@tonic-gate (void) close(fp); 402*7c478bd9Sstevel@tonic-gate return (gotit); 403*7c478bd9Sstevel@tonic-gate } 404*7c478bd9Sstevel@tonic-gate 405*7c478bd9Sstevel@tonic-gate (void) close(fp); 406*7c478bd9Sstevel@tonic-gate gotit = 1; 407*7c478bd9Sstevel@tonic-gate return (gotit); 408*7c478bd9Sstevel@tonic-gate 409*7c478bd9Sstevel@tonic-gate } 410*7c478bd9Sstevel@tonic-gate 411*7c478bd9Sstevel@tonic-gate /* 412*7c478bd9Sstevel@tonic-gate * The below is limited support for zone-aware commands. 413*7c478bd9Sstevel@tonic-gate */ 414*7c478bd9Sstevel@tonic-gate struct zone_summary { 415*7c478bd9Sstevel@tonic-gate zoneid_t zoneid; 416*7c478bd9Sstevel@tonic-gate char rootpath[MAXPATHLEN]; 417*7c478bd9Sstevel@tonic-gate size_t rootpathlen; 418*7c478bd9Sstevel@tonic-gate }; 419*7c478bd9Sstevel@tonic-gate 420*7c478bd9Sstevel@tonic-gate struct zone_summary * 421*7c478bd9Sstevel@tonic-gate fs_get_zone_summaries(void) 422*7c478bd9Sstevel@tonic-gate { 423*7c478bd9Sstevel@tonic-gate uint_t numzones = 0, oldnumzones = 0; 424*7c478bd9Sstevel@tonic-gate uint_t i, j; 425*7c478bd9Sstevel@tonic-gate zoneid_t *ids = NULL; 426*7c478bd9Sstevel@tonic-gate struct zone_summary *summaries; 427*7c478bd9Sstevel@tonic-gate zoneid_t myzoneid = getzoneid(); 428*7c478bd9Sstevel@tonic-gate 429*7c478bd9Sstevel@tonic-gate for (;;) { 430*7c478bd9Sstevel@tonic-gate if (zone_list(ids, &numzones) < 0) { 431*7c478bd9Sstevel@tonic-gate perror("unable to retrieve list of zones"); 432*7c478bd9Sstevel@tonic-gate if (ids != NULL) 433*7c478bd9Sstevel@tonic-gate free(ids); 434*7c478bd9Sstevel@tonic-gate return (NULL); 435*7c478bd9Sstevel@tonic-gate } 436*7c478bd9Sstevel@tonic-gate if (numzones <= oldnumzones) 437*7c478bd9Sstevel@tonic-gate break; 438*7c478bd9Sstevel@tonic-gate if (ids != NULL) 439*7c478bd9Sstevel@tonic-gate free(ids); 440*7c478bd9Sstevel@tonic-gate ids = malloc(numzones * sizeof (*ids)); 441*7c478bd9Sstevel@tonic-gate if (ids == NULL) { 442*7c478bd9Sstevel@tonic-gate perror("malloc failed"); 443*7c478bd9Sstevel@tonic-gate return (NULL); 444*7c478bd9Sstevel@tonic-gate } 445*7c478bd9Sstevel@tonic-gate oldnumzones = numzones; 446*7c478bd9Sstevel@tonic-gate } 447*7c478bd9Sstevel@tonic-gate 448*7c478bd9Sstevel@tonic-gate summaries = malloc((numzones + 1) * sizeof (*summaries)); 449*7c478bd9Sstevel@tonic-gate if (summaries == NULL) { 450*7c478bd9Sstevel@tonic-gate free(ids); 451*7c478bd9Sstevel@tonic-gate perror("malloc failed"); 452*7c478bd9Sstevel@tonic-gate return (NULL); 453*7c478bd9Sstevel@tonic-gate } 454*7c478bd9Sstevel@tonic-gate 455*7c478bd9Sstevel@tonic-gate 456*7c478bd9Sstevel@tonic-gate for (i = 0, j = 0; i < numzones; i++) { 457*7c478bd9Sstevel@tonic-gate ssize_t len; 458*7c478bd9Sstevel@tonic-gate 459*7c478bd9Sstevel@tonic-gate if (ids[i] == myzoneid) 460*7c478bd9Sstevel@tonic-gate continue; 461*7c478bd9Sstevel@tonic-gate len = zone_getattr(ids[i], ZONE_ATTR_ROOT, 462*7c478bd9Sstevel@tonic-gate summaries[j].rootpath, sizeof (summaries[j].rootpath)); 463*7c478bd9Sstevel@tonic-gate if (len < 0) { 464*7c478bd9Sstevel@tonic-gate /* 465*7c478bd9Sstevel@tonic-gate * Zone must have gone away. Skip. 466*7c478bd9Sstevel@tonic-gate */ 467*7c478bd9Sstevel@tonic-gate continue; 468*7c478bd9Sstevel@tonic-gate } 469*7c478bd9Sstevel@tonic-gate /* 470*7c478bd9Sstevel@tonic-gate * Adding a trailing '/' to the zone's rootpath allows us to 471*7c478bd9Sstevel@tonic-gate * use strncmp() to see if a given path resides within that 472*7c478bd9Sstevel@tonic-gate * zone. 473*7c478bd9Sstevel@tonic-gate * 474*7c478bd9Sstevel@tonic-gate * As an example, if the zone's rootpath is "/foo/root", 475*7c478bd9Sstevel@tonic-gate * "/foo/root/usr" resides within the zone, while 476*7c478bd9Sstevel@tonic-gate * "/foo/rootpath" doesn't. 477*7c478bd9Sstevel@tonic-gate */ 478*7c478bd9Sstevel@tonic-gate (void) strlcat(summaries[j].rootpath, "/", 479*7c478bd9Sstevel@tonic-gate sizeof (summaries[j].rootpath)); 480*7c478bd9Sstevel@tonic-gate summaries[j].rootpathlen = len; 481*7c478bd9Sstevel@tonic-gate summaries[j].zoneid = ids[i]; 482*7c478bd9Sstevel@tonic-gate j++; 483*7c478bd9Sstevel@tonic-gate } 484*7c478bd9Sstevel@tonic-gate summaries[j].zoneid = -1; 485*7c478bd9Sstevel@tonic-gate free(ids); 486*7c478bd9Sstevel@tonic-gate return (summaries); 487*7c478bd9Sstevel@tonic-gate } 488*7c478bd9Sstevel@tonic-gate 489*7c478bd9Sstevel@tonic-gate static zoneid_t 490*7c478bd9Sstevel@tonic-gate fs_find_zone(const struct zone_summary *summaries, const char *mntpt) 491*7c478bd9Sstevel@tonic-gate { 492*7c478bd9Sstevel@tonic-gate uint_t i; 493*7c478bd9Sstevel@tonic-gate 494*7c478bd9Sstevel@tonic-gate for (i = 0; summaries[i].zoneid != -1; i++) { 495*7c478bd9Sstevel@tonic-gate if (strncmp(mntpt, summaries[i].rootpath, 496*7c478bd9Sstevel@tonic-gate summaries[i].rootpathlen) == 0) 497*7c478bd9Sstevel@tonic-gate return (summaries[i].zoneid); 498*7c478bd9Sstevel@tonic-gate } 499*7c478bd9Sstevel@tonic-gate /* 500*7c478bd9Sstevel@tonic-gate * (-1) is the special token we return to the caller if the mount 501*7c478bd9Sstevel@tonic-gate * wasn't found in any other mounts on the system. This means it's 502*7c478bd9Sstevel@tonic-gate * only visible to our zone. 503*7c478bd9Sstevel@tonic-gate * 504*7c478bd9Sstevel@tonic-gate * Odd choice of constant, I know, but it beats calling getzoneid() a 505*7c478bd9Sstevel@tonic-gate * million times. 506*7c478bd9Sstevel@tonic-gate */ 507*7c478bd9Sstevel@tonic-gate return (-1); 508*7c478bd9Sstevel@tonic-gate } 509*7c478bd9Sstevel@tonic-gate 510*7c478bd9Sstevel@tonic-gate boolean_t 511*7c478bd9Sstevel@tonic-gate fs_mount_in_other_zone(const struct zone_summary *summaries, const char *mntpt) 512*7c478bd9Sstevel@tonic-gate { 513*7c478bd9Sstevel@tonic-gate return (fs_find_zone(summaries, mntpt) != -1); 514*7c478bd9Sstevel@tonic-gate } 515*7c478bd9Sstevel@tonic-gate 516*7c478bd9Sstevel@tonic-gate /* 517*7c478bd9Sstevel@tonic-gate * List of standard options. 518*7c478bd9Sstevel@tonic-gate */ 519*7c478bd9Sstevel@tonic-gate static const char *stdopts[] = { 520*7c478bd9Sstevel@tonic-gate MNTOPT_RO, MNTOPT_RW, 521*7c478bd9Sstevel@tonic-gate MNTOPT_SUID, MNTOPT_NOSUID, 522*7c478bd9Sstevel@tonic-gate MNTOPT_DEVICES, MNTOPT_NODEVICES, 523*7c478bd9Sstevel@tonic-gate MNTOPT_SETUID, MNTOPT_NOSETUID, 524*7c478bd9Sstevel@tonic-gate MNTOPT_NBMAND, MNTOPT_NONBMAND, 525*7c478bd9Sstevel@tonic-gate MNTOPT_EXEC, MNTOPT_NOEXEC, 526*7c478bd9Sstevel@tonic-gate }; 527*7c478bd9Sstevel@tonic-gate 528*7c478bd9Sstevel@tonic-gate #define NSTDOPT (sizeof (stdopts) / sizeof (stdopts[0])) 529*7c478bd9Sstevel@tonic-gate 530*7c478bd9Sstevel@tonic-gate static int 531*7c478bd9Sstevel@tonic-gate optindx(const char *opt) 532*7c478bd9Sstevel@tonic-gate { 533*7c478bd9Sstevel@tonic-gate int i; 534*7c478bd9Sstevel@tonic-gate 535*7c478bd9Sstevel@tonic-gate for (i = 0; i < NSTDOPT; i++) { 536*7c478bd9Sstevel@tonic-gate if (strcmp(opt, stdopts[i]) == 0) 537*7c478bd9Sstevel@tonic-gate return (i); 538*7c478bd9Sstevel@tonic-gate } 539*7c478bd9Sstevel@tonic-gate return (-1); 540*7c478bd9Sstevel@tonic-gate } 541*7c478bd9Sstevel@tonic-gate 542*7c478bd9Sstevel@tonic-gate /* 543*7c478bd9Sstevel@tonic-gate * INPUT: filesystem option not recognized by the fs specific option 544*7c478bd9Sstevel@tonic-gate * parsing code. 545*7c478bd9Sstevel@tonic-gate * OUTPUT: True if and only if the option is one of the standard VFS 546*7c478bd9Sstevel@tonic-gate * layer options. 547*7c478bd9Sstevel@tonic-gate */ 548*7c478bd9Sstevel@tonic-gate boolean_t 549*7c478bd9Sstevel@tonic-gate fsisstdopt(const char *opt) 550*7c478bd9Sstevel@tonic-gate { 551*7c478bd9Sstevel@tonic-gate return (optindx(opt) != -1); 552*7c478bd9Sstevel@tonic-gate } 553