mount_msdosfs.c revision 134565
133549Sjkh/*	$NetBSD: mount_msdos.c,v 1.18 1997/09/16 12:24:18 lukem Exp $	*/
233549Sjkh
32892Sdfr/*
42892Sdfr * Copyright (c) 1994 Christopher G. Demetriou
52892Sdfr * All rights reserved.
62892Sdfr *
72892Sdfr * Redistribution and use in source and binary forms, with or without
82892Sdfr * modification, are permitted provided that the following conditions
92892Sdfr * are met:
102892Sdfr * 1. Redistributions of source code must retain the above copyright
112892Sdfr *    notice, this list of conditions and the following disclaimer.
122892Sdfr * 2. Redistributions in binary form must reproduce the above copyright
132892Sdfr *    notice, this list of conditions and the following disclaimer in the
142892Sdfr *    documentation and/or other materials provided with the distribution.
152892Sdfr * 3. All advertising materials mentioning features or use of this software
162892Sdfr *    must display the following acknowledgement:
172892Sdfr *      This product includes software developed by Christopher G. Demetriou.
182892Sdfr * 4. The name of the author may not be used to endorse or promote products
192892Sdfr *    derived from this software without specific prior written permission
202892Sdfr *
212892Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
222892Sdfr * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
232892Sdfr * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
242892Sdfr * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
252892Sdfr * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
262892Sdfr * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
272892Sdfr * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
282892Sdfr * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
292892Sdfr * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
302892Sdfr * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
312892Sdfr */
322892Sdfr
332892Sdfr#ifndef lint
3415771Swollmanstatic const char rcsid[] =
3550476Speter  "$FreeBSD: head/sbin/mount_msdosfs/mount_msdosfs.c 134565 2004-08-31 05:19:57Z trhodes $";
362892Sdfr#endif /* not lint */
372892Sdfr
382892Sdfr#include <sys/param.h>
392892Sdfr#include <sys/mount.h>
402892Sdfr#include <sys/stat.h>
41120492Sfjoe#include <sys/iconv.h>
42121363Strhodes#include <sys/linker.h>
43121429Strhodes#include <sys/module.h>
4423335Sbde
4577162Sru#include <fs/msdosfs/msdosfsmount.h>
4623335Sbde
472892Sdfr#include <ctype.h>
482892Sdfr#include <err.h>
492892Sdfr#include <grp.h>
5033761Sache#include <locale.h>
512892Sdfr#include <pwd.h>
522892Sdfr#include <stdio.h>
5355613Sache/* must be after stdio to declare fparseln */
5455613Sache#include <libutil.h>
552892Sdfr#include <stdlib.h>
562892Sdfr#include <string.h>
5715771Swollman#include <sysexits.h>
582892Sdfr#include <unistd.h>
59121429Strhodes
602892Sdfr#include "mntopts.h"
612892Sdfr
62120492Sfjoe#define TRANSITION_PERIOD_HACK
63120492Sfjoe
6448002Sjkh/*
6548002Sjkh * XXX - no way to specify "foo=<bar>"-type options; that's what we'd
66121007Sfjoe * want for "-u", "-g", "-m", "-M", "-L", "-D", and "-W".
6748002Sjkh */
6815771Swollmanstatic struct mntopt mopts[] = {
692892Sdfr	MOPT_STDOPTS,
7028731Sbde	MOPT_FORCE,
7128731Sbde	MOPT_SYNC,
7228731Sbde	MOPT_UPDATE,
7348002Sjkh	{ "shortnames", 0, MSDOSFSMNT_SHORTNAME, 1 },
7448002Sjkh	{ "longnames", 0, MSDOSFSMNT_LONGNAME, 1 },
7548002Sjkh	{ "nowin95", 0, MSDOSFSMNT_NOWIN95, 1 },
762892Sdfr	{ NULL }
772892Sdfr};
782892Sdfr
7992882Simpstatic gid_t	a_gid(char *);
8092882Simpstatic uid_t	a_uid(char *);
8192882Simpstatic mode_t	a_mask(char *);
8292882Simpstatic void	usage(void) __dead2;
83120492Sfjoestatic int	set_charset(struct msdosfs_args *);
842892Sdfr
852892Sdfrint
86121373Strhodesmain(int argc, char **argv)
872892Sdfr{
882892Sdfr	struct msdosfs_args args;
892892Sdfr	struct stat sb;
90118837Strhodes	int c, mntflags, set_gid, set_uid, set_mask, set_dirmask;
91120492Sfjoe	char *dev, *dir, mntpath[MAXPATHLEN], *csp;
922892Sdfr
93118837Strhodes	mntflags = set_gid = set_uid = set_mask = set_dirmask = 0;
942892Sdfr	(void)memset(&args, '\0', sizeof(args));
9533549Sjkh	args.magic = MSDOSFS_ARGSMAGIC;
962892Sdfr
97120492Sfjoe	args.cs_win = NULL;
98120492Sfjoe	args.cs_dos = NULL;
99120492Sfjoe	args.cs_local = NULL;
100120492Sfjoe#ifdef TRANSITION_PERIOD_HACK
101120492Sfjoe	while ((c = getopt(argc, argv, "sl9u:g:m:M:o:L:D:W:")) != -1) {
102120492Sfjoe#else
103120492Sfjoe	while ((c = getopt(argc, argv, "sl9u:g:m:M:o:L:D:")) != -1) {
104120492Sfjoe#endif
1052892Sdfr		switch (c) {
10633549Sjkh		case 's':
10733549Sjkh			args.flags |= MSDOSFSMNT_SHORTNAME;
10833549Sjkh			break;
10933549Sjkh		case 'l':
11033549Sjkh			args.flags |= MSDOSFSMNT_LONGNAME;
11133549Sjkh			break;
11233549Sjkh		case '9':
11333549Sjkh			args.flags |= MSDOSFSMNT_NOWIN95;
11433549Sjkh			break;
1152892Sdfr		case 'u':
1162892Sdfr			args.uid = a_uid(optarg);
1172892Sdfr			set_uid = 1;
1182892Sdfr			break;
1192892Sdfr		case 'g':
1202892Sdfr			args.gid = a_gid(optarg);
1212892Sdfr			set_gid = 1;
1222892Sdfr			break;
1232892Sdfr		case 'm':
1242892Sdfr			args.mask = a_mask(optarg);
1252892Sdfr			set_mask = 1;
1262892Sdfr			break;
127118837Strhodes		case 'M':
128118837Strhodes			args.dirmask = a_mask(optarg);
129118837Strhodes			set_dirmask = 1;
130118837Strhodes			break;
13133761Sache		case 'L':
132120492Sfjoe			if (setlocale(LC_CTYPE, optarg) == NULL)
133120492Sfjoe				err(EX_CONFIG, "%s", optarg);
134120492Sfjoe			csp = strchr(optarg,'.');
135120492Sfjoe			if (!csp)
136120492Sfjoe				err(EX_CONFIG, "%s", optarg);
137120492Sfjoe			args.cs_local = malloc(ICONV_CSNMAXLEN);
138120492Sfjoe			if (args.cs_local == NULL)
139120492Sfjoe				err(EX_OSERR, "malloc()");
140120492Sfjoe			strncpy(args.cs_local,
141120492Sfjoe			    kiconv_quirkcs(csp + 1, KICONV_VENDOR_MICSFT),
142120492Sfjoe			    ICONV_CSNMAXLEN);
14333761Sache			break;
144120492Sfjoe		case 'D':
145120492Sfjoe			args.cs_dos = malloc(ICONV_CSNMAXLEN);
146120492Sfjoe			if (args.cs_dos == NULL)
147120492Sfjoe				err(EX_OSERR, "malloc()");
148120492Sfjoe			strncpy(args.cs_dos, optarg, ICONV_CSNMAXLEN);
14933749Sache			break;
1502892Sdfr		case 'o':
15148002Sjkh			getmntopts(optarg, mopts, &mntflags, &args.flags);
1522892Sdfr			break;
153120492Sfjoe#ifdef TRANSITION_PERIOD_HACK
154120492Sfjoe		case 'W':
155120492Sfjoe			args.cs_local = malloc(ICONV_CSNMAXLEN);
156120492Sfjoe			if (args.cs_local == NULL)
157120492Sfjoe				err(EX_OSERR, "malloc()");
158120492Sfjoe			args.cs_dos = malloc(ICONV_CSNMAXLEN);
159120492Sfjoe			if (args.cs_dos == NULL)
160120492Sfjoe				err(EX_OSERR, "malloc()");
161120492Sfjoe			if (strcmp(optarg, "iso22dos") == 0) {
162120492Sfjoe				strcpy(args.cs_local, "ISO8859-2");
163120492Sfjoe				strcpy(args.cs_dos, "CP852");
164120492Sfjoe			} else if (strcmp(optarg, "iso72dos") == 0) {
165120492Sfjoe				strcpy(args.cs_local, "ISO8859-7");
166120492Sfjoe				strcpy(args.cs_dos, "CP737");
167120492Sfjoe			} else if (strcmp(optarg, "koi2dos") == 0) {
168120492Sfjoe				strcpy(args.cs_local, "KOI8-R");
169120492Sfjoe				strcpy(args.cs_dos, "CP866");
170120492Sfjoe			} else if (strcmp(optarg, "koi8u2dos") == 0) {
171120492Sfjoe				strcpy(args.cs_local, "KOI8-U");
172120492Sfjoe				strcpy(args.cs_dos, "CP866");
173120492Sfjoe			} else {
174120492Sfjoe				err(EX_NOINPUT, "%s", optarg);
175120492Sfjoe			}
176120492Sfjoe			break;
177120492Sfjoe#endif /* TRANSITION_PERIOD_HACK */
1782892Sdfr		case '?':
1792892Sdfr		default:
1802892Sdfr			usage();
1812892Sdfr			break;
1822892Sdfr		}
1832892Sdfr	}
1842892Sdfr
1852892Sdfr	if (optind + 2 != argc)
1862892Sdfr		usage();
1872892Sdfr
188118837Strhodes	if (set_mask && !set_dirmask) {
189118837Strhodes		args.dirmask = args.mask;
190118837Strhodes		set_dirmask = 1;
191118837Strhodes	}
192118837Strhodes	else if (set_dirmask && !set_mask) {
193118837Strhodes		args.mask = args.dirmask;
194118837Strhodes		set_mask = 1;
195118837Strhodes	}
196118837Strhodes
1972892Sdfr	dev = argv[optind];
1982892Sdfr	dir = argv[optind + 1];
1992892Sdfr
200120492Sfjoe	if (args.cs_local) {
201120492Sfjoe		if (set_charset(&args) == -1)
202120492Sfjoe			err(EX_OSERR, "msdosfs_iconv");
203120492Sfjoe		args.flags |= MSDOSFSMNT_KICONV;
204120492Sfjoe	} else if (args.cs_dos) {
205120492Sfjoe		if ((args.cs_local = malloc(ICONV_CSNMAXLEN)) == NULL)
206120492Sfjoe			err(EX_OSERR, "malloc()");
207120492Sfjoe		strcpy(args.cs_local, "ISO8859-1");
208120492Sfjoe		if (set_charset(&args) == -1)
209120492Sfjoe			err(EX_OSERR, "msdosfs_iconv");
210120492Sfjoe		args.flags |= MSDOSFSMNT_KICONV;
211120492Sfjoe	}
212120492Sfjoe
21352055Sphk	/*
21452055Sphk	 * Resolve the mountpoint with realpath(3) and remove unnecessary
21552055Sphk	 * slashes from the devicename if there are any.
21652055Sphk	 */
21752055Sphk	(void)checkpath(dir, mntpath);
21852055Sphk	(void)rmslashes(dev, dev);
21952055Sphk
2202892Sdfr	args.fspec = dev;
2212892Sdfr	args.export.ex_root = -2;	/* unchecked anyway on DOS fs */
2222892Sdfr	if (mntflags & MNT_RDONLY)
2232892Sdfr		args.export.ex_flags = MNT_EXRDONLY;
2242892Sdfr	else
2252892Sdfr		args.export.ex_flags = 0;
2262892Sdfr	if (!set_gid || !set_uid || !set_mask) {
22752055Sphk		if (stat(mntpath, &sb) == -1)
22852055Sphk			err(EX_OSERR, "stat %s", mntpath);
2292892Sdfr
2302892Sdfr		if (!set_uid)
2312892Sdfr			args.uid = sb.st_uid;
2322892Sdfr		if (!set_gid)
2332892Sdfr			args.gid = sb.st_gid;
2342892Sdfr		if (!set_mask)
235118837Strhodes			args.mask = args.dirmask =
236118837Strhodes				sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
2372892Sdfr	}
2382892Sdfr
239101270Smux	if (mount("msdosfs", mntpath, mntflags, &args) < 0)
24015771Swollman		err(EX_OSERR, "%s", dev);
2412892Sdfr
2422892Sdfr	exit (0);
2432892Sdfr}
2442892Sdfr
2452892Sdfrgid_t
2462892Sdfra_gid(s)
2472892Sdfr	char *s;
2482892Sdfr{
2492892Sdfr	struct group *gr;
2502892Sdfr	char *gname;
2512892Sdfr	gid_t gid;
2522892Sdfr
2532892Sdfr	if ((gr = getgrnam(s)) != NULL)
2542892Sdfr		gid = gr->gr_gid;
2552892Sdfr	else {
2562892Sdfr		for (gname = s; *s && isdigit(*s); ++s);
2572892Sdfr		if (!*s)
2582892Sdfr			gid = atoi(gname);
2592892Sdfr		else
26015771Swollman			errx(EX_NOUSER, "unknown group id: %s", gname);
2612892Sdfr	}
2622892Sdfr	return (gid);
2632892Sdfr}
2642892Sdfr
2652892Sdfruid_t
2662892Sdfra_uid(s)
2672892Sdfr	char *s;
2682892Sdfr{
2692892Sdfr	struct passwd *pw;
2702892Sdfr	char *uname;
2712892Sdfr	uid_t uid;
2722892Sdfr
2732892Sdfr	if ((pw = getpwnam(s)) != NULL)
2742892Sdfr		uid = pw->pw_uid;
2752892Sdfr	else {
2762892Sdfr		for (uname = s; *s && isdigit(*s); ++s);
2772892Sdfr		if (!*s)
2782892Sdfr			uid = atoi(uname);
2792892Sdfr		else
28015771Swollman			errx(EX_NOUSER, "unknown user id: %s", uname);
2812892Sdfr	}
2822892Sdfr	return (uid);
2832892Sdfr}
2842892Sdfr
2852892Sdfrmode_t
2862892Sdfra_mask(s)
2872892Sdfr	char *s;
2882892Sdfr{
2892892Sdfr	int done, rv;
2902892Sdfr	char *ep;
2912892Sdfr
2922892Sdfr	done = 0;
29333549Sjkh	rv = -1;
2942892Sdfr	if (*s >= '0' && *s <= '7') {
2952892Sdfr		done = 1;
2962892Sdfr		rv = strtol(optarg, &ep, 8);
2972892Sdfr	}
2982892Sdfr	if (!done || rv < 0 || *ep)
29915771Swollman		errx(EX_USAGE, "invalid file mode: %s", s);
3002892Sdfr	return (rv);
3012892Sdfr}
3022892Sdfr
3032892Sdfrvoid
3042892Sdfrusage()
3052892Sdfr{
306120492Sfjoe#ifdef TRANSITION_PERIOD_HACK
307121007Sfjoe	fprintf(stderr, "%s\n%s\n%s\n",
308121429Strhodes	"usage: mount_msdosfs [-9ls] [-D DOS_codepage] [-g gid] [-L locale]",
309121429Strhodes	"                     [-M mask] [-m mask] [-o options] [-u uid]",
310121429Strhodes	"		      [-W table] special node");
311120492Sfjoe#else
312121429Strhodes	fprintf(stderr, "%s\n%s\n%s\n",
313121429Strhodes	"usage: mount_msdosfs [-9ls] [-D DOS_codepage] [-g gid] [-L locale]",
314121429Strhodes	"                     [-M mask] [-m mask] [-o options] [-u uid]",
315121429Strhodes	"		      special node");
316120492Sfjoe#endif
31715771Swollman	exit(EX_USAGE);
3182892Sdfr}
31933749Sache
320120492Sfjoeint
321120492Sfjoeset_charset(struct msdosfs_args *args)
32233749Sache{
323120492Sfjoe	int error;
32433749Sache
325120492Sfjoe	if (modfind("msdosfs_iconv") < 0)
326120492Sfjoe		if (kldload("msdosfs_iconv") < 0 || modfind("msdosfs_iconv") < 0) {
327134565Strhodes			warnx("cannot find or load \"msdosfs_iconv\" kernel module");
328120492Sfjoe			return (-1);
329120492Sfjoe		}
330120492Sfjoe
331120492Sfjoe	if ((args->cs_win = malloc(ICONV_CSNMAXLEN)) == NULL)
332120492Sfjoe		return (-1);
333120492Sfjoe	strncpy(args->cs_win, ENCODING_UNICODE, ICONV_CSNMAXLEN);
334123293Sfjoe	error = kiconv_add_xlat16_cspairs(args->cs_win, args->cs_local);
335120492Sfjoe	if (error)
336120492Sfjoe		return (-1);
337120492Sfjoe	if (args->cs_dos) {
338123293Sfjoe		error = kiconv_add_xlat16_cspairs(args->cs_dos, args->cs_local);
339120492Sfjoe		if (error)
340120492Sfjoe			return (-1);
341120492Sfjoe	} else {
342120492Sfjoe		if ((args->cs_dos = malloc(ICONV_CSNMAXLEN)) == NULL)
343120492Sfjoe			return (-1);
344120492Sfjoe		strcpy(args->cs_dos, args->cs_local);
345120492Sfjoe		error = kiconv_add_xlat16_cspair(args->cs_local, args->cs_local,
346120492Sfjoe				KICONV_FROM_UPPER | KICONV_LOWER);
347120492Sfjoe		if (error)
348120492Sfjoe			return (-1);
34933749Sache	}
35033761Sache
351120492Sfjoe	return (0);
35233761Sache}
353