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