154371Ssemenu/*
254371Ssemenu * Copyright (c) 1994 Christopher G. Demetriou
354371Ssemenu * Copyright (c) 1999 Semen Ustimenko (semenu@FreeBSD.org)
454371Ssemenu * All rights reserved.
554371Ssemenu *
654371Ssemenu * Redistribution and use in source and binary forms, with or without
754371Ssemenu * modification, are permitted provided that the following conditions
854371Ssemenu * are met:
954371Ssemenu * 1. Redistributions of source code must retain the above copyright
1054371Ssemenu *    notice, this list of conditions and the following disclaimer.
1154371Ssemenu * 2. Redistributions in binary form must reproduce the above copyright
1254371Ssemenu *    notice, this list of conditions and the following disclaimer in the
1354371Ssemenu *    documentation and/or other materials provided with the distribution.
1454371Ssemenu * 3. All advertising materials mentioning features or use of this software
1554371Ssemenu *    must display the following acknowledgement:
1654371Ssemenu *      This product includes software developed by Christopher G. Demetriou.
1754371Ssemenu * 4. The name of the author may not be used to endorse or promote products
1854371Ssemenu *    derived from this software without specific prior written permission
1954371Ssemenu *
2054371Ssemenu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2154371Ssemenu * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2254371Ssemenu * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2354371Ssemenu * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2454371Ssemenu * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2554371Ssemenu * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2654371Ssemenu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2754371Ssemenu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2854371Ssemenu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2954371Ssemenu * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3054371Ssemenu *
3154371Ssemenu * $FreeBSD$
3254371Ssemenu */
3354371Ssemenu
3454371Ssemenu#include <sys/cdefs.h>
3554371Ssemenu#include <sys/param.h>
3654371Ssemenu#include <sys/mount.h>
3754371Ssemenu#include <sys/stat.h>
3854371Ssemenu#include <fs/hpfs/hpfsmount.h>
3954371Ssemenu#include <ctype.h>
4054371Ssemenu#include <err.h>
4154371Ssemenu#include <grp.h>
4254371Ssemenu#include <pwd.h>
4354371Ssemenu#include <stdio.h>
4454371Ssemenu#include <stdlib.h>
4554371Ssemenu#include <string.h>
4654371Ssemenu#include <sysexits.h>
4754371Ssemenu#include <unistd.h>
4854371Ssemenu
4954371Ssemenu#include "mntopts.h"
5054371Ssemenu
5154371Ssemenustatic struct mntopt mopts[] = {
5254371Ssemenu	MOPT_STDOPTS,
53147242Sdelphij	MOPT_END
5454371Ssemenu};
5554371Ssemenu
5692882Simpstatic gid_t	a_gid(char *);
5792882Simpstatic uid_t	a_uid(char *);
5892882Simpstatic mode_t	a_mask(char *);
5992882Simpstatic void	usage(void) __dead2;
6092882Simpstatic void	load_u2wtable(struct hpfs_args *, char *);
6154371Ssemenu
6254371Ssemenuint
63204403Suqsmain(int argc, char *argv[])
6454371Ssemenu{
6554371Ssemenu	struct hpfs_args args;
6654371Ssemenu	struct stat sb;
67101270Smux	int c, mntflags, set_gid, set_uid, set_mask;
6854371Ssemenu	int forcerw = 0;
69118579Simp	char *dev, *dir, ndir[MAXPATHLEN];
7054371Ssemenu
7154371Ssemenu	mntflags = set_gid = set_uid = set_mask = 0;
7254371Ssemenu	(void)memset(&args, '\0', sizeof(args));
7354371Ssemenu
7454371Ssemenu	while ((c = getopt(argc, argv, "u:g:m:o:c:W:F")) !=  -1) {
7554371Ssemenu		switch (c) {
7654371Ssemenu		case 'F':
7754371Ssemenu			forcerw=1;
7854371Ssemenu			break;
7954371Ssemenu		case 'u':
8054371Ssemenu			args.uid = a_uid(optarg);
8154371Ssemenu			set_uid = 1;
8254371Ssemenu			break;
8354371Ssemenu		case 'g':
8454371Ssemenu			args.gid = a_gid(optarg);
8554371Ssemenu			set_gid = 1;
8654371Ssemenu			break;
8754371Ssemenu		case 'm':
8854371Ssemenu			args.mode = a_mask(optarg);
8954371Ssemenu			set_mask = 1;
9054371Ssemenu			break;
9154371Ssemenu		case 'o':
9254371Ssemenu			getmntopts(optarg, mopts, &mntflags, 0);
9354371Ssemenu			break;
9454371Ssemenu		case 'W':
9554371Ssemenu			load_u2wtable(&args, optarg);
9654371Ssemenu			args.flags |= HPFSMNT_TABLES;
9754371Ssemenu			break;
9854371Ssemenu		case '?':
9954371Ssemenu		default:
10054371Ssemenu			usage();
10154371Ssemenu			break;
10254371Ssemenu		}
10354371Ssemenu	}
10454371Ssemenu
10554371Ssemenu	if (optind + 2 != argc)
10654371Ssemenu		usage();
10754371Ssemenu
10854371Ssemenu	if (!(mntflags & MNT_RDONLY) && !forcerw) {
10954371Ssemenu		warnx("Write support is BETA, you need -F flag to enable RW mount!");
11054371Ssemenu		exit (111);
11154371Ssemenu	}
11254371Ssemenu
11354371Ssemenu	dev = argv[optind];
11454371Ssemenu	dir = argv[optind + 1];
11554371Ssemenu	if (dir[0] != '/') {
11654371Ssemenu		warnx("\"%s\" is a relative path", dir);
11754371Ssemenu		if (getcwd(ndir, sizeof(ndir)) == NULL)
11854371Ssemenu			err(EX_OSERR, "getcwd");
11954371Ssemenu		strncat(ndir, "/", sizeof(ndir) - strlen(ndir) - 1);
12054371Ssemenu		strncat(ndir, dir, sizeof(ndir) - strlen(ndir) - 1);
12154371Ssemenu		dir = ndir;
12254371Ssemenu		warnx("using \"%s\" instead", dir);
12354371Ssemenu	}
12454371Ssemenu
12554371Ssemenu	args.fspec = dev;
12654371Ssemenu	args.export.ex_root = 65534;	/* unchecked anyway on DOS fs */
12754371Ssemenu	if (mntflags & MNT_RDONLY)
12854371Ssemenu		args.export.ex_flags = MNT_EXRDONLY;
12954371Ssemenu	else
13054371Ssemenu		args.export.ex_flags = 0;
13154371Ssemenu
13254371Ssemenu	if (!set_gid || !set_uid || !set_mask) {
13354371Ssemenu		if (stat(dir, &sb) == -1)
13454371Ssemenu			err(EX_OSERR, "stat %s", dir);
13554371Ssemenu
13654371Ssemenu		if (!set_uid)
13754371Ssemenu			args.uid = sb.st_uid;
13854371Ssemenu		if (!set_gid)
13954371Ssemenu			args.gid = sb.st_gid;
14054371Ssemenu		if (!set_mask)
14154371Ssemenu			args.mode = sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
14254371Ssemenu	}
14354371Ssemenu
144101270Smux	if (mount("hpfs", dir, mntflags, &args) < 0)
14554371Ssemenu		err(EX_OSERR, "%s", dev);
14654371Ssemenu
14754371Ssemenu	exit (0);
14854371Ssemenu}
14954371Ssemenu
15054371Ssemenugid_t
151204403Suqsa_gid(char *s)
15254371Ssemenu{
15354371Ssemenu	struct group *gr;
15454371Ssemenu	char *gname;
15554371Ssemenu	gid_t gid;
15654371Ssemenu
15754371Ssemenu	if ((gr = getgrnam(s)) != NULL)
15854371Ssemenu		gid = gr->gr_gid;
15954371Ssemenu	else {
16054371Ssemenu		for (gname = s; *s && isdigit(*s); ++s);
16154371Ssemenu		if (!*s)
16254371Ssemenu			gid = atoi(gname);
16354371Ssemenu		else
16454371Ssemenu			errx(EX_NOUSER, "unknown group id: %s", gname);
16554371Ssemenu	}
16654371Ssemenu	return (gid);
16754371Ssemenu}
16854371Ssemenu
16954371Ssemenuuid_t
170204403Suqsa_uid(char *s)
17154371Ssemenu{
17254371Ssemenu	struct passwd *pw;
17354371Ssemenu	char *uname;
17454371Ssemenu	uid_t uid;
17554371Ssemenu
17654371Ssemenu	if ((pw = getpwnam(s)) != NULL)
17754371Ssemenu		uid = pw->pw_uid;
17854371Ssemenu	else {
17954371Ssemenu		for (uname = s; *s && isdigit(*s); ++s);
18054371Ssemenu		if (!*s)
18154371Ssemenu			uid = atoi(uname);
18254371Ssemenu		else
18354371Ssemenu			errx(EX_NOUSER, "unknown user id: %s", uname);
18454371Ssemenu	}
18554371Ssemenu	return (uid);
18654371Ssemenu}
18754371Ssemenu
18854371Ssemenumode_t
189204403Suqsa_mask(char *s)
19054371Ssemenu{
19154371Ssemenu	int done, rv=0;
19254371Ssemenu	char *ep;
19354371Ssemenu
19454371Ssemenu	done = 0;
19554371Ssemenu	if (*s >= '0' && *s <= '7') {
19654371Ssemenu		done = 1;
19754371Ssemenu		rv = strtol(optarg, &ep, 8);
19854371Ssemenu	}
19954371Ssemenu	if (!done || rv < 0 || *ep)
20054371Ssemenu		errx(EX_USAGE, "invalid file mode: %s", s);
20154371Ssemenu	return (rv);
20254371Ssemenu}
20354371Ssemenu
20454371Ssemenuvoid
205204403Suqsusage(void)
20654371Ssemenu{
20754371Ssemenu	fprintf(stderr, "usage: mount_hpfs [-u user] [-g group] [-m mask] bdev dir\n");
20854371Ssemenu	exit(EX_USAGE);
20954371Ssemenu}
21054371Ssemenu
21154371Ssemenuvoid
212204403Suqsload_u2wtable (struct hpfs_args *pargs, char *name)
21354371Ssemenu{
21454371Ssemenu	FILE *f;
21554371Ssemenu	int i, code;
21654371Ssemenu	char buf[128];
21754371Ssemenu	char *fn;
21854371Ssemenu
21954371Ssemenu	if (*name == '/')
22054371Ssemenu		fn = name;
22154371Ssemenu	else {
22254371Ssemenu		snprintf(buf, sizeof(buf), "/usr/libdata/msdosfs/%s", name);
22354371Ssemenu		buf[127] = '\0';
22454371Ssemenu		fn = buf;
22554371Ssemenu	}
22654371Ssemenu	if ((f = fopen(fn, "r")) == NULL)
22754371Ssemenu		err(EX_NOINPUT, "%s", fn);
22854371Ssemenu	for (i = 0; i < 128; i++) {
22954371Ssemenu		if (fscanf(f, "%i", &code) != 1)
23054371Ssemenu			errx(EX_DATAERR, "u2w: missing item number %d", i);
23154371Ssemenu		/* pargs->u2w[i] = code; */
23254371Ssemenu	}
23354371Ssemenu	for (i = 0; i < 128; i++) {
23454371Ssemenu		if (fscanf(f, "%i", &code) != 1)
23554371Ssemenu			errx(EX_DATAERR, "d2u: missing item number %d", i);
23654371Ssemenu		pargs->d2u[i] = code;
23754371Ssemenu	}
23854371Ssemenu	for (i = 0; i < 128; i++) {
23954371Ssemenu		if (fscanf(f, "%i", &code) != 1)
24054371Ssemenu			errx(EX_DATAERR, "u2d: missing item number %d", i);
24154371Ssemenu		pargs->u2d[i] = code;
24254371Ssemenu	}
24354371Ssemenu	fclose(f);
24454371Ssemenu}
245