1/*
2 * Copyright (c) 1994 Christopher G. Demetriou
3 * Copyright (c) 1999 Semen Ustimenko (semenu@FreeBSD.org)
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$
32 */
33
34#include <sys/cdefs.h>
35#include <sys/param.h>
36#include <sys/mount.h>
37#include <sys/stat.h>
38#include <fs/hpfs/hpfsmount.h>
39#include <ctype.h>
40#include <err.h>
41#include <grp.h>
42#include <pwd.h>
43#include <stdio.h>
44#include <stdlib.h>
45#include <string.h>
46#include <sysexits.h>
47#include <unistd.h>
48
49#include "mntopts.h"
50
51static struct mntopt mopts[] = {
52	MOPT_STDOPTS,
53	MOPT_END
54};
55
56static gid_t	a_gid(char *);
57static uid_t	a_uid(char *);
58static mode_t	a_mask(char *);
59static void	usage(void) __dead2;
60static void	load_u2wtable(struct hpfs_args *, char *);
61
62int
63main(int argc, char *argv[])
64{
65	struct hpfs_args args;
66	struct stat sb;
67	int c, mntflags, set_gid, set_uid, set_mask;
68	int forcerw = 0;
69	char *dev, *dir, ndir[MAXPATHLEN];
70
71	mntflags = set_gid = set_uid = set_mask = 0;
72	(void)memset(&args, '\0', sizeof(args));
73
74	while ((c = getopt(argc, argv, "u:g:m:o:c:W:F")) !=  -1) {
75		switch (c) {
76		case 'F':
77			forcerw=1;
78			break;
79		case 'u':
80			args.uid = a_uid(optarg);
81			set_uid = 1;
82			break;
83		case 'g':
84			args.gid = a_gid(optarg);
85			set_gid = 1;
86			break;
87		case 'm':
88			args.mode = a_mask(optarg);
89			set_mask = 1;
90			break;
91		case 'o':
92			getmntopts(optarg, mopts, &mntflags, 0);
93			break;
94		case 'W':
95			load_u2wtable(&args, optarg);
96			args.flags |= HPFSMNT_TABLES;
97			break;
98		case '?':
99		default:
100			usage();
101			break;
102		}
103	}
104
105	if (optind + 2 != argc)
106		usage();
107
108	if (!(mntflags & MNT_RDONLY) && !forcerw) {
109		warnx("Write support is BETA, you need -F flag to enable RW mount!");
110		exit (111);
111	}
112
113	dev = argv[optind];
114	dir = argv[optind + 1];
115	if (dir[0] != '/') {
116		warnx("\"%s\" is a relative path", dir);
117		if (getcwd(ndir, sizeof(ndir)) == NULL)
118			err(EX_OSERR, "getcwd");
119		strncat(ndir, "/", sizeof(ndir) - strlen(ndir) - 1);
120		strncat(ndir, dir, sizeof(ndir) - strlen(ndir) - 1);
121		dir = ndir;
122		warnx("using \"%s\" instead", dir);
123	}
124
125	args.fspec = dev;
126	args.export.ex_root = 65534;	/* unchecked anyway on DOS fs */
127	if (mntflags & MNT_RDONLY)
128		args.export.ex_flags = MNT_EXRDONLY;
129	else
130		args.export.ex_flags = 0;
131
132	if (!set_gid || !set_uid || !set_mask) {
133		if (stat(dir, &sb) == -1)
134			err(EX_OSERR, "stat %s", dir);
135
136		if (!set_uid)
137			args.uid = sb.st_uid;
138		if (!set_gid)
139			args.gid = sb.st_gid;
140		if (!set_mask)
141			args.mode = sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
142	}
143
144	if (mount("hpfs", dir, mntflags, &args) < 0)
145		err(EX_OSERR, "%s", dev);
146
147	exit (0);
148}
149
150gid_t
151a_gid(char *s)
152{
153	struct group *gr;
154	char *gname;
155	gid_t gid;
156
157	if ((gr = getgrnam(s)) != NULL)
158		gid = gr->gr_gid;
159	else {
160		for (gname = s; *s && isdigit(*s); ++s);
161		if (!*s)
162			gid = atoi(gname);
163		else
164			errx(EX_NOUSER, "unknown group id: %s", gname);
165	}
166	return (gid);
167}
168
169uid_t
170a_uid(char *s)
171{
172	struct passwd *pw;
173	char *uname;
174	uid_t uid;
175
176	if ((pw = getpwnam(s)) != NULL)
177		uid = pw->pw_uid;
178	else {
179		for (uname = s; *s && isdigit(*s); ++s);
180		if (!*s)
181			uid = atoi(uname);
182		else
183			errx(EX_NOUSER, "unknown user id: %s", uname);
184	}
185	return (uid);
186}
187
188mode_t
189a_mask(char *s)
190{
191	int done, rv=0;
192	char *ep;
193
194	done = 0;
195	if (*s >= '0' && *s <= '7') {
196		done = 1;
197		rv = strtol(optarg, &ep, 8);
198	}
199	if (!done || rv < 0 || *ep)
200		errx(EX_USAGE, "invalid file mode: %s", s);
201	return (rv);
202}
203
204void
205usage(void)
206{
207	fprintf(stderr, "usage: mount_hpfs [-u user] [-g group] [-m mask] bdev dir\n");
208	exit(EX_USAGE);
209}
210
211void
212load_u2wtable (struct hpfs_args *pargs, char *name)
213{
214	FILE *f;
215	int i, code;
216	char buf[128];
217	char *fn;
218
219	if (*name == '/')
220		fn = name;
221	else {
222		snprintf(buf, sizeof(buf), "/usr/libdata/msdosfs/%s", name);
223		buf[127] = '\0';
224		fn = buf;
225	}
226	if ((f = fopen(fn, "r")) == NULL)
227		err(EX_NOINPUT, "%s", fn);
228	for (i = 0; i < 128; i++) {
229		if (fscanf(f, "%i", &code) != 1)
230			errx(EX_DATAERR, "u2w: missing item number %d", i);
231		/* pargs->u2w[i] = code; */
232	}
233	for (i = 0; i < 128; i++) {
234		if (fscanf(f, "%i", &code) != 1)
235			errx(EX_DATAERR, "d2u: missing item number %d", i);
236		pargs->d2u[i] = code;
237	}
238	for (i = 0; i < 128; i++) {
239		if (fscanf(f, "%i", &code) != 1)
240			errx(EX_DATAERR, "u2d: missing item number %d", i);
241		pargs->u2d[i] = code;
242	}
243	fclose(f);
244}
245