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 * $FreeBSD: src/sbin/mount_msdos/mount_msdos.c,v 1.19.2.1 2000/07/20 10:35:13 kris Exp $ 33 * $DragonFly: src/sbin/mount_msdos/mount_msdos.c,v 1.7 2005/04/02 21:41:06 dillon Exp $ 34 */ 35 36 #include <sys/param.h> 37 #include <sys/mount.h> 38 #include <sys/stat.h> 39 40 #include <vfs/msdosfs/msdosfsmount.h> 41 42 #include <ctype.h> 43 #include <err.h> 44 #include <grp.h> 45 #include <locale.h> 46 #include <pwd.h> 47 #include <stdio.h> 48 /* must be after stdio to declare fparseln */ 49 #include <libutil.h> 50 #include <stdlib.h> 51 #include <string.h> 52 #include <sysexits.h> 53 #include <unistd.h> 54 55 #include "mntopts.h" 56 57 /* 58 * XXX - no way to specify "foo=<bar>"-type options; that's what we'd 59 * want for "-u", "-g", "-m", "-L", and "-W". 60 */ 61 static struct mntopt mopts[] = { 62 MOPT_STDOPTS, 63 MOPT_FORCE, 64 MOPT_SYNC, 65 MOPT_UPDATE, 66 #ifdef MSDOSFSMNT_GEMDOSFS 67 { "gemdosfs", 0, MSDOSFSMNT_GEMDOSFS, 1 }, 68 #endif 69 { "shortnames", 0, MSDOSFSMNT_SHORTNAME, 1 }, 70 { "longnames", 0, MSDOSFSMNT_LONGNAME, 1 }, 71 { "nowin95", 0, MSDOSFSMNT_NOWIN95, 1 }, 72 MOPT_NULL 73 }; 74 75 static gid_t a_gid(char *); 76 static uid_t a_uid(char *); 77 static mode_t a_mask(char *); 78 static void usage(void) __dead2; 79 static void load_u2wtable(struct msdosfs_args *, char *); 80 static void load_ultable(struct msdosfs_args *, char *); 81 82 int 83 main(int argc, char **argv) 84 { 85 struct msdosfs_args args; 86 struct stat sb; 87 int c, error, mntflags, set_gid, set_uid, set_mask; 88 char *dev, *dir, mntpath[MAXPATHLEN]; 89 struct vfsconf vfc; 90 91 mntflags = set_gid = set_uid = set_mask = 0; 92 memset(&args, '\0', sizeof(args)); 93 args.magic = MSDOSFS_ARGSMAGIC; 94 95 while ((c = getopt(argc, argv, "sl9u:g:m:o:L:W:")) != -1) { 96 switch (c) { 97 #ifdef MSDOSFSMNT_GEMDOSFS 98 case 'G': 99 args.flags |= MSDOSFSMNT_GEMDOSFS; 100 break; 101 #endif 102 case 's': 103 args.flags |= MSDOSFSMNT_SHORTNAME; 104 break; 105 case 'l': 106 args.flags |= MSDOSFSMNT_LONGNAME; 107 break; 108 case '9': 109 args.flags |= MSDOSFSMNT_NOWIN95; 110 break; 111 case 'u': 112 args.uid = a_uid(optarg); 113 set_uid = 1; 114 break; 115 case 'g': 116 args.gid = a_gid(optarg); 117 set_gid = 1; 118 break; 119 case 'm': 120 args.mask = a_mask(optarg); 121 set_mask = 1; 122 break; 123 case 'L': 124 load_ultable(&args, optarg); 125 args.flags |= MSDOSFSMNT_ULTABLE; 126 break; 127 case 'W': 128 load_u2wtable(&args, optarg); 129 args.flags |= MSDOSFSMNT_U2WTABLE; 130 break; 131 case 'o': 132 getmntopts(optarg, mopts, &mntflags, &args.flags); 133 break; 134 case '?': 135 default: 136 usage(); 137 break; 138 } 139 } 140 141 if (optind + 2 != argc) 142 usage(); 143 144 dev = argv[optind]; 145 dir = argv[optind + 1]; 146 147 /* 148 * Resolve the mountpoint with realpath(3) and remove unnecessary 149 * slashes from the devicename if there are any. 150 */ 151 checkpath(dir, mntpath); 152 rmslashes(dev, dev); 153 154 args.fspec = dev; 155 args.export.ex_root = -2; /* unchecked anyway on DOS fs */ 156 if (mntflags & MNT_RDONLY) 157 args.export.ex_flags = MNT_EXRDONLY; 158 else 159 args.export.ex_flags = 0; 160 if (!set_gid || !set_uid || !set_mask) { 161 if (stat(mntpath, &sb) == -1) 162 err(EX_OSERR, "stat %s", mntpath); 163 164 if (!set_uid) 165 args.uid = sb.st_uid; 166 if (!set_gid) 167 args.gid = sb.st_gid; 168 if (!set_mask) 169 args.mask = sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); 170 } 171 172 error = getvfsbyname("msdos", &vfc); 173 if (error && vfsisloadable("msdos")) { 174 if (vfsload("msdos")) 175 err(EX_OSERR, "vfsload(msdos)"); 176 endvfsent(); /* clear cache */ 177 error = getvfsbyname("msdos", &vfc); 178 } 179 if (error) 180 errx(EX_OSERR, "msdos filesystem is not available"); 181 182 if (mount(vfc.vfc_name, mntpath, mntflags, &args) < 0) 183 err(EX_OSERR, "%s", dev); 184 185 exit (0); 186 } 187 188 static gid_t 189 a_gid(char *s) 190 { 191 struct group *gr; 192 char *gname; 193 gid_t gid; 194 195 if ((gr = getgrnam(s)) != NULL) 196 gid = gr->gr_gid; 197 else { 198 for (gname = s; *s && isdigit(*s); ++s); 199 if (!*s) 200 gid = atoi(gname); 201 else 202 errx(EX_NOUSER, "unknown group id: %s", gname); 203 } 204 return (gid); 205 } 206 207 static uid_t 208 a_uid(char *s) 209 { 210 struct passwd *pw; 211 char *uname; 212 uid_t uid; 213 214 if ((pw = getpwnam(s)) != NULL) 215 uid = pw->pw_uid; 216 else { 217 for (uname = s; *s && isdigit(*s); ++s); 218 if (!*s) 219 uid = atoi(uname); 220 else 221 errx(EX_NOUSER, "unknown user id: %s", uname); 222 } 223 return (uid); 224 } 225 226 static mode_t 227 a_mask(char *s) 228 { 229 int done, rv; 230 char *ep; 231 232 done = 0; 233 rv = -1; 234 if (*s >= '0' && *s <= '7') { 235 done = 1; 236 rv = strtol(optarg, &ep, 8); 237 } 238 if (!done || rv < 0 || *ep) 239 errx(EX_USAGE, "invalid file mode: %s", s); 240 return (rv); 241 } 242 243 static void 244 usage(void) 245 { 246 fprintf(stderr, "%s\n%s\n", 247 "usage: mount_msdos [-o options] [-u user] [-g group] [-m mask]", 248 " [-s] [-l] [-9] [-L locale] [-W table] bdev dir"); 249 exit(EX_USAGE); 250 } 251 252 static void 253 load_u2wtable (struct msdosfs_args *pargs, char *name) 254 { 255 FILE *f; 256 int i, j, code[8]; 257 size_t line = 0; 258 char buf[128]; 259 char *fn, *s, *p; 260 261 if (*name == '/') 262 fn = name; 263 else { 264 snprintf(buf, sizeof(buf), "/usr/libdata/msdosfs/%s", name); 265 buf[127] = '\0'; 266 fn = buf; 267 } 268 if ((f = fopen(fn, "r")) == NULL) 269 err(EX_NOINPUT, "%s", fn); 270 p = NULL; 271 for (i = 0; i < 16; i++) { 272 do { 273 if (p != NULL) free(p); 274 if ((p = s = fparseln(f, NULL, &line, NULL, 0)) == NULL) 275 errx(EX_DATAERR, "can't read u2w table row %d near line %d", i, line); 276 while (isspace((unsigned char)*s)) 277 s++; 278 } while (*s == '\0'); 279 if (sscanf(s, "%i%i%i%i%i%i%i%i", 280 code, code + 1, code + 2, code + 3, code + 4, code + 5, code + 6, code + 7) != 8) 281 errx(EX_DATAERR, "u2w table: missing item(s) in row %d, line %d", i, line); 282 for (j = 0; j < 8; j++) 283 pargs->u2w[i * 8 + j] = code[j]; 284 } 285 for (i = 0; i < 16; i++) { 286 do { 287 free(p); 288 if ((p = s = fparseln(f, NULL, &line, NULL, 0)) == NULL) 289 errx(EX_DATAERR, "can't read d2u table row %d near line %d", i, line); 290 while (isspace((unsigned char)*s)) 291 s++; 292 } while (*s == '\0'); 293 if (sscanf(s, "%i%i%i%i%i%i%i%i", 294 code, code + 1, code + 2, code + 3, code + 4, code + 5, code + 6, code + 7) != 8) 295 errx(EX_DATAERR, "d2u table: missing item(s) in row %d, line %d", i, line); 296 for (j = 0; j < 8; j++) 297 pargs->d2u[i * 8 + j] = code[j]; 298 } 299 for (i = 0; i < 16; i++) { 300 do { 301 free(p); 302 if ((p = s = fparseln(f, NULL, &line, NULL, 0)) == NULL) 303 errx(EX_DATAERR, "can't read u2d table row %d near line %d", i, line); 304 while (isspace((unsigned char)*s)) 305 s++; 306 } while (*s == '\0'); 307 if (sscanf(s, "%i%i%i%i%i%i%i%i", 308 code, code + 1, code + 2, code + 3, code + 4, code + 5, code + 6, code + 7) != 8) 309 errx(EX_DATAERR, "u2d table: missing item(s) in row %d, line %d", i, line); 310 for (j = 0; j < 8; j++) 311 pargs->u2d[i * 8 + j] = code[j]; 312 } 313 free(p); 314 fclose(f); 315 } 316 317 static void 318 load_ultable (struct msdosfs_args *pargs, char *name) 319 { 320 int i; 321 322 if (setlocale(LC_CTYPE, name) == NULL) 323 err(EX_CONFIG, "%s", name); 324 for (i = 0; i < 128; i++) { 325 pargs->ul[i] = tolower(i | 0x80); 326 pargs->lu[i] = toupper(i | 0x80); 327 } 328 } 329