mount_msdosfs.c revision 121363
119370Spst/*	$NetBSD: mount_msdos.c,v 1.18 1997/09/16 12:24:18 lukem Exp $	*/
219370Spst
3130809Smarcel/*
4130809Smarcel * Copyright (c) 1994 Christopher G. Demetriou
5130809Smarcel * All rights reserved.
6130809Smarcel *
798948Sobrien * Redistribution and use in source and binary forms, with or without
819370Spst * modification, are permitted provided that the following conditions
998948Sobrien * are met:
1098948Sobrien * 1. Redistributions of source code must retain the above copyright
1198948Sobrien *    notice, this list of conditions and the following disclaimer.
1298948Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1319370Spst *    notice, this list of conditions and the following disclaimer in the
1498948Sobrien *    documentation and/or other materials provided with the distribution.
1598948Sobrien * 3. All advertising materials mentioning features or use of this software
1698948Sobrien *    must display the following acknowledgement:
1798948Sobrien *      This product includes software developed by Christopher G. Demetriou.
1819370Spst * 4. The name of the author may not be used to endorse or promote products
1998948Sobrien *    derived from this software without specific prior written permission
2098948Sobrien *
2198948Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2298948Sobrien * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2319370Spst * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2419370Spst * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2519370Spst * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2619370Spst * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2719370Spst * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2898948Sobrien * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2998948Sobrien * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3019370Spst * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3119370Spst */
3219370Spst
3319370Spst#ifndef lint
3419370Spststatic const char rcsid[] =
3519370Spst  "$FreeBSD: head/sbin/mount_msdosfs/mount_msdosfs.c 121363 2003-10-22 20:11:42Z trhodes $";
3619370Spst#endif /* not lint */
3719370Spst
3898948Sobrien#include <sys/param.h>
3998948Sobrien#include <sys/mount.h>
4019370Spst#include <sys/stat.h>
41130809Smarcel#include <sys/module.h>
42130809Smarcel#include <sys/iconv.h>
43130809Smarcel#include <sys/linker.h>
4419370Spst
4519370Spst#include <fs/msdosfs/msdosfsmount.h>
4619370Spst
4719370Spst#include <ctype.h>
4819370Spst#include <err.h>
4919370Spst#include <grp.h>
5019370Spst#include <locale.h>
5119370Spst#include <pwd.h>
5298948Sobrien#include <stdio.h>
5398948Sobrien/* must be after stdio to declare fparseln */
5498948Sobrien#include <libutil.h>
5598948Sobrien#include <stdlib.h>
5698948Sobrien#include <string.h>
5798948Sobrien#include <sysexits.h>
58130809Smarcel#include <unistd.h>
59130809Smarcel#include "mntopts.h"
60130809Smarcel
6198948Sobrien#define TRANSITION_PERIOD_HACK
6298948Sobrien
6346283Sdfr/*
6446283Sdfr * XXX - no way to specify "foo=<bar>"-type options; that's what we'd
6546283Sdfr * want for "-u", "-g", "-m", "-M", "-L", "-D", and "-W".
6646283Sdfr */
6746283Sdfrstatic struct mntopt mopts[] = {
6846283Sdfr	MOPT_STDOPTS,
69130809Smarcel	MOPT_FORCE,
70130809Smarcel	MOPT_SYNC,
71130809Smarcel	MOPT_UPDATE,
7298948Sobrien#ifdef MSDOSFSMNT_GEMDOSFS
7398948Sobrien	{ "gemdosfs", 0, MSDOSFSMNT_GEMDOSFS, 1 },
7498948Sobrien#endif
75130809Smarcel	{ "shortnames", 0, MSDOSFSMNT_SHORTNAME, 1 },
76130809Smarcel	{ "longnames", 0, MSDOSFSMNT_LONGNAME, 1 },
77130809Smarcel	{ "nowin95", 0, MSDOSFSMNT_NOWIN95, 1 },
7898948Sobrien	{ NULL }
79130809Smarcel};
8046283Sdfr
8146283Sdfrstatic gid_t	a_gid(char *);
8246283Sdfrstatic uid_t	a_uid(char *);
8346283Sdfrstatic mode_t	a_mask(char *);
8498948Sobrienstatic void	usage(void) __dead2;
8546283Sdfrstatic int	set_charset(struct msdosfs_args *);
8646283Sdfr
8746283Sdfrint
8846283Sdfrmain(argc, argv)
8998948Sobrien	int argc;
9046283Sdfr	char **argv;
9198948Sobrien{
9298948Sobrien	struct msdosfs_args args;
9346283Sdfr	struct stat sb;
9498948Sobrien	int c, mntflags, set_gid, set_uid, set_mask, set_dirmask;
9598948Sobrien	char *dev, *dir, mntpath[MAXPATHLEN], *csp;
9619370Spst
97130809Smarcel	mntflags = set_gid = set_uid = set_mask = set_dirmask = 0;
9898948Sobrien	(void)memset(&args, '\0', sizeof(args));
9998948Sobrien	args.magic = MSDOSFS_ARGSMAGIC;
10098948Sobrien
10198948Sobrien	args.cs_win = NULL;
10298948Sobrien	args.cs_dos = NULL;
10398948Sobrien	args.cs_local = NULL;
10498948Sobrien#ifdef TRANSITION_PERIOD_HACK
10598948Sobrien	while ((c = getopt(argc, argv, "sl9u:g:m:M:o:L:D:W:")) != -1) {
10698948Sobrien#else
10798948Sobrien	while ((c = getopt(argc, argv, "sl9u:g:m:M:o:L:D:")) != -1) {
10898948Sobrien#endif
10998948Sobrien		switch (c) {
11098948Sobrien#ifdef MSDOSFSMNT_GEMDOSFS
11198948Sobrien		case 'G':
11298948Sobrien			args.flags |= MSDOSFSMNT_GEMDOSFS;
11398948Sobrien			break;
11498948Sobrien#endif
11598948Sobrien		case 's':
11698948Sobrien			args.flags |= MSDOSFSMNT_SHORTNAME;
11798948Sobrien			break;
11898948Sobrien		case 'l':
11998948Sobrien			args.flags |= MSDOSFSMNT_LONGNAME;
12019370Spst			break;
12119370Spst		case '9':
12219370Spst			args.flags |= MSDOSFSMNT_NOWIN95;
12398948Sobrien			break;
12419370Spst		case 'u':
12519370Spst			args.uid = a_uid(optarg);
12619370Spst			set_uid = 1;
12719370Spst			break;
12819370Spst		case 'g':
12919370Spst			args.gid = a_gid(optarg);
13019370Spst			set_gid = 1;
13119370Spst			break;
13219370Spst		case 'm':
13319370Spst			args.mask = a_mask(optarg);
13419370Spst			set_mask = 1;
13519370Spst			break;
13619370Spst		case 'M':
13719370Spst			args.dirmask = a_mask(optarg);
13819370Spst			set_dirmask = 1;
13919370Spst			break;
14019370Spst		case 'L':
14119370Spst			if (setlocale(LC_CTYPE, optarg) == NULL)
14219370Spst				err(EX_CONFIG, "%s", optarg);
14319370Spst			csp = strchr(optarg,'.');
14419370Spst			if (!csp)
14519370Spst				err(EX_CONFIG, "%s", optarg);
14619370Spst			args.cs_local = malloc(ICONV_CSNMAXLEN);
14719370Spst			if (args.cs_local == NULL)
14819370Spst				err(EX_OSERR, "malloc()");
14998948Sobrien			strncpy(args.cs_local,
15019370Spst			    kiconv_quirkcs(csp + 1, KICONV_VENDOR_MICSFT),
15119370Spst			    ICONV_CSNMAXLEN);
15219370Spst			break;
153130809Smarcel		case 'D':
15419370Spst			args.cs_dos = malloc(ICONV_CSNMAXLEN);
15519370Spst			if (args.cs_dos == NULL)
15619370Spst				err(EX_OSERR, "malloc()");
157130809Smarcel			strncpy(args.cs_dos, optarg, ICONV_CSNMAXLEN);
158130809Smarcel			break;
159130809Smarcel		case 'o':
160130809Smarcel			getmntopts(optarg, mopts, &mntflags, &args.flags);
161130809Smarcel			break;
162130809Smarcel#ifdef TRANSITION_PERIOD_HACK
163130809Smarcel		case 'W':
164130809Smarcel			args.cs_local = malloc(ICONV_CSNMAXLEN);
16519370Spst			if (args.cs_local == NULL)
16619370Spst				err(EX_OSERR, "malloc()");
167130809Smarcel			args.cs_dos = malloc(ICONV_CSNMAXLEN);
16819370Spst			if (args.cs_dos == NULL)
169130809Smarcel				err(EX_OSERR, "malloc()");
170130809Smarcel			if (strcmp(optarg, "iso22dos") == 0) {
171130809Smarcel				strcpy(args.cs_local, "ISO8859-2");
172130809Smarcel				strcpy(args.cs_dos, "CP852");
17319370Spst			} else if (strcmp(optarg, "iso72dos") == 0) {
17419370Spst				strcpy(args.cs_local, "ISO8859-7");
17519370Spst				strcpy(args.cs_dos, "CP737");
17619370Spst			} else if (strcmp(optarg, "koi2dos") == 0) {
17719370Spst				strcpy(args.cs_local, "KOI8-R");
17819370Spst				strcpy(args.cs_dos, "CP866");
17919370Spst			} else if (strcmp(optarg, "koi8u2dos") == 0) {
18019370Spst				strcpy(args.cs_local, "KOI8-U");
18119370Spst				strcpy(args.cs_dos, "CP866");
18219370Spst			} else {
18319370Spst				err(EX_NOINPUT, "%s", optarg);
18419370Spst			}
18519370Spst			break;
18619370Spst#endif /* TRANSITION_PERIOD_HACK */
18719370Spst		case '?':
18819370Spst		default:
18919370Spst			usage();
19019370Spst			break;
19119370Spst		}
19219370Spst	}
19319370Spst
19498948Sobrien	if (optind + 2 != argc)
19598948Sobrien		usage();
19698948Sobrien
19798948Sobrien	if (set_mask && !set_dirmask) {
198130809Smarcel		args.dirmask = args.mask;
199130809Smarcel		set_dirmask = 1;
200130809Smarcel	}
20146283Sdfr	else if (set_dirmask && !set_mask) {
20298948Sobrien		args.mask = args.dirmask;
20398948Sobrien		set_mask = 1;
20446283Sdfr	}
205130809Smarcel
206130809Smarcel	dev = argv[optind];
207130809Smarcel	dir = argv[optind + 1];
208130809Smarcel
209130809Smarcel	if (args.cs_local) {
210130809Smarcel		if (set_charset(&args) == -1)
211130809Smarcel			err(EX_OSERR, "msdosfs_iconv");
212130809Smarcel		args.flags |= MSDOSFSMNT_KICONV;
213130809Smarcel	} else if (args.cs_dos) {
214130809Smarcel		if ((args.cs_local = malloc(ICONV_CSNMAXLEN)) == NULL)
215130809Smarcel			err(EX_OSERR, "malloc()");
216130809Smarcel		strcpy(args.cs_local, "ISO8859-1");
217130809Smarcel		if (set_charset(&args) == -1)
218130809Smarcel			err(EX_OSERR, "msdosfs_iconv");
219130809Smarcel		args.flags |= MSDOSFSMNT_KICONV;
220130809Smarcel	}
221130809Smarcel
222130809Smarcel	/*
223130809Smarcel	 * Resolve the mountpoint with realpath(3) and remove unnecessary
224130809Smarcel	 * slashes from the devicename if there are any.
225130809Smarcel	 */
226130809Smarcel	(void)checkpath(dir, mntpath);
227130809Smarcel	(void)rmslashes(dev, dev);
228130809Smarcel
229130809Smarcel	args.fspec = dev;
230130809Smarcel	args.export.ex_root = -2;	/* unchecked anyway on DOS fs */
231130809Smarcel	if (mntflags & MNT_RDONLY)
232130809Smarcel		args.export.ex_flags = MNT_EXRDONLY;
233130809Smarcel	else
234130809Smarcel		args.export.ex_flags = 0;
235130809Smarcel	if (!set_gid || !set_uid || !set_mask) {
236130809Smarcel		if (stat(mntpath, &sb) == -1)
237130809Smarcel			err(EX_OSERR, "stat %s", mntpath);
238130809Smarcel
23919370Spst		if (!set_uid)
24019370Spst			args.uid = sb.st_uid;
24119370Spst		if (!set_gid)
24219370Spst			args.gid = sb.st_gid;
24319370Spst		if (!set_mask)
24419370Spst			args.mask = args.dirmask =
245130809Smarcel				sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
246130809Smarcel	}
247130809Smarcel
248130809Smarcel	if (mount("msdosfs", mntpath, mntflags, &args) < 0)
249130809Smarcel		err(EX_OSERR, "%s", dev);
250130809Smarcel
251130809Smarcel	exit (0);
252130809Smarcel}
253130809Smarcel
25419370Spstgid_t
25598948Sobriena_gid(s)
25698948Sobrien	char *s;
25798948Sobrien{
25846283Sdfr	struct group *gr;
259130809Smarcel	char *gname;
26046283Sdfr	gid_t gid;
26198948Sobrien
26298948Sobrien	if ((gr = getgrnam(s)) != NULL)
26398948Sobrien		gid = gr->gr_gid;
26498948Sobrien	else {
26598948Sobrien		for (gname = s; *s && isdigit(*s); ++s);
26698948Sobrien		if (!*s)
26798948Sobrien			gid = atoi(gname);
26898948Sobrien		else
26998948Sobrien			errx(EX_NOUSER, "unknown group id: %s", gname);
27098948Sobrien	}
27198948Sobrien	return (gid);
27219370Spst}
27398948Sobrien
27498948Sobrienuid_t
27598948Sobriena_uid(s)
27698948Sobrien	char *s;
27798948Sobrien{
27819370Spst	struct passwd *pw;
279130809Smarcel	char *uname;
28098948Sobrien	uid_t uid;
281130809Smarcel
28298948Sobrien	if ((pw = getpwnam(s)) != NULL)
28398948Sobrien		uid = pw->pw_uid;
28498948Sobrien	else {
28598948Sobrien		for (uname = s; *s && isdigit(*s); ++s);
28698948Sobrien		if (!*s)
28798948Sobrien			uid = atoi(uname);
28898948Sobrien		else
28998948Sobrien			errx(EX_NOUSER, "unknown user id: %s", uname);
29098948Sobrien	}
29198948Sobrien	return (uid);
29298948Sobrien}
29398948Sobrien
29498948Sobrienmode_t
29598948Sobriena_mask(s)
29698948Sobrien	char *s;
29798948Sobrien{
29898948Sobrien	int done, rv;
29998948Sobrien	char *ep;
30098948Sobrien
30198948Sobrien	done = 0;
30298948Sobrien	rv = -1;
303130809Smarcel	if (*s >= '0' && *s <= '7') {
30498948Sobrien		done = 1;
30598948Sobrien		rv = strtol(optarg, &ep, 8);
30698948Sobrien	}
307130809Smarcel	if (!done || rv < 0 || *ep)
308130809Smarcel		errx(EX_USAGE, "invalid file mode: %s", s);
309130809Smarcel	return (rv);
310130809Smarcel}
311130809Smarcel
31298948Sobrienvoid
31398948Sobrienusage()
31498948Sobrien{
31598948Sobrien#ifdef TRANSITION_PERIOD_HACK
31619370Spst	fprintf(stderr, "%s\n%s\n%s\n",
31719370Spst	"usage: mount_msdosfs [-o options] [-u user] [-g group] [-m mask] [-M mask]",
31819370Spst	"                     [-s] [-l] [-9] [-L locale] [-D dos-codepage] [-W table]",
31919370Spst	"                     bdev dir");
32019370Spst#else
32119370Spst	fprintf(stderr, "%s\n%s\n",
32219370Spst	"usage: mount_msdosfs [-o options] [-u user] [-g group] [-m mask] [-M mask]",
32398948Sobrien	"                     [-s] [-l] [-9] [-L locale] [-D dos-codepage] bdev dir");
32419370Spst#endif
32519370Spst	exit(EX_USAGE);
32619370Spst}
32719370Spst
32819370Spstint
32919370Spstset_charset(struct msdosfs_args *args)
33019370Spst{
33119370Spst	int error;
33219370Spst
33319370Spst	if (modfind("msdosfs_iconv") < 0)
33419370Spst		if (kldload("msdosfs_iconv") < 0 || modfind("msdosfs_iconv") < 0) {
335130809Smarcel			warnx( "cannot find or load \"msdosfs_iconv\" kernel module");
33619370Spst			return (-1);
33719370Spst		}
33819370Spst
339130809Smarcel	if ((args->cs_win = malloc(ICONV_CSNMAXLEN)) == NULL)
34019370Spst		return (-1);
34119370Spst	strncpy(args->cs_win, ENCODING_UNICODE, ICONV_CSNMAXLEN);
342130809Smarcel	error = kiconv_add_xlat16_cspair(args->cs_win, args->cs_local, 0);
34319370Spst	if (error)
34419370Spst		return (-1);
34519370Spst	error = kiconv_add_xlat16_cspair(args->cs_local, args->cs_win, 0);
346130809Smarcel	if (error)
34719370Spst		return (-1);
34819370Spst	if (args->cs_dos) {
34919370Spst		error = kiconv_add_xlat16_cspair(args->cs_dos, args->cs_local, KICONV_FROM_UPPER);
35019370Spst		if (error)
351130809Smarcel			return (-1);
352130809Smarcel		error = kiconv_add_xlat16_cspair(args->cs_local, args->cs_dos, KICONV_LOWER);
353130809Smarcel		if (error)
354130809Smarcel			return (-1);
355130809Smarcel	} else {
356130809Smarcel		if ((args->cs_dos = malloc(ICONV_CSNMAXLEN)) == NULL)
357130809Smarcel			return (-1);
358130809Smarcel		strcpy(args->cs_dos, args->cs_local);
359130809Smarcel		error = kiconv_add_xlat16_cspair(args->cs_local, args->cs_local,
360130809Smarcel				KICONV_FROM_UPPER | KICONV_LOWER);
361130809Smarcel		if (error)
362130809Smarcel			return (-1);
363130809Smarcel	}
364130809Smarcel
365130809Smarcel	return (0);
366130809Smarcel}
36719370Spst