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