mount_msdosfs.c revision 118837
11590Srgrimes/*	$NetBSD: mount_msdos.c,v 1.18 1997/09/16 12:24:18 lukem Exp $	*/
21590Srgrimes
31590Srgrimes/*
41590Srgrimes * Copyright (c) 1994 Christopher G. Demetriou
51590Srgrimes * All rights reserved.
61590Srgrimes *
71590Srgrimes * Redistribution and use in source and binary forms, with or without
81590Srgrimes * modification, are permitted provided that the following conditions
91590Srgrimes * are met:
101590Srgrimes * 1. Redistributions of source code must retain the above copyright
111590Srgrimes *    notice, this list of conditions and the following disclaimer.
121590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
131590Srgrimes *    notice, this list of conditions and the following disclaimer in the
141590Srgrimes *    documentation and/or other materials provided with the distribution.
151590Srgrimes * 3. All advertising materials mentioning features or use of this software
161590Srgrimes *    must display the following acknowledgement:
171590Srgrimes *      This product includes software developed by Christopher G. Demetriou.
181590Srgrimes * 4. The name of the author may not be used to endorse or promote products
191590Srgrimes *    derived from this software without specific prior written permission
201590Srgrimes *
211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
221590Srgrimes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
231590Srgrimes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
241590Srgrimes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
251590Srgrimes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
261590Srgrimes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
271590Srgrimes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
281590Srgrimes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
291590Srgrimes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
301590Srgrimes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
311590Srgrimes */
321590Srgrimes
331590Srgrimes#ifndef lint
341590Srgrimesstatic const char rcsid[] =
351590Srgrimes  "$FreeBSD: head/sbin/mount_msdosfs/mount_msdosfs.c 118837 2003-08-12 20:06:56Z trhodes $";
361590Srgrimes#endif /* not lint */
371590Srgrimes
381590Srgrimes#include <sys/param.h>
3998552Smarkm#include <sys/mount.h>
401590Srgrimes#include <sys/stat.h>
411590Srgrimes
421590Srgrimes#include <fs/msdosfs/msdosfsmount.h>
431590Srgrimes
4498552Smarkm#include <ctype.h>
451590Srgrimes#include <err.h>
461590Srgrimes#include <grp.h>
471590Srgrimes#include <locale.h>
4898552Smarkm#include <pwd.h>
491590Srgrimes#include <stdio.h>
5098552Smarkm/* must be after stdio to declare fparseln */
5198552Smarkm#include <libutil.h>
5298552Smarkm#include <stdlib.h>
531590Srgrimes#include <string.h>
541590Srgrimes#include <sysexits.h>
551590Srgrimes#include <unistd.h>
561590Srgrimes
571590Srgrimes#include "mntopts.h"
581590Srgrimes
5974575Sache/*
6053948Sache * XXX - no way to specify "foo=<bar>"-type options; that's what we'd
611590Srgrimes * want for "-u", "-g", "-m", "-L", and "-W".
621590Srgrimes */
631590Srgrimesstatic struct mntopt mopts[] = {
641590Srgrimes	MOPT_STDOPTS,
651590Srgrimes	MOPT_FORCE,
661590Srgrimes	MOPT_SYNC,
671590Srgrimes	MOPT_UPDATE,
681590Srgrimes#ifdef MSDOSFSMNT_GEMDOSFS
691590Srgrimes	{ "gemdosfs", 0, MSDOSFSMNT_GEMDOSFS, 1 },
701590Srgrimes#endif
711590Srgrimes	{ "shortnames", 0, MSDOSFSMNT_SHORTNAME, 1 },
721590Srgrimes	{ "longnames", 0, MSDOSFSMNT_LONGNAME, 1 },
7372091Sasmodai	{ "nowin95", 0, MSDOSFSMNT_NOWIN95, 1 },
741590Srgrimes	{ NULL }
751590Srgrimes};
761590Srgrimes
771590Srgrimesstatic gid_t	a_gid(char *);
781590Srgrimesstatic uid_t	a_uid(char *);
791590Srgrimesstatic mode_t	a_mask(char *);
801590Srgrimesstatic void	usage(void) __dead2;
811590Srgrimesstatic void     load_u2wtable(struct msdosfs_args *, char *);
821590Srgrimesstatic void     load_ultable(struct msdosfs_args *, char *);
83227175Sed
84227175Sedint
85227175Sedmain(argc, argv)
86227175Sed	int argc;
87227175Sed	char **argv;
88227175Sed{
89227175Sed	struct msdosfs_args args;
90227175Sed	struct stat sb;
91227175Sed	int c, mntflags, set_gid, set_uid, set_mask, set_dirmask;
92227175Sed	char *dev, *dir, mntpath[MAXPATHLEN];
93227175Sed
94227175Sed	mntflags = set_gid = set_uid = set_mask = set_dirmask = 0;
95227175Sed	(void)memset(&args, '\0', sizeof(args));
96227175Sed	args.magic = MSDOSFS_ARGSMAGIC;
97227175Sed
98227175Sed	while ((c = getopt(argc, argv, "sl9u:g:m:M:o:L:W:")) != -1) {
99227175Sed		switch (c) {
100227175Sed#ifdef MSDOSFSMNT_GEMDOSFS
101227175Sed		case 'G':
102227175Sed			args.flags |= MSDOSFSMNT_GEMDOSFS;
103227175Sed			break;
104227175Sed#endif
105227175Sed		case 's':
106319257Sasomers			args.flags |= MSDOSFSMNT_SHORTNAME;
1071590Srgrimes			break;
1081590Srgrimes		case 'l':
1091590Srgrimes			args.flags |= MSDOSFSMNT_LONGNAME;
1101590Srgrimes			break;
111227175Sed		case '9':
112227175Sed			args.flags |= MSDOSFSMNT_NOWIN95;
113227175Sed			break;
114227175Sed		case 'u':
1151590Srgrimes			args.uid = a_uid(optarg);
116227175Sed			set_uid = 1;
11798552Smarkm			break;
1181590Srgrimes		case 'g':
11998552Smarkm			args.gid = a_gid(optarg);
1201590Srgrimes			set_gid = 1;
1211590Srgrimes			break;
1221590Srgrimes		case 'm':
1231590Srgrimes			args.mask = a_mask(optarg);
1241590Srgrimes			set_mask = 1;
1251590Srgrimes			break;
1261590Srgrimes		case 'M':
1271590Srgrimes			args.dirmask = a_mask(optarg);
1281590Srgrimes			set_dirmask = 1;
1291590Srgrimes			break;
1301590Srgrimes		case 'L':
1311590Srgrimes			load_ultable(&args, optarg);
1321590Srgrimes			args.flags |= MSDOSFSMNT_ULTABLE;
1331590Srgrimes			break;
1341590Srgrimes		case 'W':
1351590Srgrimes			load_u2wtable(&args, optarg);
1361590Srgrimes			args.flags |= MSDOSFSMNT_U2WTABLE;
1371590Srgrimes			break;
138319257Sasomers		case 'o':
1391590Srgrimes			getmntopts(optarg, mopts, &mntflags, &args.flags);
1401590Srgrimes			break;
1411590Srgrimes		case '?':
1421590Srgrimes		default:
1431590Srgrimes			usage();
1441590Srgrimes			break;
1451590Srgrimes		}
1461590Srgrimes	}
1471590Srgrimes
14893481Sjmallett	if (optind + 2 != argc)
14993481Sjmallett		usage();
15093481Sjmallett
15198552Smarkm	if (set_mask && !set_dirmask) {
15298552Smarkm		args.dirmask = args.mask;
15393481Sjmallett		set_dirmask = 1;
15493481Sjmallett	}
15593481Sjmallett	else if (set_dirmask && !set_mask) {
15693481Sjmallett		args.mask = args.dirmask;
15793481Sjmallett		set_mask = 1;
15893481Sjmallett	}
15993481Sjmallett
16093481Sjmallett	dev = argv[optind];
16193481Sjmallett	dir = argv[optind + 1];
16293481Sjmallett
16393481Sjmallett	/*
16493481Sjmallett	 * Resolve the mountpoint with realpath(3) and remove unnecessary
16593481Sjmallett	 * slashes from the devicename if there are any.
16693481Sjmallett	 */
16793481Sjmallett	(void)checkpath(dir, mntpath);
16893481Sjmallett	(void)rmslashes(dev, dev);
1691590Srgrimes
1701590Srgrimes	args.fspec = dev;
1711590Srgrimes	args.export.ex_root = -2;	/* unchecked anyway on DOS fs */
1721590Srgrimes	if (mntflags & MNT_RDONLY)
17398552Smarkm		args.export.ex_flags = MNT_EXRDONLY;
1741590Srgrimes	else
17598552Smarkm		args.export.ex_flags = 0;
17698552Smarkm	if (!set_gid || !set_uid || !set_mask) {
17798552Smarkm		if (stat(mntpath, &sb) == -1)
17898552Smarkm			err(EX_OSERR, "stat %s", mntpath);
17998552Smarkm
1801590Srgrimes		if (!set_uid)
1811590Srgrimes			args.uid = sb.st_uid;
1821590Srgrimes		if (!set_gid)
1831590Srgrimes			args.gid = sb.st_gid;
1841590Srgrimes		if (!set_mask)
1851590Srgrimes			args.mask = args.dirmask =
1861590Srgrimes				sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
1871590Srgrimes	}
1881590Srgrimes
1891590Srgrimes	if (mount("msdosfs", mntpath, mntflags, &args) < 0)
1901590Srgrimes		err(EX_OSERR, "%s", dev);
191102944Sdwmalone
1921590Srgrimes	exit (0);
1931590Srgrimes}
1941590Srgrimes
1951590Srgrimesgid_t
1961590Srgrimesa_gid(s)
1971590Srgrimes	char *s;
1981590Srgrimes{
1991590Srgrimes	struct group *gr;
2001590Srgrimes	char *gname;
2011590Srgrimes	gid_t gid;
2021590Srgrimes
2031590Srgrimes	if ((gr = getgrnam(s)) != NULL)
2041590Srgrimes		gid = gr->gr_gid;
2051590Srgrimes	else {
2061590Srgrimes		for (gname = s; *s && isdigit(*s); ++s);
2071590Srgrimes		if (!*s)
2081590Srgrimes			gid = atoi(gname);
2091590Srgrimes		else
2101590Srgrimes			errx(EX_NOUSER, "unknown group id: %s", gname);
211319257Sasomers	}
2121590Srgrimes	return (gid);
2131590Srgrimes}
2141590Srgrimes
2151590Srgrimesuid_t
2161590Srgrimesa_uid(s)
2171590Srgrimes	char *s;
2181590Srgrimes{
2191590Srgrimes	struct passwd *pw;
2201590Srgrimes	char *uname;
2211590Srgrimes	uid_t uid;
2221590Srgrimes
2231590Srgrimes	if ((pw = getpwnam(s)) != NULL)
2241590Srgrimes		uid = pw->pw_uid;
2251590Srgrimes	else {
2261590Srgrimes		for (uname = s; *s && isdigit(*s); ++s);
2271590Srgrimes		if (!*s)
2281590Srgrimes			uid = atoi(uname);
2291590Srgrimes		else
2301590Srgrimes			errx(EX_NOUSER, "unknown user id: %s", uname);
2311590Srgrimes	}
2321590Srgrimes	return (uid);
2331590Srgrimes}
2341590Srgrimes
2351590Srgrimesmode_t
2361590Srgrimesa_mask(s)
2371590Srgrimes	char *s;
2381590Srgrimes{
2391590Srgrimes	int done, rv;
2401590Srgrimes	char *ep;
2411590Srgrimes
2421590Srgrimes	done = 0;
2431590Srgrimes	rv = -1;
2441590Srgrimes	if (*s >= '0' && *s <= '7') {
2451590Srgrimes		done = 1;
2461590Srgrimes		rv = strtol(optarg, &ep, 8);
2471590Srgrimes	}
2481590Srgrimes	if (!done || rv < 0 || *ep)
2491590Srgrimes		errx(EX_USAGE, "invalid file mode: %s", s);
2501590Srgrimes	return (rv);
25193481Sjmallett}
25293481Sjmallett
2531590Srgrimesvoid
2541590Srgrimesusage()
2551590Srgrimes{
2561590Srgrimes	fprintf(stderr, "%s\n%s\n",
2571590Srgrimes	"usage: mount_msdosfs [-o options] [-u user] [-g group] [-m mask]",
2581590Srgrimes	"                     [-s] [-l] [-9] [-L locale] [-W table] bdev dir");
2591590Srgrimes	exit(EX_USAGE);
2601590Srgrimes}
2611590Srgrimes
2621590Srgrimesvoid
2631590Srgrimesload_u2wtable (pargs, name)
264319257Sasomers	struct msdosfs_args *pargs;
2651590Srgrimes	char *name;
2661590Srgrimes{
2671590Srgrimes	FILE *f;
2681590Srgrimes	int i, j, code[8];
2691590Srgrimes	size_t line = 0;
2701590Srgrimes	char buf[128];
2711590Srgrimes	char *fn, *s, *p;
2721590Srgrimes
273319257Sasomers	if (*name == '/')
2741590Srgrimes		fn = name;
275319257Sasomers	else {
2761590Srgrimes		snprintf(buf, sizeof(buf), "/usr/libdata/msdosfs/%s", name);
2771590Srgrimes		buf[127] = '\0';
2781590Srgrimes		fn = buf;
2791590Srgrimes	}
2801590Srgrimes	if ((f = fopen(fn, "r")) == NULL)
2811590Srgrimes		err(EX_NOINPUT, "%s", fn);
2821590Srgrimes	p = NULL;
2831590Srgrimes	for (i = 0; i < 16; i++) {
2841590Srgrimes		do {
2851590Srgrimes			if (p != NULL) free(p);
2861590Srgrimes			if ((p = s = fparseln(f, NULL, &line, NULL, 0)) == NULL)
2871590Srgrimes				errx(EX_DATAERR, "can't read u2w table row %d near line %d", i, line);
2881590Srgrimes			while (isspace((unsigned char)*s))
2891590Srgrimes				s++;
2901590Srgrimes		} while (*s == '\0');
2911590Srgrimes		if (sscanf(s, "%i%i%i%i%i%i%i%i",
2921590Srgrimescode, code + 1, code + 2, code + 3, code + 4, code + 5, code + 6, code + 7) != 8)
2931590Srgrimes			errx(EX_DATAERR, "u2w table: missing item(s) in row %d, line %d", i, line);
2941590Srgrimes		for (j = 0; j < 8; j++)
2951590Srgrimes			pargs->u2w[i * 8 + j] = code[j];
2961590Srgrimes	}
2971590Srgrimes	for (i = 0; i < 16; i++) {
298319257Sasomers		do {
2991590Srgrimes			free(p);
3001590Srgrimes			if ((p = s = fparseln(f, NULL, &line, NULL, 0)) == NULL)
3011590Srgrimes				errx(EX_DATAERR, "can't read d2u table row %d near line %d", i, line);
3021590Srgrimes			while (isspace((unsigned char)*s))
3031590Srgrimes				s++;
3041590Srgrimes		} while (*s == '\0');
3051590Srgrimes		if (sscanf(s, "%i%i%i%i%i%i%i%i",
3061590Srgrimescode, code + 1, code + 2, code + 3, code + 4, code + 5, code + 6, code + 7) != 8)
3071590Srgrimes			errx(EX_DATAERR, "d2u table: missing item(s) in row %d, line %d", i, line);
3081590Srgrimes		for (j = 0; j < 8; j++)
3091590Srgrimes			pargs->d2u[i * 8 + j] = code[j];
3101590Srgrimes	}
311319257Sasomers	for (i = 0; i < 16; i++) {
312319257Sasomers		do {
313319257Sasomers			free(p);
3141590Srgrimes			if ((p = s = fparseln(f, NULL, &line, NULL, 0)) == NULL)
315319257Sasomers				errx(EX_DATAERR, "can't read u2d table row %d near line %d", i, line);
316319257Sasomers			while (isspace((unsigned char)*s))
317319257Sasomers				s++;
318319257Sasomers		} while (*s == '\0');
3191590Srgrimes		if (sscanf(s, "%i%i%i%i%i%i%i%i",
3201590Srgrimescode, code + 1, code + 2, code + 3, code + 4, code + 5, code + 6, code + 7) != 8)
3211590Srgrimes			errx(EX_DATAERR, "u2d table: missing item(s) in row %d, line %d", i, line);
3221590Srgrimes		for (j = 0; j < 8; j++)
3231590Srgrimes			pargs->u2d[i * 8 + j] = code[j];
3241590Srgrimes	}
32598552Smarkm	free(p);
3261590Srgrimes	fclose(f);
32798552Smarkm}
328319257Sasomers
32998552Smarkmvoid
33098552Smarkmload_ultable (pargs, name)
33198552Smarkm	struct msdosfs_args *pargs;
33298552Smarkm	char *name;
333319257Sasomers{
3341590Srgrimes	int i;
335319257Sasomers
3361590Srgrimes	if (setlocale(LC_CTYPE, name) == NULL)
3371590Srgrimes		err(EX_CONFIG, "%s", name);
3381590Srgrimes	for (i = 0; i < 128; i++) {
3391590Srgrimes		pargs->ul[i] = tolower(i | 0x80);
3401590Srgrimes		pargs->lu[i] = toupper(i | 0x80);
3411590Srgrimes	}
342319257Sasomers}
3431590Srgrimes