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