1*facf4a8dSllai1 /* 2*facf4a8dSllai1 * CDDL HEADER START 3*facf4a8dSllai1 * 4*facf4a8dSllai1 * The contents of this file are subject to the terms of the 5*facf4a8dSllai1 * Common Development and Distribution License (the "License"). 6*facf4a8dSllai1 * You may not use this file except in compliance with the License. 7*facf4a8dSllai1 * 8*facf4a8dSllai1 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*facf4a8dSllai1 * or http://www.opensolaris.org/os/licensing. 10*facf4a8dSllai1 * See the License for the specific language governing permissions 11*facf4a8dSllai1 * and limitations under the License. 12*facf4a8dSllai1 * 13*facf4a8dSllai1 * When distributing Covered Code, include this CDDL HEADER in each 14*facf4a8dSllai1 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*facf4a8dSllai1 * If applicable, add the following below this CDDL HEADER, with the 16*facf4a8dSllai1 * fields enclosed by brackets "[]" replaced with your own identifying 17*facf4a8dSllai1 * information: Portions Copyright [yyyy] [name of copyright owner] 18*facf4a8dSllai1 * 19*facf4a8dSllai1 * CDDL HEADER END 20*facf4a8dSllai1 */ 21*facf4a8dSllai1 22*facf4a8dSllai1 /* 23*facf4a8dSllai1 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24*facf4a8dSllai1 * Use is subject to license terms. 25*facf4a8dSllai1 */ 26*facf4a8dSllai1 27*facf4a8dSllai1 #pragma ident "%Z%%M% %I% %E% SMI" 28*facf4a8dSllai1 29*facf4a8dSllai1 #include <sys/types.h> 30*facf4a8dSllai1 #include <limits.h> 31*facf4a8dSllai1 #include <stdio.h> 32*facf4a8dSllai1 #include <stdlib.h> 33*facf4a8dSllai1 #include <unistd.h> 34*facf4a8dSllai1 #include <signal.h> 35*facf4a8dSllai1 #include <errno.h> 36*facf4a8dSllai1 #include <string.h> 37*facf4a8dSllai1 #include <locale.h> 38*facf4a8dSllai1 #include <sys/stat.h> 39*facf4a8dSllai1 #include <sys/mount.h> 40*facf4a8dSllai1 #include <sys/mntent.h> 41*facf4a8dSllai1 #include <sys/fs/sdev_node.h> 42*facf4a8dSllai1 43*facf4a8dSllai1 44*facf4a8dSllai1 #define READFLAG_RO 1 45*facf4a8dSllai1 #define READFLAG_RW 2 46*facf4a8dSllai1 47*facf4a8dSllai1 48*facf4a8dSllai1 extern int optind; 49*facf4a8dSllai1 extern char *optarg; 50*facf4a8dSllai1 51*facf4a8dSllai1 static char typename[64], *myname; 52*facf4a8dSllai1 static char fstype[] = MNTTYPE_DEV; 53*facf4a8dSllai1 54*facf4a8dSllai1 static int readflag; 55*facf4a8dSllai1 static int overlay; 56*facf4a8dSllai1 static int remount; 57*facf4a8dSllai1 58*facf4a8dSllai1 static char *special; 59*facf4a8dSllai1 static char *mountpt; 60*facf4a8dSllai1 static struct sdev_mountargs mountargs; 61*facf4a8dSllai1 62*facf4a8dSllai1 static char *myopts[] = { 63*facf4a8dSllai1 #define SUBOPT_READONLY 0 64*facf4a8dSllai1 "ro", 65*facf4a8dSllai1 #define SUBOPT_READWRITE 1 66*facf4a8dSllai1 "rw", 67*facf4a8dSllai1 #define SUBOPT_ATTRIBDIR 2 68*facf4a8dSllai1 "attrdir", 69*facf4a8dSllai1 #define SUBOPT_REMOUNT 3 70*facf4a8dSllai1 "remount", 71*facf4a8dSllai1 NULL 72*facf4a8dSllai1 }; 73*facf4a8dSllai1 74*facf4a8dSllai1 75*facf4a8dSllai1 static void 76*facf4a8dSllai1 usage(void) 77*facf4a8dSllai1 { 78*facf4a8dSllai1 (void) fprintf(stderr, gettext( 79*facf4a8dSllai1 "%s usage:\n%s [-F %s] [-r] [-o specific_options]" 80*facf4a8dSllai1 " {special | mount_point}\n%s [-F %s] [-r] [-o specific_options]" 81*facf4a8dSllai1 " special mount_point\n"), fstype, myname, fstype, myname, fstype); 82*facf4a8dSllai1 exit(1); 83*facf4a8dSllai1 } 84*facf4a8dSllai1 85*facf4a8dSllai1 86*facf4a8dSllai1 static int 87*facf4a8dSllai1 do_mount(void) 88*facf4a8dSllai1 { 89*facf4a8dSllai1 int flags = MS_DATA; 90*facf4a8dSllai1 91*facf4a8dSllai1 if (readflag == READFLAG_RO) 92*facf4a8dSllai1 flags |= MS_RDONLY; 93*facf4a8dSllai1 if (overlay) 94*facf4a8dSllai1 flags |= MS_OVERLAY; 95*facf4a8dSllai1 if (remount) 96*facf4a8dSllai1 flags |= MS_REMOUNT; 97*facf4a8dSllai1 98*facf4a8dSllai1 if (mount(special, mountpt, flags, fstype, &mountargs, 99*facf4a8dSllai1 sizeof (mountargs), NULL, 0)) { 100*facf4a8dSllai1 switch (errno) { 101*facf4a8dSllai1 case EPERM: 102*facf4a8dSllai1 (void) fprintf(stderr, gettext("%s: not super user\n"), 103*facf4a8dSllai1 typename); 104*facf4a8dSllai1 break; 105*facf4a8dSllai1 case ENXIO: 106*facf4a8dSllai1 (void) fprintf(stderr, gettext("%s: %s no such " 107*facf4a8dSllai1 "device\n"), typename, special); 108*facf4a8dSllai1 break; 109*facf4a8dSllai1 case ENOTDIR: 110*facf4a8dSllai1 (void) fprintf(stderr, gettext("%s: %s " 111*facf4a8dSllai1 "not a directory\n" 112*facf4a8dSllai1 "\tor a component of %s is not a directory\n"), 113*facf4a8dSllai1 typename, mountpt, special); 114*facf4a8dSllai1 break; 115*facf4a8dSllai1 case ENOENT: 116*facf4a8dSllai1 (void) fprintf(stderr, gettext("%s: %s or %s, no such " 117*facf4a8dSllai1 "file or directory\n"), 118*facf4a8dSllai1 typename, special, mountpt); 119*facf4a8dSllai1 break; 120*facf4a8dSllai1 case EINVAL: 121*facf4a8dSllai1 (void) fprintf(stderr, gettext("%s: %s is not this " 122*facf4a8dSllai1 "filesystem type.\n"), typename, special); 123*facf4a8dSllai1 break; 124*facf4a8dSllai1 case EBUSY: 125*facf4a8dSllai1 (void) fprintf(stderr, gettext("%s: %s " 126*facf4a8dSllai1 "is already mounted, %s is busy,\n" 127*facf4a8dSllai1 "\tor allowable number of mount points exceeded\n"), 128*facf4a8dSllai1 typename, special, mountpt); 129*facf4a8dSllai1 break; 130*facf4a8dSllai1 case ENOTBLK: 131*facf4a8dSllai1 (void) fprintf(stderr, gettext("%s: %s not a block " 132*facf4a8dSllai1 "device\n"), typename, special); 133*facf4a8dSllai1 break; 134*facf4a8dSllai1 case EROFS: 135*facf4a8dSllai1 (void) fprintf(stderr, gettext("%s: %s read-only " 136*facf4a8dSllai1 "filesystem\n"), typename, special); 137*facf4a8dSllai1 break; 138*facf4a8dSllai1 case ENOSPC: 139*facf4a8dSllai1 (void) fprintf(stderr, gettext("%s: the state of %s " 140*facf4a8dSllai1 "is not okay\n" 141*facf4a8dSllai1 "\tand read/write mount was attempted\n"), 142*facf4a8dSllai1 typename, special); 143*facf4a8dSllai1 break; 144*facf4a8dSllai1 default: 145*facf4a8dSllai1 (void) fprintf(stderr, gettext("%s: cannot mount %s: " 146*facf4a8dSllai1 "%s\n"), typename, special, strerror(errno)); 147*facf4a8dSllai1 break; 148*facf4a8dSllai1 } 149*facf4a8dSllai1 return (-1); 150*facf4a8dSllai1 } 151*facf4a8dSllai1 return (0); 152*facf4a8dSllai1 } 153*facf4a8dSllai1 154*facf4a8dSllai1 155*facf4a8dSllai1 /* 156*facf4a8dSllai1 * Wrapper around strdup(). 157*facf4a8dSllai1 */ 158*facf4a8dSllai1 static char * 159*facf4a8dSllai1 do_strdup(const char *s1) 160*facf4a8dSllai1 { 161*facf4a8dSllai1 char *str; 162*facf4a8dSllai1 163*facf4a8dSllai1 str = strdup(s1); 164*facf4a8dSllai1 if (str == NULL) { 165*facf4a8dSllai1 (void) fprintf(stderr, gettext("%s: strdup failed: %s\n"), 166*facf4a8dSllai1 typename, strerror(errno)); 167*facf4a8dSllai1 } 168*facf4a8dSllai1 return (str); 169*facf4a8dSllai1 } 170*facf4a8dSllai1 171*facf4a8dSllai1 172*facf4a8dSllai1 /* 173*facf4a8dSllai1 * Wrapper around stat(). 174*facf4a8dSllai1 */ 175*facf4a8dSllai1 static int 176*facf4a8dSllai1 do_stat(const char *path, struct stat *buf) 177*facf4a8dSllai1 { 178*facf4a8dSllai1 int ret; 179*facf4a8dSllai1 180*facf4a8dSllai1 ret = stat(path, buf); 181*facf4a8dSllai1 if (ret < 0) { 182*facf4a8dSllai1 (void) fprintf(stderr, gettext("%s: can't stat %s: %s\n"), 183*facf4a8dSllai1 typename, path, strerror(errno)); 184*facf4a8dSllai1 } 185*facf4a8dSllai1 return (ret); 186*facf4a8dSllai1 } 187*facf4a8dSllai1 188*facf4a8dSllai1 189*facf4a8dSllai1 /* 190*facf4a8dSllai1 * Wraper around realpath() 191*facf4a8dSllai1 */ 192*facf4a8dSllai1 static char * 193*facf4a8dSllai1 do_realpath(const char *path, char *resolved_path) 194*facf4a8dSllai1 { 195*facf4a8dSllai1 char *ret; 196*facf4a8dSllai1 197*facf4a8dSllai1 ret = realpath(path, resolved_path); 198*facf4a8dSllai1 if (ret == NULL) { 199*facf4a8dSllai1 (void) fprintf(stderr, gettext("%s: realpath %s failed: %s\n"), 200*facf4a8dSllai1 typename, path, strerror(errno)); 201*facf4a8dSllai1 } 202*facf4a8dSllai1 return (ret); 203*facf4a8dSllai1 } 204*facf4a8dSllai1 205*facf4a8dSllai1 206*facf4a8dSllai1 static int 207*facf4a8dSllai1 parse_subopts(char *subopts) 208*facf4a8dSllai1 { 209*facf4a8dSllai1 char *value; 210*facf4a8dSllai1 char path[PATH_MAX + 1]; 211*facf4a8dSllai1 212*facf4a8dSllai1 while (*subopts != '\0') { 213*facf4a8dSllai1 switch (getsubopt(&subopts, myopts, &value)) { 214*facf4a8dSllai1 case SUBOPT_READONLY: 215*facf4a8dSllai1 if (readflag == READFLAG_RW) { 216*facf4a8dSllai1 (void) fprintf(stderr, gettext("%s: both " 217*facf4a8dSllai1 "read-only and read-write options " 218*facf4a8dSllai1 "specified\n"), typename); 219*facf4a8dSllai1 return (-1); 220*facf4a8dSllai1 } 221*facf4a8dSllai1 readflag = READFLAG_RO; 222*facf4a8dSllai1 break; 223*facf4a8dSllai1 224*facf4a8dSllai1 case SUBOPT_READWRITE: 225*facf4a8dSllai1 if (readflag == READFLAG_RO) { 226*facf4a8dSllai1 (void) fprintf(stderr, gettext("%s: both " 227*facf4a8dSllai1 "read-only and read-write options " 228*facf4a8dSllai1 "specified\n"), typename); 229*facf4a8dSllai1 return (-1); 230*facf4a8dSllai1 } 231*facf4a8dSllai1 readflag = READFLAG_RW; 232*facf4a8dSllai1 break; 233*facf4a8dSllai1 234*facf4a8dSllai1 case SUBOPT_ATTRIBDIR: 235*facf4a8dSllai1 if (value == NULL) { 236*facf4a8dSllai1 (void) fprintf(stderr, gettext("%s: no " 237*facf4a8dSllai1 "attribute directory\n"), typename); 238*facf4a8dSllai1 return (-1); 239*facf4a8dSllai1 } else { 240*facf4a8dSllai1 if (do_realpath(value, path) == NULL) 241*facf4a8dSllai1 return (-1); 242*facf4a8dSllai1 mountargs.sdev_attrdir = 243*facf4a8dSllai1 (uint64_t)(uintptr_t)do_strdup(path); 244*facf4a8dSllai1 if (mountargs.sdev_attrdir == NULL) 245*facf4a8dSllai1 return (-1); 246*facf4a8dSllai1 } 247*facf4a8dSllai1 break; 248*facf4a8dSllai1 249*facf4a8dSllai1 case SUBOPT_REMOUNT: 250*facf4a8dSllai1 remount = 1; 251*facf4a8dSllai1 break; 252*facf4a8dSllai1 253*facf4a8dSllai1 default: 254*facf4a8dSllai1 (void) fprintf(stderr, gettext("%s: illegal -o " 255*facf4a8dSllai1 "suboption: %s\n"), typename, value); 256*facf4a8dSllai1 return (-1); 257*facf4a8dSllai1 } 258*facf4a8dSllai1 } 259*facf4a8dSllai1 return (0); 260*facf4a8dSllai1 } 261*facf4a8dSllai1 262*facf4a8dSllai1 263*facf4a8dSllai1 int 264*facf4a8dSllai1 main(int argc, char **argv) 265*facf4a8dSllai1 { 266*facf4a8dSllai1 struct stat st; 267*facf4a8dSllai1 char mntpath[PATH_MAX + 1]; 268*facf4a8dSllai1 int cc; 269*facf4a8dSllai1 270*facf4a8dSllai1 (void) setlocale(LC_ALL, ""); 271*facf4a8dSllai1 272*facf4a8dSllai1 #if !defined(TEXT_DOMAIN) 273*facf4a8dSllai1 #define TEXT_DOMAIN "SYS_TEST" 274*facf4a8dSllai1 #endif 275*facf4a8dSllai1 (void) textdomain(TEXT_DOMAIN); 276*facf4a8dSllai1 277*facf4a8dSllai1 if (myname = strrchr(argv[0], '/')) 278*facf4a8dSllai1 myname++; 279*facf4a8dSllai1 else 280*facf4a8dSllai1 myname = argv[0]; 281*facf4a8dSllai1 (void) snprintf(typename, sizeof (typename), "%s %s", fstype, myname); 282*facf4a8dSllai1 argv[0] = typename; 283*facf4a8dSllai1 284*facf4a8dSllai1 while ((cc = getopt(argc, argv, "?o:rmO")) != -1) { 285*facf4a8dSllai1 switch (cc) { 286*facf4a8dSllai1 case 'r': 287*facf4a8dSllai1 if (readflag == READFLAG_RW) { 288*facf4a8dSllai1 (void) fprintf(stderr, gettext("%s: both " 289*facf4a8dSllai1 "read-only and read-write options " 290*facf4a8dSllai1 "specified\n"), typename); 291*facf4a8dSllai1 return (1); 292*facf4a8dSllai1 } 293*facf4a8dSllai1 readflag = READFLAG_RO; 294*facf4a8dSllai1 break; 295*facf4a8dSllai1 296*facf4a8dSllai1 case 'O': 297*facf4a8dSllai1 overlay = 1; 298*facf4a8dSllai1 break; 299*facf4a8dSllai1 300*facf4a8dSllai1 case 'o': 301*facf4a8dSllai1 if (parse_subopts(optarg)) 302*facf4a8dSllai1 return (1); 303*facf4a8dSllai1 break; 304*facf4a8dSllai1 305*facf4a8dSllai1 default: 306*facf4a8dSllai1 usage(); 307*facf4a8dSllai1 break; 308*facf4a8dSllai1 } 309*facf4a8dSllai1 } 310*facf4a8dSllai1 311*facf4a8dSllai1 /* 312*facf4a8dSllai1 * There must be at least 2 more arguments, the 313*facf4a8dSllai1 * special file and the directory. 314*facf4a8dSllai1 */ 315*facf4a8dSllai1 if ((argc - optind) != 2) 316*facf4a8dSllai1 usage(); 317*facf4a8dSllai1 318*facf4a8dSllai1 special = argv[optind++]; 319*facf4a8dSllai1 320*facf4a8dSllai1 if (do_realpath(argv[optind++], mntpath) == NULL) 321*facf4a8dSllai1 return (1); 322*facf4a8dSllai1 mountpt = mntpath; 323*facf4a8dSllai1 324*facf4a8dSllai1 if (mountpt) { 325*facf4a8dSllai1 if (do_stat(mountpt, &st) < 0) 326*facf4a8dSllai1 return (1); 327*facf4a8dSllai1 if (! S_ISDIR(st.st_mode)) { 328*facf4a8dSllai1 (void) fprintf(stderr, gettext("%s: %s is not a " 329*facf4a8dSllai1 "directory\n"), typename, mountpt); 330*facf4a8dSllai1 return (1); 331*facf4a8dSllai1 } 332*facf4a8dSllai1 } 333*facf4a8dSllai1 334*facf4a8dSllai1 if (mountargs.sdev_attrdir) { 335*facf4a8dSllai1 if (do_stat((const char *)(uintptr_t)mountargs.sdev_attrdir, 336*facf4a8dSllai1 &st) < 0) 337*facf4a8dSllai1 return (1); 338*facf4a8dSllai1 if (! S_ISDIR(st.st_mode)) { 339*facf4a8dSllai1 (void) fprintf(stderr, gettext("%s: %s is not a " 340*facf4a8dSllai1 "directory\n"), typename, mountargs.sdev_attrdir); 341*facf4a8dSllai1 return (1); 342*facf4a8dSllai1 } 343*facf4a8dSllai1 } 344*facf4a8dSllai1 345*facf4a8dSllai1 /* Special checks if /dev is the mount point */ 346*facf4a8dSllai1 /* Remount of /dev requires an attribute directory */ 347*facf4a8dSllai1 if (strcmp(mountpt, "/dev") == 0 && remount && 348*facf4a8dSllai1 mountargs.sdev_attrdir == NULL) { 349*facf4a8dSllai1 (void) fprintf(stderr, gettext("%s: missing attribute " 350*facf4a8dSllai1 "directory\n"), typename); 351*facf4a8dSllai1 return (1); 352*facf4a8dSllai1 } 353*facf4a8dSllai1 354*facf4a8dSllai1 (void) signal(SIGHUP, SIG_IGN); 355*facf4a8dSllai1 (void) signal(SIGQUIT, SIG_IGN); 356*facf4a8dSllai1 (void) signal(SIGINT, SIG_IGN); 357*facf4a8dSllai1 358*facf4a8dSllai1 /* Perform the mount */ 359*facf4a8dSllai1 if (do_mount()) 360*facf4a8dSllai1 return (1); 361*facf4a8dSllai1 362*facf4a8dSllai1 return (0); 363*facf4a8dSllai1 } 364