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: stable/10/sbin/devfs/devfs.c 315355 2017-03-16 01:59:43Z ngie $");
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>
42100881Smike#include <stdint.h>
43100206Sdd#include <stdlib.h>
44100206Sdd#include <string.h>
45100206Sdd#include <unistd.h>
46100206Sdd
47100206Sdd#include "extern.h"
48100206Sdd
49100206Sddint mpfd;
50100206Sdd
51100206Sddstatic ctbl_t ctbl_main = {
52100206Sdd	{ "rule",		rule_main },
53100206Sdd	{ "ruleset",		ruleset_main },
54100206Sdd	{ NULL,			NULL }
55100206Sdd};
56100206Sdd
57100206Sddint
58100206Sddmain(int ac, char **av)
59100206Sdd{
60100206Sdd	const char *mountpt;
61100206Sdd	struct cmd *c;
62124830Sgrehan	int ch;
63100206Sdd
64100206Sdd	mountpt = NULL;
65100206Sdd	while ((ch = getopt(ac, av, "m:")) != -1)
66100206Sdd		switch (ch) {
67100206Sdd		case 'm':
68100206Sdd			mountpt = optarg;
69100206Sdd			break;
70100206Sdd		default:
71100206Sdd			usage();
72100206Sdd		}
73100206Sdd	ac -= optind;
74100206Sdd	av += optind;
75100206Sdd	if (ac < 1)
76100206Sdd		usage();
77100206Sdd
78100206Sdd	if (mountpt == NULL)
79100206Sdd		mountpt = _PATH_DEV;
80100206Sdd	mpfd = open(mountpt, O_RDONLY);
81100206Sdd	if (mpfd == -1)
82100206Sdd		err(1, "open: %s", mountpt);
83100206Sdd
84100206Sdd	for (c = ctbl_main; c->name != NULL; ++c)
85100206Sdd		if (strcmp(c->name, av[0]) == 0)
86100206Sdd			exit((*c->handler)(ac, av));
87100206Sdd	errx(1, "unknown command: %s", av[0]);
88100206Sdd}
89100206Sdd
90100206Sdd/*
91100206Sdd * Convert an integer to a "number" (ruleset numbers and rule numbers
92100206Sdd * are 16-bit).  If the conversion is successful, num contains the
93100206Sdd * integer representation of s and 1 is returned; otherwise, 0 is
94100206Sdd * returned and num is unchanged.
95100206Sdd */
96100206Sddint
97100206Sddatonum(const char *s, uint16_t *num)
98100206Sdd{
99100206Sdd	unsigned long ul;
100100206Sdd	char *cp;
101100206Sdd
102100206Sdd	ul = strtoul(s, &cp, 10);
103100206Sdd	if (ul > UINT16_MAX || *cp != '\0')
104100206Sdd		return (0);
105100206Sdd	*num = (uint16_t)ul;
106100206Sdd	return (1);
107100206Sdd}
108100206Sdd
109100206Sdd/*
110100206Sdd * Convert user input in ASCII to an integer.
111100206Sdd */
112100206Sddint
113100206Sddeatoi(const char *s)
114100206Sdd{
115100206Sdd	char *cp;
116100206Sdd	long l;
117100206Sdd
118100206Sdd	l = strtol(s, &cp, 10);
119100206Sdd	if (l > INT_MAX || *cp != '\0')
120100206Sdd		errx(1, "error converting to integer: %s", s);
121100206Sdd	return ((int)l);
122100805Sdd}
123100206Sdd
124100206Sdd/*
125100206Sdd * As atonum(), but the result of failure is death.
126100206Sdd */
127100206Sdduint16_t
128100206Sddeatonum(const char *s)
129100206Sdd{
130100206Sdd	uint16_t num;
131100206Sdd
132100206Sdd	if (!atonum(s, &num))
133100206Sdd		errx(1, "error converting to number: %s", s); /* XXX clarify */
134100206Sdd	return (num);
135100805Sdd}
136100206Sdd
137100799Sdd/*
138100799Sdd * Read a line from a /FILE/.  If the return value isn't 0, it is the
139100799Sdd * length of the line, a pointer to which exists in /line/.  It is the
140100799Sdd * caller's responsibility to free(3) it.  If the return value is 0,
141100799Sdd * there was an error or we reached EOF, and /line/ is undefined (so,
142100799Sdd * obviously, the caller shouldn't try to free(3) it).
143100799Sdd */
144100799Sddsize_t
145100799Sddefgetln(FILE *fp, char **line)
146100799Sdd{
147100799Sdd	size_t rv;
148100799Sdd	char *cp;
149100799Sdd
150100799Sdd	cp = fgetln(fp, &rv);
151100799Sdd	if (cp == NULL) {
152100799Sdd		*line = NULL;
153100799Sdd		return (rv);
154100799Sdd	}
155100799Sdd	if (cp[rv - 1] == '\n') {
156100799Sdd		cp[rv - 1] = '\0';
157100799Sdd		*line = strdup(cp);
158100799Sdd		if (*line == NULL)
159100799Sdd			errx(1, "cannot allocate memory");
160100799Sdd		--rv;
161100799Sdd	} else {
162100799Sdd		*line = malloc(rv + 1);
163100799Sdd		if (*line == NULL)
164100799Sdd			errx(1, "cannot allocate memory");
165159605Smaxim		memcpy(*line, cp, rv);
166159605Smaxim		(*line)[rv] = '\0';
167100799Sdd	}
168100799Sdd	assert(rv == strlen(*line));
169100799Sdd	return (rv);
170100799Sdd}
171100799Sdd
172100799Sddstruct ptrstq {
173100799Sdd	STAILQ_ENTRY(ptrstq)	 tq;
174100799Sdd	void			*ptr;
175100799Sdd};
176100799Sdd
177100799Sdd/*
178100799Sdd * Create an argument vector from /line/.  The caller must free(3)
179100799Sdd * /avp/, and /avp[0]/ when the argument vector is no longer
180100799Sdd * needed unless /acp/ is 0, in which case /avp/ is undefined.
181100799Sdd * /avp/ is NULL-terminated, so it is actually one longer than /acp/.
182100799Sdd */
183100206Sddvoid
184100799Sddtokenize(const char *line, int *acp, char ***avp)
185100799Sdd{
186100799Sdd	static const char *delims = " \t\n";
187100799Sdd	struct ptrstq *pt;
188100799Sdd	STAILQ_HEAD(, ptrstq) plist;
189100799Sdd	char **ap, *cp, *wline, *xcp;
190100799Sdd
191100799Sdd	line += strspn(line, delims);
192100799Sdd	wline = strdup(line);
193100799Sdd	if (wline == NULL)
194100799Sdd		errx(1, "cannot allocate memory");
195100799Sdd
196100799Sdd	STAILQ_INIT(&plist);
197100799Sdd	for (xcp = wline, *acp = 0;
198100799Sdd	     (cp = strsep(&xcp, delims)) != NULL;)
199100799Sdd		if (*cp != '\0') {
200100799Sdd			pt = calloc(1, sizeof(*pt));
201100799Sdd			if (pt == NULL)
202100799Sdd				errx(1, "cannot allocate memory");
203100799Sdd			pt->ptr = cp;
204100799Sdd			STAILQ_INSERT_TAIL(&plist, pt, tq);
205100799Sdd			++*acp;
206100799Sdd		}
207100799Sdd	if (*acp == 0)
208100799Sdd		return;
209100799Sdd	assert(STAILQ_FIRST(&plist)->ptr == wline);
210100799Sdd	*avp = malloc(sizeof(**avp) * (*acp + 1));
211100799Sdd	if (*avp == NULL)
212100799Sdd		errx(1, "cannot allocate memory");
213100799Sdd	for (ap = *avp; !STAILQ_EMPTY(&plist);) {
214100799Sdd		pt = STAILQ_FIRST(&plist);
215100799Sdd		*ap = pt->ptr;
216100799Sdd		++ap;
217100799Sdd		assert(ap <= *avp + (*acp));
218100799Sdd		STAILQ_REMOVE_HEAD(&plist, tq);
219100799Sdd		free(pt);
220100799Sdd	}
221100799Sdd	*ap = NULL;
222100799Sdd}
223100799Sdd
224100799Sddvoid
225100206Sddusage(void)
226100206Sdd{
227100206Sdd
228315355Sngie	fprintf(stderr, "usage: %s\n%s\n",
229315355Sngie	    "\tdevfs [-m mount-point] [-s ruleset] rule ...",
230315355Sngie	    "\tdevfs [-m mount-point] ruleset ...");
231100206Sdd	exit(1);
232100206Sdd}
233