mount_msdosfs.c revision 121363
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 121363 2003-10-22 20:11:42Z trhodes $";
362892Sdfr#endif /* not lint */
372892Sdfr
382892Sdfr#include <sys/param.h>
392892Sdfr#include <sys/mount.h>
402892Sdfr#include <sys/stat.h>
41120492Sfjoe#include <sys/module.h>
42120492Sfjoe#include <sys/iconv.h>
43121363Strhodes#include <sys/linker.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>
592892Sdfr#include "mntopts.h"
602892Sdfr
61120492Sfjoe#define TRANSITION_PERIOD_HACK
62120492Sfjoe
6348002Sjkh/*
6448002Sjkh * XXX - no way to specify "foo=<bar>"-type options; that's what we'd
65121007Sfjoe * want for "-u", "-g", "-m", "-M", "-L", "-D", and "-W".
6648002Sjkh */
6715771Swollmanstatic struct mntopt mopts[] = {
682892Sdfr	MOPT_STDOPTS,
6928731Sbde	MOPT_FORCE,
7028731Sbde	MOPT_SYNC,
7128731Sbde	MOPT_UPDATE,
7248002Sjkh#ifdef MSDOSFSMNT_GEMDOSFS
7348002Sjkh	{ "gemdosfs", 0, MSDOSFSMNT_GEMDOSFS, 1 },
7448002Sjkh#endif
7548002Sjkh	{ "shortnames", 0, MSDOSFSMNT_SHORTNAME, 1 },
7648002Sjkh	{ "longnames", 0, MSDOSFSMNT_LONGNAME, 1 },
7748002Sjkh	{ "nowin95", 0, MSDOSFSMNT_NOWIN95, 1 },
782892Sdfr	{ NULL }
792892Sdfr};
802892Sdfr
8192882Simpstatic gid_t	a_gid(char *);
8292882Simpstatic uid_t	a_uid(char *);
8392882Simpstatic mode_t	a_mask(char *);
8492882Simpstatic void	usage(void) __dead2;
85120492Sfjoestatic int	set_charset(struct msdosfs_args *);
862892Sdfr
872892Sdfrint
882892Sdfrmain(argc, argv)
892892Sdfr	int argc;
902892Sdfr	char **argv;
912892Sdfr{
922892Sdfr	struct msdosfs_args args;
932892Sdfr	struct stat sb;
94118837Strhodes	int c, mntflags, set_gid, set_uid, set_mask, set_dirmask;
95120492Sfjoe	char *dev, *dir, mntpath[MAXPATHLEN], *csp;
962892Sdfr
97118837Strhodes	mntflags = set_gid = set_uid = set_mask = set_dirmask = 0;
982892Sdfr	(void)memset(&args, '\0', sizeof(args));
9933549Sjkh	args.magic = MSDOSFS_ARGSMAGIC;
1002892Sdfr
101120492Sfjoe	args.cs_win = NULL;
102120492Sfjoe	args.cs_dos = NULL;
103120492Sfjoe	args.cs_local = NULL;
104120492Sfjoe#ifdef TRANSITION_PERIOD_HACK
105120492Sfjoe	while ((c = getopt(argc, argv, "sl9u:g:m:M:o:L:D:W:")) != -1) {
106120492Sfjoe#else
107120492Sfjoe	while ((c = getopt(argc, argv, "sl9u:g:m:M:o:L:D:")) != -1) {
108120492Sfjoe#endif
1092892Sdfr		switch (c) {
11033549Sjkh#ifdef MSDOSFSMNT_GEMDOSFS
11133549Sjkh		case 'G':
11233549Sjkh			args.flags |= MSDOSFSMNT_GEMDOSFS;
11333549Sjkh			break;
11433549Sjkh#endif
11533549Sjkh		case 's':
11633549Sjkh			args.flags |= MSDOSFSMNT_SHORTNAME;
11733549Sjkh			break;
11833549Sjkh		case 'l':
11933549Sjkh			args.flags |= MSDOSFSMNT_LONGNAME;
12033549Sjkh			break;
12133549Sjkh		case '9':
12233549Sjkh			args.flags |= MSDOSFSMNT_NOWIN95;
12333549Sjkh			break;
1242892Sdfr		case 'u':
1252892Sdfr			args.uid = a_uid(optarg);
1262892Sdfr			set_uid = 1;
1272892Sdfr			break;
1282892Sdfr		case 'g':
1292892Sdfr			args.gid = a_gid(optarg);
1302892Sdfr			set_gid = 1;
1312892Sdfr			break;
1322892Sdfr		case 'm':
1332892Sdfr			args.mask = a_mask(optarg);
1342892Sdfr			set_mask = 1;
1352892Sdfr			break;
136118837Strhodes		case 'M':
137118837Strhodes			args.dirmask = a_mask(optarg);
138118837Strhodes			set_dirmask = 1;
139118837Strhodes			break;
14033761Sache		case 'L':
141120492Sfjoe			if (setlocale(LC_CTYPE, optarg) == NULL)
142120492Sfjoe				err(EX_CONFIG, "%s", optarg);
143120492Sfjoe			csp = strchr(optarg,'.');
144120492Sfjoe			if (!csp)
145120492Sfjoe				err(EX_CONFIG, "%s", optarg);
146120492Sfjoe			args.cs_local = malloc(ICONV_CSNMAXLEN);
147120492Sfjoe			if (args.cs_local == NULL)
148120492Sfjoe				err(EX_OSERR, "malloc()");
149120492Sfjoe			strncpy(args.cs_local,
150120492Sfjoe			    kiconv_quirkcs(csp + 1, KICONV_VENDOR_MICSFT),
151120492Sfjoe			    ICONV_CSNMAXLEN);
15233761Sache			break;
153120492Sfjoe		case 'D':
154120492Sfjoe			args.cs_dos = malloc(ICONV_CSNMAXLEN);
155120492Sfjoe			if (args.cs_dos == NULL)
156120492Sfjoe				err(EX_OSERR, "malloc()");
157120492Sfjoe			strncpy(args.cs_dos, optarg, ICONV_CSNMAXLEN);
15833749Sache			break;
1592892Sdfr		case 'o':
16048002Sjkh			getmntopts(optarg, mopts, &mntflags, &args.flags);
1612892Sdfr			break;
162120492Sfjoe#ifdef TRANSITION_PERIOD_HACK
163120492Sfjoe		case 'W':
164120492Sfjoe			args.cs_local = malloc(ICONV_CSNMAXLEN);
165120492Sfjoe			if (args.cs_local == NULL)
166120492Sfjoe				err(EX_OSERR, "malloc()");
167120492Sfjoe			args.cs_dos = malloc(ICONV_CSNMAXLEN);
168120492Sfjoe			if (args.cs_dos == NULL)
169120492Sfjoe				err(EX_OSERR, "malloc()");
170120492Sfjoe			if (strcmp(optarg, "iso22dos") == 0) {
171120492Sfjoe				strcpy(args.cs_local, "ISO8859-2");
172120492Sfjoe				strcpy(args.cs_dos, "CP852");
173120492Sfjoe			} else if (strcmp(optarg, "iso72dos") == 0) {
174120492Sfjoe				strcpy(args.cs_local, "ISO8859-7");
175120492Sfjoe				strcpy(args.cs_dos, "CP737");
176120492Sfjoe			} else if (strcmp(optarg, "koi2dos") == 0) {
177120492Sfjoe				strcpy(args.cs_local, "KOI8-R");
178120492Sfjoe				strcpy(args.cs_dos, "CP866");
179120492Sfjoe			} else if (strcmp(optarg, "koi8u2dos") == 0) {
180120492Sfjoe				strcpy(args.cs_local, "KOI8-U");
181120492Sfjoe				strcpy(args.cs_dos, "CP866");
182120492Sfjoe			} else {
183120492Sfjoe				err(EX_NOINPUT, "%s", optarg);
184120492Sfjoe			}
185120492Sfjoe			break;
186120492Sfjoe#endif /* TRANSITION_PERIOD_HACK */
1872892Sdfr		case '?':
1882892Sdfr		default:
1892892Sdfr			usage();
1902892Sdfr			break;
1912892Sdfr		}
1922892Sdfr	}
1932892Sdfr
1942892Sdfr	if (optind + 2 != argc)
1952892Sdfr		usage();
1962892Sdfr
197118837Strhodes	if (set_mask && !set_dirmask) {
198118837Strhodes		args.dirmask = args.mask;
199118837Strhodes		set_dirmask = 1;
200118837Strhodes	}
201118837Strhodes	else if (set_dirmask && !set_mask) {
202118837Strhodes		args.mask = args.dirmask;
203118837Strhodes		set_mask = 1;
204118837Strhodes	}
205118837Strhodes
2062892Sdfr	dev = argv[optind];
2072892Sdfr	dir = argv[optind + 1];
2082892Sdfr
209120492Sfjoe	if (args.cs_local) {
210120492Sfjoe		if (set_charset(&args) == -1)
211120492Sfjoe			err(EX_OSERR, "msdosfs_iconv");
212120492Sfjoe		args.flags |= MSDOSFSMNT_KICONV;
213120492Sfjoe	} else if (args.cs_dos) {
214120492Sfjoe		if ((args.cs_local = malloc(ICONV_CSNMAXLEN)) == NULL)
215120492Sfjoe			err(EX_OSERR, "malloc()");
216120492Sfjoe		strcpy(args.cs_local, "ISO8859-1");
217120492Sfjoe		if (set_charset(&args) == -1)
218120492Sfjoe			err(EX_OSERR, "msdosfs_iconv");
219120492Sfjoe		args.flags |= MSDOSFSMNT_KICONV;
220120492Sfjoe	}
221120492Sfjoe
22252055Sphk	/*
22352055Sphk	 * Resolve the mountpoint with realpath(3) and remove unnecessary
22452055Sphk	 * slashes from the devicename if there are any.
22552055Sphk	 */
22652055Sphk	(void)checkpath(dir, mntpath);
22752055Sphk	(void)rmslashes(dev, dev);
22852055Sphk
2292892Sdfr	args.fspec = dev;
2302892Sdfr	args.export.ex_root = -2;	/* unchecked anyway on DOS fs */
2312892Sdfr	if (mntflags & MNT_RDONLY)
2322892Sdfr		args.export.ex_flags = MNT_EXRDONLY;
2332892Sdfr	else
2342892Sdfr		args.export.ex_flags = 0;
2352892Sdfr	if (!set_gid || !set_uid || !set_mask) {
23652055Sphk		if (stat(mntpath, &sb) == -1)
23752055Sphk			err(EX_OSERR, "stat %s", mntpath);
2382892Sdfr
2392892Sdfr		if (!set_uid)
2402892Sdfr			args.uid = sb.st_uid;
2412892Sdfr		if (!set_gid)
2422892Sdfr			args.gid = sb.st_gid;
2432892Sdfr		if (!set_mask)
244118837Strhodes			args.mask = args.dirmask =
245118837Strhodes				sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
2462892Sdfr	}
2472892Sdfr
248101270Smux	if (mount("msdosfs", mntpath, mntflags, &args) < 0)
24915771Swollman		err(EX_OSERR, "%s", dev);
2502892Sdfr
2512892Sdfr	exit (0);
2522892Sdfr}
2532892Sdfr
2542892Sdfrgid_t
2552892Sdfra_gid(s)
2562892Sdfr	char *s;
2572892Sdfr{
2582892Sdfr	struct group *gr;
2592892Sdfr	char *gname;
2602892Sdfr	gid_t gid;
2612892Sdfr
2622892Sdfr	if ((gr = getgrnam(s)) != NULL)
2632892Sdfr		gid = gr->gr_gid;
2642892Sdfr	else {
2652892Sdfr		for (gname = s; *s && isdigit(*s); ++s);
2662892Sdfr		if (!*s)
2672892Sdfr			gid = atoi(gname);
2682892Sdfr		else
26915771Swollman			errx(EX_NOUSER, "unknown group id: %s", gname);
2702892Sdfr	}
2712892Sdfr	return (gid);
2722892Sdfr}
2732892Sdfr
2742892Sdfruid_t
2752892Sdfra_uid(s)
2762892Sdfr	char *s;
2772892Sdfr{
2782892Sdfr	struct passwd *pw;
2792892Sdfr	char *uname;
2802892Sdfr	uid_t uid;
2812892Sdfr
2822892Sdfr	if ((pw = getpwnam(s)) != NULL)
2832892Sdfr		uid = pw->pw_uid;
2842892Sdfr	else {
2852892Sdfr		for (uname = s; *s && isdigit(*s); ++s);
2862892Sdfr		if (!*s)
2872892Sdfr			uid = atoi(uname);
2882892Sdfr		else
28915771Swollman			errx(EX_NOUSER, "unknown user id: %s", uname);
2902892Sdfr	}
2912892Sdfr	return (uid);
2922892Sdfr}
2932892Sdfr
2942892Sdfrmode_t
2952892Sdfra_mask(s)
2962892Sdfr	char *s;
2972892Sdfr{
2982892Sdfr	int done, rv;
2992892Sdfr	char *ep;
3002892Sdfr
3012892Sdfr	done = 0;
30233549Sjkh	rv = -1;
3032892Sdfr	if (*s >= '0' && *s <= '7') {
3042892Sdfr		done = 1;
3052892Sdfr		rv = strtol(optarg, &ep, 8);
3062892Sdfr	}
3072892Sdfr	if (!done || rv < 0 || *ep)
30815771Swollman		errx(EX_USAGE, "invalid file mode: %s", s);
3092892Sdfr	return (rv);
3102892Sdfr}
3112892Sdfr
3122892Sdfrvoid
3132892Sdfrusage()
3142892Sdfr{
315120492Sfjoe#ifdef TRANSITION_PERIOD_HACK
316121007Sfjoe	fprintf(stderr, "%s\n%s\n%s\n",
317121360Strhodes	"usage: mount_msdosfs [-o options] [-u user] [-g group] [-m mask] [-M mask]",
318121360Strhodes	"                     [-s] [-l] [-9] [-L locale] [-D dos-codepage] [-W table]",
319121007Sfjoe	"                     bdev dir");
320120492Sfjoe#else
321121007Sfjoe	fprintf(stderr, "%s\n%s\n",
322121007Sfjoe	"usage: mount_msdosfs [-o options] [-u user] [-g group] [-m mask] [-M mask]",
323120492Sfjoe	"                     [-s] [-l] [-9] [-L locale] [-D dos-codepage] bdev dir");
324120492Sfjoe#endif
32515771Swollman	exit(EX_USAGE);
3262892Sdfr}
32733749Sache
328120492Sfjoeint
329120492Sfjoeset_charset(struct msdosfs_args *args)
33033749Sache{
331120492Sfjoe	int error;
33233749Sache
333120492Sfjoe	if (modfind("msdosfs_iconv") < 0)
334120492Sfjoe		if (kldload("msdosfs_iconv") < 0 || modfind("msdosfs_iconv") < 0) {
335120492Sfjoe			warnx( "cannot find or load \"msdosfs_iconv\" kernel module");
336120492Sfjoe			return (-1);
337120492Sfjoe		}
338120492Sfjoe
339120492Sfjoe	if ((args->cs_win = malloc(ICONV_CSNMAXLEN)) == NULL)
340120492Sfjoe		return (-1);
341120492Sfjoe	strncpy(args->cs_win, ENCODING_UNICODE, ICONV_CSNMAXLEN);
342120492Sfjoe	error = kiconv_add_xlat16_cspair(args->cs_win, args->cs_local, 0);
343120492Sfjoe	if (error)
344120492Sfjoe		return (-1);
345120492Sfjoe	error = kiconv_add_xlat16_cspair(args->cs_local, args->cs_win, 0);
346120492Sfjoe	if (error)
347120492Sfjoe		return (-1);
348120492Sfjoe	if (args->cs_dos) {
349120492Sfjoe		error = kiconv_add_xlat16_cspair(args->cs_dos, args->cs_local, KICONV_FROM_UPPER);
350120492Sfjoe		if (error)
351120492Sfjoe			return (-1);
352120492Sfjoe		error = kiconv_add_xlat16_cspair(args->cs_local, args->cs_dos, KICONV_LOWER);
353120492Sfjoe		if (error)
354120492Sfjoe			return (-1);
355120492Sfjoe	} else {
356120492Sfjoe		if ((args->cs_dos = malloc(ICONV_CSNMAXLEN)) == NULL)
357120492Sfjoe			return (-1);
358120492Sfjoe		strcpy(args->cs_dos, args->cs_local);
359120492Sfjoe		error = kiconv_add_xlat16_cspair(args->cs_local, args->cs_local,
360120492Sfjoe				KICONV_FROM_UPPER | KICONV_LOWER);
361120492Sfjoe		if (error)
362120492Sfjoe			return (-1);
36333749Sache	}
36433761Sache
365120492Sfjoe	return (0);
36633761Sache}
367