mount_msdosfs.c revision 121429
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 121429 2003-10-23 16:09:20Z 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#ifdef MSDOSFSMNT_GEMDOSFS
7448002Sjkh	{ "gemdosfs", 0, MSDOSFSMNT_GEMDOSFS, 1 },
7548002Sjkh#endif
7648002Sjkh	{ "shortnames", 0, MSDOSFSMNT_SHORTNAME, 1 },
7748002Sjkh	{ "longnames", 0, MSDOSFSMNT_LONGNAME, 1 },
7848002Sjkh	{ "nowin95", 0, MSDOSFSMNT_NOWIN95, 1 },
792892Sdfr	{ NULL }
802892Sdfr};
812892Sdfr
8292882Simpstatic gid_t	a_gid(char *);
8392882Simpstatic uid_t	a_uid(char *);
8492882Simpstatic mode_t	a_mask(char *);
8592882Simpstatic void	usage(void) __dead2;
86120492Sfjoestatic int	set_charset(struct msdosfs_args *);
872892Sdfr
882892Sdfrint
89121373Strhodesmain(int argc, char **argv)
902892Sdfr{
912892Sdfr	struct msdosfs_args args;
922892Sdfr	struct stat sb;
93118837Strhodes	int c, mntflags, set_gid, set_uid, set_mask, set_dirmask;
94120492Sfjoe	char *dev, *dir, mntpath[MAXPATHLEN], *csp;
952892Sdfr
96118837Strhodes	mntflags = set_gid = set_uid = set_mask = set_dirmask = 0;
972892Sdfr	(void)memset(&args, '\0', sizeof(args));
9833549Sjkh	args.magic = MSDOSFS_ARGSMAGIC;
992892Sdfr
100120492Sfjoe	args.cs_win = NULL;
101120492Sfjoe	args.cs_dos = NULL;
102120492Sfjoe	args.cs_local = NULL;
103120492Sfjoe#ifdef TRANSITION_PERIOD_HACK
104120492Sfjoe	while ((c = getopt(argc, argv, "sl9u:g:m:M:o:L:D:W:")) != -1) {
105120492Sfjoe#else
106120492Sfjoe	while ((c = getopt(argc, argv, "sl9u:g:m:M:o:L:D:")) != -1) {
107120492Sfjoe#endif
1082892Sdfr		switch (c) {
10933549Sjkh#ifdef MSDOSFSMNT_GEMDOSFS
11033549Sjkh		case 'G':
11133549Sjkh			args.flags |= MSDOSFSMNT_GEMDOSFS;
11233549Sjkh			break;
11333549Sjkh#endif
11433549Sjkh		case 's':
11533549Sjkh			args.flags |= MSDOSFSMNT_SHORTNAME;
11633549Sjkh			break;
11733549Sjkh		case 'l':
11833549Sjkh			args.flags |= MSDOSFSMNT_LONGNAME;
11933549Sjkh			break;
12033549Sjkh		case '9':
12133549Sjkh			args.flags |= MSDOSFSMNT_NOWIN95;
12233549Sjkh			break;
1232892Sdfr		case 'u':
1242892Sdfr			args.uid = a_uid(optarg);
1252892Sdfr			set_uid = 1;
1262892Sdfr			break;
1272892Sdfr		case 'g':
1282892Sdfr			args.gid = a_gid(optarg);
1292892Sdfr			set_gid = 1;
1302892Sdfr			break;
1312892Sdfr		case 'm':
1322892Sdfr			args.mask = a_mask(optarg);
1332892Sdfr			set_mask = 1;
1342892Sdfr			break;
135118837Strhodes		case 'M':
136118837Strhodes			args.dirmask = a_mask(optarg);
137118837Strhodes			set_dirmask = 1;
138118837Strhodes			break;
13933761Sache		case 'L':
140120492Sfjoe			if (setlocale(LC_CTYPE, optarg) == NULL)
141120492Sfjoe				err(EX_CONFIG, "%s", optarg);
142120492Sfjoe			csp = strchr(optarg,'.');
143120492Sfjoe			if (!csp)
144120492Sfjoe				err(EX_CONFIG, "%s", optarg);
145120492Sfjoe			args.cs_local = malloc(ICONV_CSNMAXLEN);
146120492Sfjoe			if (args.cs_local == NULL)
147120492Sfjoe				err(EX_OSERR, "malloc()");
148120492Sfjoe			strncpy(args.cs_local,
149120492Sfjoe			    kiconv_quirkcs(csp + 1, KICONV_VENDOR_MICSFT),
150120492Sfjoe			    ICONV_CSNMAXLEN);
15133761Sache			break;
152120492Sfjoe		case 'D':
153120492Sfjoe			args.cs_dos = malloc(ICONV_CSNMAXLEN);
154120492Sfjoe			if (args.cs_dos == NULL)
155120492Sfjoe				err(EX_OSERR, "malloc()");
156120492Sfjoe			strncpy(args.cs_dos, optarg, ICONV_CSNMAXLEN);
15733749Sache			break;
1582892Sdfr		case 'o':
15948002Sjkh			getmntopts(optarg, mopts, &mntflags, &args.flags);
1602892Sdfr			break;
161120492Sfjoe#ifdef TRANSITION_PERIOD_HACK
162120492Sfjoe		case 'W':
163120492Sfjoe			args.cs_local = malloc(ICONV_CSNMAXLEN);
164120492Sfjoe			if (args.cs_local == NULL)
165120492Sfjoe				err(EX_OSERR, "malloc()");
166120492Sfjoe			args.cs_dos = malloc(ICONV_CSNMAXLEN);
167120492Sfjoe			if (args.cs_dos == NULL)
168120492Sfjoe				err(EX_OSERR, "malloc()");
169120492Sfjoe			if (strcmp(optarg, "iso22dos") == 0) {
170120492Sfjoe				strcpy(args.cs_local, "ISO8859-2");
171120492Sfjoe				strcpy(args.cs_dos, "CP852");
172120492Sfjoe			} else if (strcmp(optarg, "iso72dos") == 0) {
173120492Sfjoe				strcpy(args.cs_local, "ISO8859-7");
174120492Sfjoe				strcpy(args.cs_dos, "CP737");
175120492Sfjoe			} else if (strcmp(optarg, "koi2dos") == 0) {
176120492Sfjoe				strcpy(args.cs_local, "KOI8-R");
177120492Sfjoe				strcpy(args.cs_dos, "CP866");
178120492Sfjoe			} else if (strcmp(optarg, "koi8u2dos") == 0) {
179120492Sfjoe				strcpy(args.cs_local, "KOI8-U");
180120492Sfjoe				strcpy(args.cs_dos, "CP866");
181120492Sfjoe			} else {
182120492Sfjoe				err(EX_NOINPUT, "%s", optarg);
183120492Sfjoe			}
184120492Sfjoe			break;
185120492Sfjoe#endif /* TRANSITION_PERIOD_HACK */
1862892Sdfr		case '?':
1872892Sdfr		default:
1882892Sdfr			usage();
1892892Sdfr			break;
1902892Sdfr		}
1912892Sdfr	}
1922892Sdfr
1932892Sdfr	if (optind + 2 != argc)
1942892Sdfr		usage();
1952892Sdfr
196118837Strhodes	if (set_mask && !set_dirmask) {
197118837Strhodes		args.dirmask = args.mask;
198118837Strhodes		set_dirmask = 1;
199118837Strhodes	}
200118837Strhodes	else if (set_dirmask && !set_mask) {
201118837Strhodes		args.mask = args.dirmask;
202118837Strhodes		set_mask = 1;
203118837Strhodes	}
204118837Strhodes
2052892Sdfr	dev = argv[optind];
2062892Sdfr	dir = argv[optind + 1];
2072892Sdfr
208120492Sfjoe	if (args.cs_local) {
209120492Sfjoe		if (set_charset(&args) == -1)
210120492Sfjoe			err(EX_OSERR, "msdosfs_iconv");
211120492Sfjoe		args.flags |= MSDOSFSMNT_KICONV;
212120492Sfjoe	} else if (args.cs_dos) {
213120492Sfjoe		if ((args.cs_local = malloc(ICONV_CSNMAXLEN)) == NULL)
214120492Sfjoe			err(EX_OSERR, "malloc()");
215120492Sfjoe		strcpy(args.cs_local, "ISO8859-1");
216120492Sfjoe		if (set_charset(&args) == -1)
217120492Sfjoe			err(EX_OSERR, "msdosfs_iconv");
218120492Sfjoe		args.flags |= MSDOSFSMNT_KICONV;
219120492Sfjoe	}
220120492Sfjoe
22152055Sphk	/*
22252055Sphk	 * Resolve the mountpoint with realpath(3) and remove unnecessary
22352055Sphk	 * slashes from the devicename if there are any.
22452055Sphk	 */
22552055Sphk	(void)checkpath(dir, mntpath);
22652055Sphk	(void)rmslashes(dev, dev);
22752055Sphk
2282892Sdfr	args.fspec = dev;
2292892Sdfr	args.export.ex_root = -2;	/* unchecked anyway on DOS fs */
2302892Sdfr	if (mntflags & MNT_RDONLY)
2312892Sdfr		args.export.ex_flags = MNT_EXRDONLY;
2322892Sdfr	else
2332892Sdfr		args.export.ex_flags = 0;
2342892Sdfr	if (!set_gid || !set_uid || !set_mask) {
23552055Sphk		if (stat(mntpath, &sb) == -1)
23652055Sphk			err(EX_OSERR, "stat %s", mntpath);
2372892Sdfr
2382892Sdfr		if (!set_uid)
2392892Sdfr			args.uid = sb.st_uid;
2402892Sdfr		if (!set_gid)
2412892Sdfr			args.gid = sb.st_gid;
2422892Sdfr		if (!set_mask)
243118837Strhodes			args.mask = args.dirmask =
244118837Strhodes				sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
2452892Sdfr	}
2462892Sdfr
247101270Smux	if (mount("msdosfs", mntpath, mntflags, &args) < 0)
24815771Swollman		err(EX_OSERR, "%s", dev);
2492892Sdfr
2502892Sdfr	exit (0);
2512892Sdfr}
2522892Sdfr
2532892Sdfrgid_t
2542892Sdfra_gid(s)
2552892Sdfr	char *s;
2562892Sdfr{
2572892Sdfr	struct group *gr;
2582892Sdfr	char *gname;
2592892Sdfr	gid_t gid;
2602892Sdfr
2612892Sdfr	if ((gr = getgrnam(s)) != NULL)
2622892Sdfr		gid = gr->gr_gid;
2632892Sdfr	else {
2642892Sdfr		for (gname = s; *s && isdigit(*s); ++s);
2652892Sdfr		if (!*s)
2662892Sdfr			gid = atoi(gname);
2672892Sdfr		else
26815771Swollman			errx(EX_NOUSER, "unknown group id: %s", gname);
2692892Sdfr	}
2702892Sdfr	return (gid);
2712892Sdfr}
2722892Sdfr
2732892Sdfruid_t
2742892Sdfra_uid(s)
2752892Sdfr	char *s;
2762892Sdfr{
2772892Sdfr	struct passwd *pw;
2782892Sdfr	char *uname;
2792892Sdfr	uid_t uid;
2802892Sdfr
2812892Sdfr	if ((pw = getpwnam(s)) != NULL)
2822892Sdfr		uid = pw->pw_uid;
2832892Sdfr	else {
2842892Sdfr		for (uname = s; *s && isdigit(*s); ++s);
2852892Sdfr		if (!*s)
2862892Sdfr			uid = atoi(uname);
2872892Sdfr		else
28815771Swollman			errx(EX_NOUSER, "unknown user id: %s", uname);
2892892Sdfr	}
2902892Sdfr	return (uid);
2912892Sdfr}
2922892Sdfr
2932892Sdfrmode_t
2942892Sdfra_mask(s)
2952892Sdfr	char *s;
2962892Sdfr{
2972892Sdfr	int done, rv;
2982892Sdfr	char *ep;
2992892Sdfr
3002892Sdfr	done = 0;
30133549Sjkh	rv = -1;
3022892Sdfr	if (*s >= '0' && *s <= '7') {
3032892Sdfr		done = 1;
3042892Sdfr		rv = strtol(optarg, &ep, 8);
3052892Sdfr	}
3062892Sdfr	if (!done || rv < 0 || *ep)
30715771Swollman		errx(EX_USAGE, "invalid file mode: %s", s);
3082892Sdfr	return (rv);
3092892Sdfr}
3102892Sdfr
3112892Sdfrvoid
3122892Sdfrusage()
3132892Sdfr{
314120492Sfjoe#ifdef TRANSITION_PERIOD_HACK
315121007Sfjoe	fprintf(stderr, "%s\n%s\n%s\n",
316121429Strhodes	"usage: mount_msdosfs [-9ls] [-D DOS_codepage] [-g gid] [-L locale]",
317121429Strhodes	"                     [-M mask] [-m mask] [-o options] [-u uid]",
318121429Strhodes	"		      [-W table] special node");
319120492Sfjoe#else
320121429Strhodes	fprintf(stderr, "%s\n%s\n%s\n",
321121429Strhodes	"usage: mount_msdosfs [-9ls] [-D DOS_codepage] [-g gid] [-L locale]",
322121429Strhodes	"                     [-M mask] [-m mask] [-o options] [-u uid]",
323121429Strhodes	"		      special node");
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