devfs.c revision 100805
1100206Sdd/*-
2100799Sdd * Copyright (c) 2001, 2002 Dima Dorfman.
3100206Sdd * All rights reserved.
4100206Sdd *
5100206Sdd * Redistribution and use in source and binary forms, with or without
6100206Sdd * modification, are permitted provided that the following conditions
7100206Sdd * are met:
8100206Sdd * 1. Redistributions of source code must retain the above copyright
9100206Sdd *    notice, this list of conditions and the following disclaimer.
10100206Sdd * 2. Redistributions in binary form must reproduce the above copyright
11100206Sdd *    notice, this list of conditions and the following disclaimer in the
12100206Sdd *    documentation and/or other materials provided with the distribution.
13100206Sdd *
14100206Sdd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15100206Sdd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16100206Sdd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17100206Sdd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18100206Sdd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19100206Sdd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20100206Sdd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21100206Sdd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22100206Sdd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23100206Sdd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24100206Sdd * SUCH DAMAGE.
25100206Sdd */
26100206Sdd
27100206Sdd/*
28100206Sdd * DEVFS control.
29100206Sdd */
30100206Sdd
31100206Sdd#include <sys/cdefs.h>
32100206Sdd__FBSDID("$FreeBSD: head/sbin/devfs/devfs.c 100805 2002-07-28 06:59:40Z dd $");
33100206Sdd
34100206Sdd#include <sys/param.h>
35100799Sdd#include <sys/queue.h>
36100206Sdd
37100799Sdd#include <assert.h>
38100206Sdd#include <err.h>
39100206Sdd#include <fcntl.h>
40100206Sdd#include <paths.h>
41100206Sdd#include <stdio.h>
42100206Sdd#include <stdlib.h>
43100206Sdd#include <string.h>
44100206Sdd#include <unistd.h>
45100206Sdd
46100206Sdd#include "extern.h"
47100206Sdd
48100206Sddint mpfd;
49100206Sdd
50100206Sddstatic ctbl_t ctbl_main = {
51100206Sdd	{ "rule",		rule_main },
52100206Sdd	{ "ruleset",		ruleset_main },
53100206Sdd	{ NULL,			NULL }
54100206Sdd};
55100206Sdd
56100206Sddint
57100206Sddmain(int ac, char **av)
58100206Sdd{
59100206Sdd	const char *mountpt;
60100206Sdd	struct cmd *c;
61100206Sdd	char ch;
62100206Sdd
63100206Sdd	mountpt = NULL;
64100206Sdd	while ((ch = getopt(ac, av, "m:")) != -1)
65100206Sdd		switch (ch) {
66100206Sdd		case 'm':
67100206Sdd			mountpt = optarg;
68100206Sdd			break;
69100206Sdd		default:
70100206Sdd			usage();
71100206Sdd		}
72100206Sdd	ac -= optind;
73100206Sdd	av += optind;
74100206Sdd	if (ac < 1)
75100206Sdd		usage();
76100206Sdd
77100206Sdd	if (mountpt == NULL)
78100206Sdd		mountpt = _PATH_DEV;
79100206Sdd	mpfd = open(mountpt, O_RDONLY);
80100206Sdd	if (mpfd == -1)
81100206Sdd		err(1, "open: %s", mountpt);
82100206Sdd
83100206Sdd	for (c = ctbl_main; c->name != NULL; ++c)
84100206Sdd		if (strcmp(c->name, av[0]) == 0)
85100206Sdd			exit((*c->handler)(ac, av));
86100206Sdd	errx(1, "unknown command: %s", av[0]);
87100206Sdd}
88100206Sdd
89100206Sdd/*
90100206Sdd * Convert an integer to a "number" (ruleset numbers and rule numbers
91100206Sdd * are 16-bit).  If the conversion is successful, num contains the
92100206Sdd * integer representation of s and 1 is returned; otherwise, 0 is
93100206Sdd * returned and num is unchanged.
94100206Sdd */
95100206Sddint
96100206Sddatonum(const char *s, uint16_t *num)
97100206Sdd{
98100206Sdd	unsigned long ul;
99100206Sdd	char *cp;
100100206Sdd
101100206Sdd	ul = strtoul(s, &cp, 10);
102100206Sdd	if (ul > UINT16_MAX || *cp != '\0')
103100206Sdd		return (0);
104100206Sdd	*num = (uint16_t)ul;
105100206Sdd	return (1);
106100206Sdd}
107100206Sdd
108100206Sdd/*
109100206Sdd * Convert user input in ASCII to an integer.
110100206Sdd */
111100206Sddint
112100206Sddeatoi(const char *s)
113100206Sdd{
114100206Sdd	char *cp;
115100206Sdd	long l;
116100206Sdd
117100206Sdd	l = strtol(s, &cp, 10);
118100206Sdd	if (l > INT_MAX || *cp != '\0')
119100206Sdd		errx(1, "error converting to integer: %s", s);
120100206Sdd	return ((int)l);
121100805Sdd}
122100206Sdd
123100206Sdd/*
124100206Sdd * As atonum(), but the result of failure is death.
125100206Sdd */
126100206Sdduint16_t
127100206Sddeatonum(const char *s)
128100206Sdd{
129100206Sdd	uint16_t num;
130100206Sdd
131100206Sdd	if (!atonum(s, &num))
132100206Sdd		errx(1, "error converting to number: %s", s); /* XXX clarify */
133100206Sdd	return (num);
134100805Sdd}
135100206Sdd
136100799Sdd/*
137100799Sdd * Read a line from a /FILE/.  If the return value isn't 0, it is the
138100799Sdd * length of the line, a pointer to which exists in /line/.  It is the
139100799Sdd * caller's responsibility to free(3) it.  If the return value is 0,
140100799Sdd * there was an error or we reached EOF, and /line/ is undefined (so,
141100799Sdd * obviously, the caller shouldn't try to free(3) it).
142100799Sdd */
143100799Sddsize_t
144100799Sddefgetln(FILE *fp, char **line)
145100799Sdd{
146100799Sdd	size_t rv;
147100799Sdd	char *cp;
148100799Sdd
149100799Sdd	cp = fgetln(fp, &rv);
150100799Sdd	if (cp == NULL) {
151100799Sdd		*line = NULL;
152100799Sdd		return (rv);
153100799Sdd	}
154100799Sdd	if (cp[rv - 1] == '\n') {
155100799Sdd		cp[rv - 1] = '\0';
156100799Sdd		*line = strdup(cp);
157100799Sdd		if (*line == NULL)
158100799Sdd			errx(1, "cannot allocate memory");
159100799Sdd		--rv;
160100799Sdd	} else {
161100799Sdd		*line = malloc(rv + 1);
162100799Sdd		if (*line == NULL)
163100799Sdd			errx(1, "cannot allocate memory");
164100799Sdd		memcpy(*line, cp, rv);
165100799Sdd		*line[rv] = '\0';
166100799Sdd	}
167100799Sdd	assert(rv == strlen(*line));
168100799Sdd	return (rv);
169100799Sdd}
170100799Sdd
171100799Sddstruct ptrstq {
172100799Sdd	STAILQ_ENTRY(ptrstq)	 tq;
173100799Sdd	void			*ptr;
174100799Sdd};
175100799Sdd
176100799Sdd/*
177100799Sdd * Create an argument vector from /line/.  The caller must free(3)
178100799Sdd * /avp/, and /avp[0]/ when the argument vector is no longer
179100799Sdd * needed unless /acp/ is 0, in which case /avp/ is undefined.
180100799Sdd * /avp/ is NULL-terminated, so it is actually one longer than /acp/.
181100799Sdd */
182100206Sddvoid
183100799Sddtokenize(const char *line, int *acp, char ***avp)
184100799Sdd{
185100799Sdd	static const char *delims = " \t\n";
186100799Sdd	struct ptrstq *pt;
187100799Sdd	STAILQ_HEAD(, ptrstq) plist;
188100799Sdd	char **ap, *cp, *wline, *xcp;
189100799Sdd
190100799Sdd	line += strspn(line, delims);
191100799Sdd	wline = strdup(line);
192100799Sdd	if (wline == NULL)
193100799Sdd		errx(1, "cannot allocate memory");
194100799Sdd
195100799Sdd	STAILQ_INIT(&plist);
196100799Sdd	for (xcp = wline, *acp = 0;
197100799Sdd	     (cp = strsep(&xcp, delims)) != NULL;)
198100799Sdd		if (*cp != '\0') {
199100799Sdd			pt = calloc(1, sizeof(*pt));
200100799Sdd			if (pt == NULL)
201100799Sdd				errx(1, "cannot allocate memory");
202100799Sdd			pt->ptr = cp;
203100799Sdd			STAILQ_INSERT_TAIL(&plist, pt, tq);
204100799Sdd			++*acp;
205100799Sdd		}
206100799Sdd	if (*acp == 0)
207100799Sdd		return;
208100799Sdd	assert(STAILQ_FIRST(&plist)->ptr == wline);
209100799Sdd	*avp = malloc(sizeof(**avp) * (*acp + 1));
210100799Sdd	if (*avp == NULL)
211100799Sdd		errx(1, "cannot allocate memory");
212100799Sdd	for (ap = *avp; !STAILQ_EMPTY(&plist);) {
213100799Sdd		pt = STAILQ_FIRST(&plist);
214100799Sdd		*ap = pt->ptr;
215100799Sdd		++ap;
216100799Sdd		assert(ap <= *avp + (*acp));
217100799Sdd		STAILQ_REMOVE_HEAD(&plist, tq);
218100799Sdd		free(pt);
219100799Sdd	}
220100799Sdd	*ap = NULL;
221100799Sdd}
222100799Sdd
223100799Sddvoid
224100206Sddusage(void)
225100206Sdd{
226100206Sdd
227100206Sdd	fprintf(stderr, "usage: devfs rule|ruleset arguments\n");
228100206Sdd	exit(1);
229100206Sdd}
230