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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <ctype.h> 28 #include <string.h> 29 #include <stdio.h> 30 #include <unistd.h> /* defines F_LOCK for lockf */ 31 #include <stdlib.h> /* for getopt(3) */ 32 #include <signal.h> 33 #include <locale.h> 34 #include <fslib.h> 35 #include <sys/types.h> 36 #include <errno.h> 37 #include <sys/mnttab.h> 38 #include <sys/mntent.h> 39 #include <sys/mount.h> 40 #include <sys/vfs.h> 41 #include <sys/fs/hsfs_susp.h> 42 #include <sys/fs/hsfs_rrip.h> 43 44 extern int optind; 45 extern char *optarg; 46 47 #define NAME_MAX 64 48 #define GLOBAL 0 49 #define NOGLOBAL 1 50 51 #ifndef MNTOPT_NOGLOBAL 52 #define MNTOPT_NOGLOBAL "noglobal" 53 #endif /* MNTOPT_NOGLOBAL */ 54 55 static int gflg = 0; /* mount into global name space: flag form */ 56 static int global = 0; /* mount into global name space: option form */ 57 static int havegblopt = 0; /* global value supercedes gflg value */ 58 static int qflg = 0; /* quiet option - don't flag bad options */ 59 60 static char fstype[] = MNTTYPE_HSFS; 61 62 static char typename[NAME_MAX], *myname; 63 /* 64 * Mount options that require special handling 65 */ 66 static char *myopts[] = { 67 MNTOPT_GLOBAL, 68 MNTOPT_NOGLOBAL, 69 NULL 70 }; 71 72 73 static void rpterr(char *, char *); 74 static void usage(void); 75 76 int 77 main(int argc, char **argv) 78 { 79 char *options, *value; 80 char *special, *mountp; 81 char *gopt; 82 struct mnttab mm; 83 int c; 84 char obuff[MAX_MNTOPT_STR]; 85 char saved_input_options[MAX_MNTOPT_STR]; 86 int hsfs_flags; 87 88 int flags; 89 int Oflg = 0; /* Overlay mounts */ 90 91 (void) setlocale(LC_ALL, ""); 92 93 #if !defined(TEXT_DOMAIN) 94 #define TEXT_DOMAIN "SYS_TEST" 95 #endif 96 (void) textdomain(TEXT_DOMAIN); 97 98 myname = strrchr(argv[0], '/'); 99 if (myname) 100 myname++; 101 else 102 myname = argv[0]; 103 snprintf(typename, sizeof (typename), "%s %s", fstype, myname); 104 argv[0] = typename; 105 106 /* 107 * Check for arguments requiring special handling. Ignore 108 * unrecognized options. 109 */ 110 strcpy(obuff, "ro"); /* default */ 111 while ((c = getopt(argc, argv, "o:rmOgq")) != EOF) { 112 switch (c) { 113 case 'o': 114 if (strlen(optarg) > MAX_MNTOPT_STR) { 115 (void) fprintf(stderr, gettext( 116 "%s: option set too long\n"), 117 myname); 118 exit(1); 119 } 120 if (strlen(optarg) == 0) { 121 (void) fprintf(stderr, gettext( 122 "%s: missing suboptions\n"), 123 myname); 124 exit(1); 125 } 126 strcpy(obuff, optarg); 127 options = optarg; 128 while (*options != '\0') { 129 switch (getsubopt(&options, myopts, 130 &value)) { 131 case GLOBAL: 132 havegblopt = 1; 133 global = 1; 134 break; 135 case NOGLOBAL: 136 havegblopt = 1; 137 global = 0; 138 break; 139 } 140 } 141 break; 142 case 'O': 143 Oflg++; 144 break; 145 case 'r': 146 /* accept for backwards compatibility */ 147 break; 148 case 'm': 149 break; 150 case 'g': 151 gflg++; 152 break; 153 case 'q': 154 qflg++; 155 break; 156 157 } 158 } 159 160 if ((argc - optind) != 2) 161 usage(); 162 163 special = argv[optind++]; 164 mountp = argv[optind++]; 165 166 /* 167 * Force readonly. obuff is guaranteed to have something in 168 * it. We might end up with "ro,ro", but that's acceptable. 169 */ 170 flags = MS_RDONLY; 171 172 if ((strlen(obuff) + strlen(MNTOPT_RO) + 2) > MAX_MNTOPT_STR) { 173 (void) fprintf(stderr, gettext("%s: option set too long\n"), 174 myname); 175 exit(1); 176 } 177 178 strcat(obuff, ","); 179 strcat(obuff, MNTOPT_RO); 180 181 flags |= Oflg ? MS_OVERLAY : 0; 182 183 /* 184 * xxx it's not clear if should just put MS_GLOBAL in flags, 185 * or provide it as a string. Be safe, do both. The subopt 186 * version has precedence over the switch version. 187 */ 188 gopt = NULL; 189 if ((havegblopt && global) || gflg) { 190 gopt = MNTOPT_GLOBAL; 191 flags |= MS_GLOBAL; 192 } else if (havegblopt) { 193 gopt = MNTOPT_NOGLOBAL; 194 } 195 196 if (gopt != NULL) { 197 if ((strlen(obuff) + strlen(gopt) + 2) > MAX_MNTOPT_STR) { 198 (void) fprintf(stderr, 199 gettext("%s: option set too long\n"), myname); 200 exit(1); 201 } 202 203 strcat(obuff, ","); 204 strcat(obuff, gopt); 205 } 206 207 signal(SIGHUP, SIG_IGN); 208 signal(SIGQUIT, SIG_IGN); 209 signal(SIGINT, SIG_IGN); 210 211 /* 212 * Save a copy of the options to compare with the options that 213 * were actually recognized and supported by the kernel. 214 */ 215 216 (void) strcpy(saved_input_options, obuff); 217 218 /* 219 * Perform the mount. 220 */ 221 222 if (mount(special, mountp, flags | MS_OPTIONSTR, fstype, NULL, 0, 223 obuff, sizeof (obuff)) == -1) { 224 rpterr(special, mountp); 225 exit(31+2); 226 } 227 228 if (!qflg) { 229 cmp_requested_to_actual_options(saved_input_options, obuff, 230 special, mountp); 231 } 232 233 exit(0); 234 /* NOTREACHED */ 235 } 236 237 238 static void 239 rpterr(char *bs, char *mp) 240 { 241 switch (errno) { 242 case EPERM: 243 (void) fprintf(stderr, gettext("%s: insufficient privileges\n"), 244 myname); 245 break; 246 case ENXIO: 247 (void) fprintf(stderr, gettext("%s: %s no such device\n"), 248 myname, bs); 249 break; 250 case ENOTDIR: 251 (void) fprintf(stderr, gettext("%s: %s not a directory\n\tor a " 252 "component of %s is not a directory\n"), myname, mp, bs); 253 break; 254 case ENOENT: 255 (void) fprintf(stderr, 256 gettext("%s: %s or %s, no such file or directory\n"), 257 myname, bs, mp); 258 break; 259 case EINVAL: 260 (void) fprintf(stderr, gettext("%s: %s is not an hsfs file " 261 "system.\n"), typename, bs); 262 break; 263 case EBUSY: 264 (void) fprintf(stderr, 265 gettext("%s: %s is already mounted or %s is busy\n"), 266 myname, bs, mp); 267 break; 268 case ENOTBLK: 269 (void) fprintf(stderr, 270 gettext("%s: %s not a block device\n"), myname, bs); 271 break; 272 case EROFS: 273 (void) fprintf(stderr, gettext("%s: %s write-protected\n"), 274 myname, bs); 275 break; 276 case ENOSPC: 277 (void) fprintf(stderr, 278 gettext("%s: %s is corrupted. needs checking\n"), 279 myname, bs); 280 break; 281 default: 282 perror(myname); 283 (void) fprintf(stderr, gettext("%s: cannot mount %s\n"), myname, 284 bs); 285 } 286 } 287 288 289 static void 290 usage() 291 { 292 char *opts; 293 294 opts = "{-r | -o ro | -o nrr | -o nosuid | -o notraildot | -o nomaplcase}"; 295 (void) fprintf(stdout, 296 gettext("hsfs usage: mount [-F hsfs] %s {special | mount_point}\n"), opts); 297 (void) fprintf(stdout, 298 gettext("hsfs usage: mount [-F hsfs] %s special mount_point\n"), opts); 299 exit(32); 300 } 301