mount_ntfs.c revision 141611
1/*
2 * Copyright (c) 1994 Christopher G. Demetriou
3 * Copyright (c) 1999 Semen Ustimenko
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 *    must display the following acknowledgement:
16 *      This product includes software developed by Christopher G. Demetriou.
17 * 4. The name of the author may not be used to endorse or promote products
18 *    derived from this software without specific prior written permission
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 *
31 * $FreeBSD: head/sbin/mount_ntfs/mount_ntfs.c 141611 2005-02-10 09:19:34Z ru $
32 *
33 */
34
35#include <sys/cdefs.h>
36#include <sys/param.h>
37#define NTFS
38#include <sys/mount.h>
39#include <sys/stat.h>
40#include <sys/module.h>
41#include <sys/iconv.h>
42#include <sys/linker.h>
43#include <fs/ntfs/ntfsmount.h>
44#include <ctype.h>
45#include <err.h>
46#include <grp.h>
47#include <pwd.h>
48#include <stdio.h>
49#include <stdlib.h>
50#include <string.h>
51#include <sysexits.h>
52#include <unistd.h>
53#include <libutil.h>
54
55#include "mntopts.h"
56
57#define TRANSITION_PERIOD_HACK
58
59static struct mntopt mopts[] = {
60	MOPT_STDOPTS,
61	{ NULL }
62};
63
64static gid_t	a_gid(char *);
65static uid_t	a_uid(char *);
66static mode_t	a_mask(char *);
67static void	usage(void) __dead2;
68
69static int	set_charset(struct ntfs_args *);
70
71int
72main(argc, argv)
73	int argc;
74	char **argv;
75{
76	struct ntfs_args args;
77	struct stat sb;
78	int c, mntflags, set_gid, set_uid, set_mask;
79	char *dev, *dir, mntpath[MAXPATHLEN];
80
81	mntflags = set_gid = set_uid = set_mask = 0;
82	(void)memset(&args, '\0', sizeof(args));
83	args.cs_ntfs = NULL;
84	args.cs_local = NULL;
85
86#ifdef TRANSITION_PERIOD_HACK
87	while ((c = getopt(argc, argv, "aiu:g:m:o:C:W:")) !=  -1) {
88#else
89	while ((c = getopt(argc, argv, "aiu:g:m:o:C:")) !=  -1) {
90#endif
91		switch (c) {
92		case 'u':
93			args.uid = a_uid(optarg);
94			set_uid = 1;
95			break;
96		case 'g':
97			args.gid = a_gid(optarg);
98			set_gid = 1;
99			break;
100		case 'm':
101			args.mode = a_mask(optarg);
102			set_mask = 1;
103			break;
104		case 'i':
105			args.flag |= NTFS_MFLAG_CASEINS;
106			break;
107		case 'a':
108			args.flag |= NTFS_MFLAG_ALLNAMES;
109			break;
110		case 'o':
111			getmntopts(optarg, mopts, &mntflags, 0);
112			break;
113		case 'C':
114			args.cs_local = malloc(ICONV_CSNMAXLEN);
115			if (args.cs_local == NULL)
116				err(EX_OSERR, "malloc()");
117			strncpy(args.cs_local,
118			    kiconv_quirkcs(optarg, KICONV_VENDOR_MICSFT),
119			    ICONV_CSNMAXLEN);
120			break;
121#ifdef TRANSITION_PERIOD_HACK
122		case 'W':
123			args.cs_local = malloc(ICONV_CSNMAXLEN);
124			if (args.cs_local == NULL)
125				err(EX_OSERR, "malloc()");
126			if (strcmp(optarg, "iso22dos") == 0) {
127				strcpy(args.cs_local, "ISO8859-2");
128			} else if (strcmp(optarg, "iso72dos") == 0) {
129				strcpy(args.cs_local, "ISO8859-7");
130			} else if (strcmp(optarg, "koi2dos") == 0) {
131				strcpy(args.cs_local, "KOI8-R");
132			} else if (strcmp(optarg, "koi8u2dos") == 0) {
133				strcpy(args.cs_local, "KOI8-U");
134			} else {
135				err(EX_NOINPUT, "%s", optarg);
136			}
137			break;
138#endif /* TRANSITION_PERIOD_HACK */
139		case '?':
140		default:
141			usage();
142			break;
143		}
144	}
145
146	if (optind + 2 != argc)
147		usage();
148
149	dev = argv[optind];
150	dir = argv[optind + 1];
151
152	if (args.cs_local) {
153		if (set_charset(&args) == -1)
154			err(EX_OSERR, "ntfs_iconv");
155		args.flag |= NTFS_MFLAG_KICONV;
156		/*
157		 * XXX
158		 * Force to be MNT_RDONLY,
159		 * since only reading is supported right now,
160		 */
161		mntflags |= MNT_RDONLY;
162	}
163
164	/*
165	 * Resolve the mountpoint with realpath(3) and remove unnecessary
166	 * slashes from the devicename if there are any.
167	 */
168	(void)checkpath(dir, mntpath);
169	(void)rmslashes(dev, dev);
170
171	args.fspec = dev;
172	args.export.ex_root = 65534;	/* unchecked anyway on DOS fs */
173	if (mntflags & MNT_RDONLY)
174		args.export.ex_flags = MNT_EXRDONLY;
175	else
176		args.export.ex_flags = 0;
177	if (!set_gid || !set_uid || !set_mask) {
178		if (stat(mntpath, &sb) == -1)
179			err(EX_OSERR, "stat %s", mntpath);
180
181		if (!set_uid)
182			args.uid = sb.st_uid;
183		if (!set_gid)
184			args.gid = sb.st_gid;
185		if (!set_mask)
186			args.mode = sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
187	}
188
189	if (mount("ntfs", mntpath, mntflags, &args) < 0)
190		err(EX_OSERR, "%s", dev);
191
192	exit (0);
193}
194
195gid_t
196a_gid(s)
197	char *s;
198{
199	struct group *gr;
200	char *gname;
201	gid_t gid;
202
203	if ((gr = getgrnam(s)) != NULL)
204		gid = gr->gr_gid;
205	else {
206		for (gname = s; *s && isdigit(*s); ++s);
207		if (!*s)
208			gid = atoi(gname);
209		else
210			errx(EX_NOUSER, "unknown group id: %s", gname);
211	}
212	return (gid);
213}
214
215uid_t
216a_uid(s)
217	char *s;
218{
219	struct passwd *pw;
220	char *uname;
221	uid_t uid;
222
223	if ((pw = getpwnam(s)) != NULL)
224		uid = pw->pw_uid;
225	else {
226		for (uname = s; *s && isdigit(*s); ++s);
227		if (!*s)
228			uid = atoi(uname);
229		else
230			errx(EX_NOUSER, "unknown user id: %s", uname);
231	}
232	return (uid);
233}
234
235mode_t
236a_mask(s)
237	char *s;
238{
239	int done, rv=0;
240	char *ep;
241
242	done = 0;
243	if (*s >= '0' && *s <= '7') {
244		done = 1;
245		rv = strtol(optarg, &ep, 8);
246	}
247	if (!done || rv < 0 || *ep)
248		errx(EX_USAGE, "invalid file mode: %s", s);
249	return (rv);
250}
251
252void
253usage()
254{
255#ifdef TRANSITION_PERIOD_HACK
256	fprintf(stderr, "%s\n%s\n",
257	"usage: mount_ntfs [-a] [-i] [-u user] [-g group] [-m mask]",
258	"                  [-C charset] [-W u2wtable] special node");
259#else
260	fprintf(stderr, "usage: mount_ntfs [-a] [-i] [-u user] [-g group] [-m mask] [-C charset] special node\n");
261#endif
262	exit(EX_USAGE);
263}
264
265int
266set_charset(struct ntfs_args *pargs)
267{
268	int error;
269
270	if (modfind("ntfs_iconv") < 0)
271		if (kldload("ntfs_iconv") < 0 || modfind("ntfs_iconv") < 0) {
272			warnx( "cannot find or load \"ntfs_iconv\" kernel module");
273			return (-1);
274		}
275
276	if ((pargs->cs_ntfs = malloc(ICONV_CSNMAXLEN)) == NULL)
277		return (-1);
278	strncpy(pargs->cs_ntfs, ENCODING_UNICODE, ICONV_CSNMAXLEN);
279	error = kiconv_add_xlat16_cspairs(pargs->cs_ntfs, pargs->cs_local);
280	if (error)
281		return (-1);
282
283	return (0);
284}
285