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, mntflags, set_gid, set_uid, set_mask, set_dirmask; 92 char *dev, *dir, mntpath[MAXPATHLEN]; 93 94 mntflags = set_gid = set_uid = set_mask = set_dirmask = 0; 95 (void)memset(&args, '\0', sizeof(args)); 96 args.magic = MSDOSFS_ARGSMAGIC; 97 98 while ((c = getopt(argc, argv, "sl9u:g:m:M:o:L:W:")) != -1) { 99 switch (c) { 100 #ifdef MSDOSFSMNT_GEMDOSFS 101 case 'G': 102 args.flags |= MSDOSFSMNT_GEMDOSFS; 103 break; 104 #endif 105 case 's': 106 args.flags |= MSDOSFSMNT_SHORTNAME; 107 break; 108 case 'l': 109 args.flags |= MSDOSFSMNT_LONGNAME; 110 break; 111 case '9': 112 args.flags |= MSDOSFSMNT_NOWIN95; 113 break; 114 case 'u': 115 args.uid = a_uid(optarg); 116 set_uid = 1; 117 break; 118 case 'g': 119 args.gid = a_gid(optarg); 120 set_gid = 1; 121 break; 122 case 'm': 123 args.mask = a_mask(optarg); 124 set_mask = 1; 125 break; 126 case 'M': 127 args.dirmask = a_mask(optarg); 128 set_dirmask = 1; 129 break; 130 case 'L': 131 load_ultable(&args, optarg); 132 args.flags |= MSDOSFSMNT_ULTABLE; 133 break; 134 case 'W': 135 load_u2wtable(&args, optarg); 136 args.flags |= MSDOSFSMNT_U2WTABLE; 137 break; 138 case 'o': 139 getmntopts(optarg, mopts, &mntflags, &args.flags); 140 break; 141 case '?': 142 default: 143 usage(); 144 break; 145 } 146 } 147 148 if (optind + 2 != argc) 149 usage(); 150 151 if (set_mask && !set_dirmask) { 152 args.dirmask = args.mask; 153 set_dirmask = 1; 154 } 155 else if (set_dirmask && !set_mask) { 156 args.mask = args.dirmask; 157 set_mask = 1; 158 } 159 160 dev = argv[optind]; 161 dir = argv[optind + 1]; 162 163 /* 164 * Resolve the mountpoint with realpath(3) and remove unnecessary 165 * slashes from the devicename if there are any. 166 */ 167 (void)checkpath(dir, mntpath); 168 (void)rmslashes(dev, dev); 169 170 args.fspec = dev; 171 args.export.ex_root = -2; /* unchecked anyway on DOS fs */ 172 if (mntflags & MNT_RDONLY) 173 args.export.ex_flags = MNT_EXRDONLY; 174 else 175 args.export.ex_flags = 0; 176 if (!set_gid || !set_uid || !set_mask) { 177 if (stat(mntpath, &sb) == -1) 178 err(EX_OSERR, "stat %s", mntpath); 179 180 if (!set_uid) 181 args.uid = sb.st_uid; 182 if (!set_gid) 183 args.gid = sb.st_gid; 184 if (!set_mask) 185 args.mask = args.dirmask = 186 sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); 187 } 188 189 if (mount("msdosfs", mntpath, mntflags, &args) < 0) 190 err(EX_OSERR, "%s", dev); 191 192 exit (0); 193 } 194 195 gid_t 196 a_gid(s) 197 char *s; 198 { 199 struct group *gr; 200 char *gname; 201 gid_t gid; 202 203 if ((gr = getgrnam(s)) != NULL) 204 gid = gr->gr_gid; 205 else { 206 for (gname = s; *s && isdigit(*s); ++s); 207 if (!*s) 208 gid = atoi(gname); 209 else 210 errx(EX_NOUSER, "unknown group id: %s", gname); 211 } 212 return (gid); 213 } 214 215 uid_t 216 a_uid(s) 217 char *s; 218 { 219 struct passwd *pw; 220 char *uname; 221 uid_t uid; 222 223 if ((pw = getpwnam(s)) != NULL) 224 uid = pw->pw_uid; 225 else { 226 for (uname = s; *s && isdigit(*s); ++s); 227 if (!*s) 228 uid = atoi(uname); 229 else 230 errx(EX_NOUSER, "unknown user id: %s", uname); 231 } 232 return (uid); 233 } 234 235 mode_t 236 a_mask(s) 237 char *s; 238 { 239 int done, rv; 240 char *ep; 241 242 done = 0; 243 rv = -1; 244 if (*s >= '0' && *s <= '7') { 245 done = 1; 246 rv = strtol(optarg, &ep, 8); 247 } 248 if (!done || rv < 0 || *ep) 249 errx(EX_USAGE, "invalid file mode: %s", s); 250 return (rv); 251 } 252 253 void 254 usage() 255 { 256 fprintf(stderr, "%s\n%s\n", 257 "usage: mount_msdosfs [-o options] [-u user] [-g group] [-m mask]", 258 " [-s] [-l] [-9] [-L locale] [-W table] bdev dir"); 259 exit(EX_USAGE); 260 } 261 262 void 263 load_u2wtable (pargs, name) 264 struct msdosfs_args *pargs; 265 char *name; 266 { 267 FILE *f; 268 int i, j, code[8]; 269 size_t line = 0; 270 char buf[128]; 271 char *fn, *s, *p; 272 273 if (*name == '/') 274 fn = name; 275 else { 276 snprintf(buf, sizeof(buf), "/usr/libdata/msdosfs/%s", name); 277 buf[127] = '\0'; 278 fn = buf; 279 } 280 if ((f = fopen(fn, "r")) == NULL) 281 err(EX_NOINPUT, "%s", fn); 282 p = NULL; 283 for (i = 0; i < 16; i++) { 284 do { 285 if (p != NULL) free(p); 286 if ((p = s = fparseln(f, NULL, &line, NULL, 0)) == NULL) 287 errx(EX_DATAERR, "can't read u2w table row %d near line %d", i, line); 288 while (isspace((unsigned char)*s)) 289 s++; 290 } while (*s == '\0'); 291 if (sscanf(s, "%i%i%i%i%i%i%i%i", 292 code, code + 1, code + 2, code + 3, code + 4, code + 5, code + 6, code + 7) != 8) 293 errx(EX_DATAERR, "u2w table: missing item(s) in row %d, line %d", i, line); 294 for (j = 0; j < 8; j++) 295 pargs->u2w[i * 8 + j] = code[j]; 296 } 297 for (i = 0; i < 16; i++) { 298 do { 299 free(p); 300 if ((p = s = fparseln(f, NULL, &line, NULL, 0)) == NULL) 301 errx(EX_DATAERR, "can't read d2u table row %d near line %d", i, line); 302 while (isspace((unsigned char)*s)) 303 s++; 304 } while (*s == '\0'); 305 if (sscanf(s, "%i%i%i%i%i%i%i%i", 306 code, code + 1, code + 2, code + 3, code + 4, code + 5, code + 6, code + 7) != 8) 307 errx(EX_DATAERR, "d2u table: missing item(s) in row %d, line %d", i, line); 308 for (j = 0; j < 8; j++) 309 pargs->d2u[i * 8 + j] = code[j]; 310 } 311 for (i = 0; i < 16; i++) { 312 do { 313 free(p); 314 if ((p = s = fparseln(f, NULL, &line, NULL, 0)) == NULL) 315 errx(EX_DATAERR, "can't read u2d table row %d near line %d", i, line); 316 while (isspace((unsigned char)*s)) 317 s++; 318 } while (*s == '\0'); 319 if (sscanf(s, "%i%i%i%i%i%i%i%i", 320 code, code + 1, code + 2, code + 3, code + 4, code + 5, code + 6, code + 7) != 8) 321 errx(EX_DATAERR, "u2d table: missing item(s) in row %d, line %d", i, line); 322 for (j = 0; j < 8; j++) 323 pargs->u2d[i * 8 + j] = code[j]; 324 } 325 free(p); 326 fclose(f); 327 } 328 329 void 330 load_ultable (pargs, name) 331 struct msdosfs_args *pargs; 332 char *name; 333 { 334 int i; 335 336 if (setlocale(LC_CTYPE, name) == NULL) 337 err(EX_CONFIG, "%s", name); 338 for (i = 0; i < 128; i++) { 339 pargs->ul[i] = tolower(i | 0x80); 340 pargs->lu[i] = toupper(i | 0x80); 341 } 342 } 343