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