1/*	$NetBSD: mount_tmpfs.c,v 1.23 2008/07/28 12:42:12 pooka Exp $	*/
2
3/*
4 * Copyright (c) 2005, 2006 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Julio M. Merino Vidal, developed as part of Google's Summer of Code
9 * 2005 program.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33#include <sys/cdefs.h>
34#ifndef lint
35__RCSID("$NetBSD: mount_tmpfs.c,v 1.23 2008/07/28 12:42:12 pooka Exp $");
36#endif /* not lint */
37
38#include <sys/param.h>
39#include <sys/mount.h>
40#include <sys/stat.h>
41
42#include <fs/tmpfs/tmpfs_args.h>
43
44#include <ctype.h>
45#include <err.h>
46#include <errno.h>
47#include <grp.h>
48#include <mntopts.h>
49#include <pwd.h>
50#include <stdio.h>
51#include <stdlib.h>
52#include <string.h>
53#include <unistd.h>
54
55#include "mountprog.h"
56#include "mount_tmpfs.h"
57
58/* --------------------------------------------------------------------- */
59
60static const struct mntopt mopts[] = {
61	MOPT_STDOPTS,
62	MOPT_GETARGS,
63	MOPT_NULL,
64};
65
66/* --------------------------------------------------------------------- */
67
68static void	usage(void) __dead;
69
70/* --------------------------------------------------------------------- */
71
72void
73mount_tmpfs_parseargs(int argc, char *argv[],
74	struct tmpfs_args *args, int *mntflags,
75	char *canon_dev, char *canon_dir)
76{
77	int gidset, modeset, uidset; /* Ought to be 'bool'. */
78	int ch;
79	gid_t gid;
80	uid_t uid;
81	mode_t mode;
82	int64_t tmpnumber;
83	mntoptparse_t mp;
84	struct stat sb;
85
86	/* Set default values for mount point arguments. */
87	memset(args, 0, sizeof(*args));
88	args->ta_version = TMPFS_ARGS_VERSION;
89	args->ta_size_max = 0;
90	args->ta_nodes_max = 0;
91	*mntflags = 0;
92
93	gidset = 0; gid = 0;
94	uidset = 0; uid = 0;
95	modeset = 0; mode = 0;
96
97	optind = optreset = 1;
98	while ((ch = getopt(argc, argv, "g:m:n:o:s:u:")) != -1 ) {
99		switch (ch) {
100		case 'g':
101			gid = a_gid(optarg);
102			gidset = 1;
103			break;
104
105		case 'm':
106			mode = a_mask(optarg);
107			modeset = 1;
108			break;
109
110		case 'n':
111			if (dehumanize_number(optarg, &tmpnumber) == -1)
112				err(EXIT_FAILURE, "failed to parse nodes `%s'",
113				    optarg);
114			args->ta_nodes_max = tmpnumber;
115			break;
116
117		case 'o':
118			mp = getmntopts(optarg, mopts, mntflags, 0);
119			if (mp == NULL)
120				err(EXIT_FAILURE, "getmntopts");
121			freemntopts(mp);
122			break;
123
124		case 's':
125			if (dehumanize_number(optarg, &tmpnumber) == -1)
126				err(EXIT_FAILURE, "failed to parse size `%s'",
127				    optarg);
128			args->ta_size_max = tmpnumber;
129			break;
130
131		case 'u':
132			uid = a_uid(optarg);
133			uidset = 1;
134			break;
135
136		case '?':
137		default:
138			usage();
139		}
140	}
141	argc -= optind;
142	argv += optind;
143
144	if (argc != 2)
145		usage();
146
147	strlcpy(canon_dev, argv[0], MAXPATHLEN);
148	pathadj(argv[1], canon_dir);
149
150	if (stat(canon_dir, &sb) == -1)
151		err(EXIT_FAILURE, "cannot stat `%s'", canon_dir);
152
153	args->ta_root_uid = uidset ? uid : sb.st_uid;
154	args->ta_root_gid = gidset ? gid : sb.st_gid;
155	args->ta_root_mode = modeset ? mode : sb.st_mode;
156}
157
158/* --------------------------------------------------------------------- */
159
160static void
161usage(void)
162{
163	(void)fprintf(stderr,
164	    "Usage: %s [-g group] [-m mode] [-n nodes] [-o options] [-s size]\n"
165	    "           [-u user] tmpfs mountpoint\n", getprogname());
166	exit(1);
167}
168
169/* --------------------------------------------------------------------- */
170
171int
172mount_tmpfs(int argc, char *argv[])
173{
174	struct tmpfs_args args;
175	char canon_dev[MAXPATHLEN], canon_dir[MAXPATHLEN];
176	int mntflags;
177
178	mount_tmpfs_parseargs(argc, argv, &args, &mntflags,
179	    canon_dev, canon_dir);
180
181	if (mount(MOUNT_TMPFS, canon_dir, mntflags, &args, sizeof args) == -1)
182		err(EXIT_FAILURE, "tmpfs on %s", canon_dir);
183
184	if (mntflags & MNT_GETARGS) {
185		struct passwd *pw;
186		struct group *gr;
187
188		(void)printf("version=%d, ", args.ta_version);
189		(void)printf("size_max=%" PRIuMAX ", ",
190		    (uintmax_t)args.ta_size_max);
191		(void)printf("nodes_max=%" PRIuMAX ", ",
192		    (uintmax_t)args.ta_nodes_max);
193
194		pw = getpwuid(args.ta_root_uid);
195		if (pw == NULL)
196			(void)printf("root_uid=%" PRIuMAX ", ",
197			    (uintmax_t)args.ta_root_uid);
198		else
199			(void)printf("root_uid=%s, ", pw->pw_name);
200
201		gr = getgrgid(args.ta_root_gid);
202		if (gr == NULL)
203			(void)printf("root_gid=%" PRIuMAX ", ",
204			    (uintmax_t)args.ta_root_gid);
205		else
206			(void)printf("root_gid=%s, ", gr->gr_name);
207
208		(void)printf("root_mode=%o\n", args.ta_root_mode);
209	}
210
211	return EXIT_SUCCESS;
212}
213
214#ifndef MOUNT_NOMAIN
215int
216main(int argc, char *argv[])
217{
218
219	setprogname(argv[0]);
220	return mount_tmpfs(argc, argv);
221}
222#endif
223