1 /* $NetBSD: mount_msdos.c,v 1.18 1997/09/16 12:24:18 lukem Exp $ */ 2 3 /* 4 * Copyright (c) 1994 Christopher G. Demetriou 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Christopher G. Demetriou. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #ifndef lint 34 static const char rcsid[] = 35 "$FreeBSD$"; 36 #endif /* not lint */ 37 38 #include <sys/param.h> 39 #include <sys/mount.h> 40 #include <sys/stat.h> 41 42 #include <fs/msdosfs/msdosfsmount.h> 43 44 #include <ctype.h> 45 #include <err.h> 46 #include <grp.h> 47 #include <locale.h> 48 #include <pwd.h> 49 #include <stdio.h> 50 /* must be after stdio to declare fparseln */ 51 #include <libutil.h> 52 #include <stdlib.h> 53 #include <string.h> 54 #include <sysexits.h> 55 #include <unistd.h> 56 57 #include "mntopts.h" 58 59 /* 60 * XXX - no way to specify "foo=<bar>"-type options; that's what we'd 61 * want for "-u", "-g", "-m", "-L", and "-W". 62 */ 63 static struct mntopt mopts[] = { 64 MOPT_STDOPTS, 65 MOPT_FORCE, 66 MOPT_SYNC, 67 MOPT_UPDATE, 68 #ifdef MSDOSFSMNT_GEMDOSFS 69 { "gemdosfs", 0, MSDOSFSMNT_GEMDOSFS, 1 }, 70 #endif 71 { "shortnames", 0, MSDOSFSMNT_SHORTNAME, 1 }, 72 { "longnames", 0, MSDOSFSMNT_LONGNAME, 1 }, 73 { "nowin95", 0, MSDOSFSMNT_NOWIN95, 1 }, 74 { NULL } 75 }; 76 77 static gid_t a_gid(char *); 78 static uid_t a_uid(char *); 79 static mode_t a_mask(char *); 80 static void usage(void) __dead2; 81 static void load_u2wtable(struct msdosfs_args *, char *); 82 static void load_ultable(struct msdosfs_args *, char *); 83 84 int 85 main(argc, argv) 86 int argc; 87 char **argv; 88 { 89 struct msdosfs_args args; 90 struct stat sb; 91 int c, error, mntflags, set_gid, set_uid, set_mask; 92 char *dev, *dir, mntpath[MAXPATHLEN]; 93 struct vfsconf vfc; 94 95 mntflags = set_gid = set_uid = set_mask = 0; 96 (void)memset(&args, '\0', sizeof(args)); 97 args.magic = MSDOSFS_ARGSMAGIC; 98 99 while ((c = getopt(argc, argv, "sl9u:g:m:o:L:W:")) != -1) { 100 switch (c) { 101 #ifdef MSDOSFSMNT_GEMDOSFS 102 case 'G': 103 args.flags |= MSDOSFSMNT_GEMDOSFS; 104 break; 105 #endif 106 case 's': 107 args.flags |= MSDOSFSMNT_SHORTNAME; 108 break; 109 case 'l': 110 args.flags |= MSDOSFSMNT_LONGNAME; 111 break; 112 case '9': 113 args.flags |= MSDOSFSMNT_NOWIN95; 114 break; 115 case 'u': 116 args.uid = a_uid(optarg); 117 set_uid = 1; 118 break; 119 case 'g': 120 args.gid = a_gid(optarg); 121 set_gid = 1; 122 break; 123 case 'm': 124 args.mask = a_mask(optarg); 125 set_mask = 1; 126 break; 127 case 'L': 128 load_ultable(&args, optarg); 129 args.flags |= MSDOSFSMNT_ULTABLE; 130 break; 131 case 'W': 132 load_u2wtable(&args, optarg); 133 args.flags |= MSDOSFSMNT_U2WTABLE; 134 break; 135 case 'o': 136 getmntopts(optarg, mopts, &mntflags, &args.flags); 137 break; 138 case '?': 139 default: 140 usage(); 141 break; 142 } 143 } 144 145 if (optind + 2 != argc) 146 usage(); 147 148 dev = argv[optind]; 149 dir = argv[optind + 1]; 150 151 /* 152 * Resolve the mountpoint with realpath(3) and remove unnecessary 153 * slashes from the devicename if there are any. 154 */ 155 (void)checkpath(dir, mntpath); 156 (void)rmslashes(dev, dev); 157 158 args.fspec = dev; 159 args.export.ex_root = -2; /* unchecked anyway on DOS fs */ 160 if (mntflags & MNT_RDONLY) 161 args.export.ex_flags = MNT_EXRDONLY; 162 else 163 args.export.ex_flags = 0; 164 if (!set_gid || !set_uid || !set_mask) { 165 if (stat(mntpath, &sb) == -1) 166 err(EX_OSERR, "stat %s", mntpath); 167 168 if (!set_uid) 169 args.uid = sb.st_uid; 170 if (!set_gid) 171 args.gid = sb.st_gid; 172 if (!set_mask) 173 args.mask = sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); 174 } 175 176 error = getvfsbyname("msdosfs", &vfc); 177 if (error && vfsisloadable("msdosfs")) { 178 if (vfsload("msdosfs")) 179 err(EX_OSERR, "vfsload(msdosfs)"); 180 endvfsent(); /* clear cache */ 181 error = getvfsbyname("msdosfs", &vfc); 182 } 183 if (error) 184 errx(EX_OSERR, "msdos filesystem is not available"); 185 186 if (mount(vfc.vfc_name, mntpath, mntflags, &args) < 0) 187 err(EX_OSERR, "%s", dev); 188 189 exit (0); 190 } 191 192 gid_t 193 a_gid(s) 194 char *s; 195 { 196 struct group *gr; 197 char *gname; 198 gid_t gid; 199 200 if ((gr = getgrnam(s)) != NULL) 201 gid = gr->gr_gid; 202 else { 203 for (gname = s; *s && isdigit(*s); ++s); 204 if (!*s) 205 gid = atoi(gname); 206 else 207 errx(EX_NOUSER, "unknown group id: %s", gname); 208 } 209 return (gid); 210 } 211 212 uid_t 213 a_uid(s) 214 char *s; 215 { 216 struct passwd *pw; 217 char *uname; 218 uid_t uid; 219 220 if ((pw = getpwnam(s)) != NULL) 221 uid = pw->pw_uid; 222 else { 223 for (uname = s; *s && isdigit(*s); ++s); 224 if (!*s) 225 uid = atoi(uname); 226 else 227 errx(EX_NOUSER, "unknown user id: %s", uname); 228 } 229 return (uid); 230 } 231 232 mode_t 233 a_mask(s) 234 char *s; 235 { 236 int done, rv; 237 char *ep; 238 239 done = 0; 240 rv = -1; 241 if (*s >= '0' && *s <= '7') { 242 done = 1; 243 rv = strtol(optarg, &ep, 8); 244 } 245 if (!done || rv < 0 || *ep) 246 errx(EX_USAGE, "invalid file mode: %s", s); 247 return (rv); 248 } 249 250 void 251 usage() 252 { 253 fprintf(stderr, "%s\n%s\n", 254 "usage: mount_msdosfs [-o options] [-u user] [-g group] [-m mask]", 255 " [-s] [-l] [-9] [-L locale] [-W table] bdev dir"); 256 exit(EX_USAGE); 257 } 258 259 void 260 load_u2wtable (pargs, name) 261 struct msdosfs_args *pargs; 262 char *name; 263 { 264 FILE *f; 265 int i, j, code[8]; 266 size_t line = 0; 267 char buf[128]; 268 char *fn, *s, *p; 269 270 if (*name == '/') 271 fn = name; 272 else { 273 snprintf(buf, sizeof(buf), "/usr/libdata/msdosfs/%s", name); 274 buf[127] = '\0'; 275 fn = buf; 276 } 277 if ((f = fopen(fn, "r")) == NULL) 278 err(EX_NOINPUT, "%s", fn); 279 p = NULL; 280 for (i = 0; i < 16; i++) { 281 do { 282 if (p != NULL) free(p); 283 if ((p = s = fparseln(f, NULL, &line, NULL, 0)) == NULL) 284 errx(EX_DATAERR, "can't read u2w table row %d near line %d", i, line); 285 while (isspace((unsigned char)*s)) 286 s++; 287 } while (*s == '\0'); 288 if (sscanf(s, "%i%i%i%i%i%i%i%i", 289 code, code + 1, code + 2, code + 3, code + 4, code + 5, code + 6, code + 7) != 8) 290 errx(EX_DATAERR, "u2w table: missing item(s) in row %d, line %d", i, line); 291 for (j = 0; j < 8; j++) 292 pargs->u2w[i * 8 + j] = code[j]; 293 } 294 for (i = 0; i < 16; i++) { 295 do { 296 free(p); 297 if ((p = s = fparseln(f, NULL, &line, NULL, 0)) == NULL) 298 errx(EX_DATAERR, "can't read d2u table row %d near line %d", i, line); 299 while (isspace((unsigned char)*s)) 300 s++; 301 } while (*s == '\0'); 302 if (sscanf(s, "%i%i%i%i%i%i%i%i", 303 code, code + 1, code + 2, code + 3, code + 4, code + 5, code + 6, code + 7) != 8) 304 errx(EX_DATAERR, "d2u table: missing item(s) in row %d, line %d", i, line); 305 for (j = 0; j < 8; j++) 306 pargs->d2u[i * 8 + j] = code[j]; 307 } 308 for (i = 0; i < 16; i++) { 309 do { 310 free(p); 311 if ((p = s = fparseln(f, NULL, &line, NULL, 0)) == NULL) 312 errx(EX_DATAERR, "can't read u2d table row %d near line %d", i, line); 313 while (isspace((unsigned char)*s)) 314 s++; 315 } while (*s == '\0'); 316 if (sscanf(s, "%i%i%i%i%i%i%i%i", 317 code, code + 1, code + 2, code + 3, code + 4, code + 5, code + 6, code + 7) != 8) 318 errx(EX_DATAERR, "u2d table: missing item(s) in row %d, line %d", i, line); 319 for (j = 0; j < 8; j++) 320 pargs->u2d[i * 8 + j] = code[j]; 321 } 322 free(p); 323 fclose(f); 324 } 325 326 void 327 load_ultable (pargs, name) 328 struct msdosfs_args *pargs; 329 char *name; 330 { 331 int i; 332 333 if (setlocale(LC_CTYPE, name) == NULL) 334 err(EX_CONFIG, "%s", name); 335 for (i = 0; i < 128; i++) { 336 pargs->ul[i] = tolower(i | 0x80); 337 pargs->lu[i] = toupper(i | 0x80); 338 } 339 } 340