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