1/*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 1985, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#ifndef lint
33static const char copyright[] =
34"@(#) Copyright (c) 1985, 1993\n\
35	The Regents of the University of California.  All rights reserved.\n";
36#endif /* not lint */
37
38#ifndef lint
39#if 0
40static char sccsid[] = "@(#)timedc.c	8.1 (Berkeley) 6/6/93";
41#endif
42static const char rcsid[] =
43  "$FreeBSD$";
44#endif /* not lint */
45
46#include "timedc.h"
47#include <ctype.h>
48#include <err.h>
49#include <setjmp.h>
50#include <signal.h>
51#include <stdlib.h>
52#include <string.h>
53#include <syslog.h>
54#include <unistd.h>
55
56int trace = 0;
57FILE *fd = NULL;
58int	margc;
59int	fromatty;
60#define	MAX_MARGV	20
61char	*margv[MAX_MARGV];
62char	cmdline[200];
63jmp_buf	toplevel;
64static struct cmd *getcmd(char *);
65
66int
67main(int argc, char *argv[])
68{
69	register struct cmd *c;
70
71	openlog("timedc", 0, LOG_AUTH);
72
73	/*
74	 * security dictates!
75	 */
76	if (priv_resources() < 0)
77		errx(1, "could not get privileged resources");
78	if (setuid(getuid()) != 0)
79		err(1, "setuid()");
80
81	if (--argc > 0) {
82		c = getcmd(*++argv);
83		if (c == (struct cmd *)-1) {
84			printf("?Ambiguous command\n");
85			exit(1);
86		}
87		if (c == NULL) {
88			printf("?Invalid command\n");
89			exit(1);
90		}
91		if (c->c_priv && getuid()) {
92			printf("?Privileged command\n");
93			exit(1);
94		}
95		(*c->c_handler)(argc, argv);
96		exit(0);
97	}
98
99	fromatty = isatty(fileno(stdin));
100	if (fromatty)
101		printf("TIMEDC will be removed from FreeBSD-13, and will be "
102		    "provided as a port (net/timed) or package (timed).\n");
103	if (setjmp(toplevel))
104		putchar('\n');
105	(void) signal(SIGINT, intr);
106	for (;;) {
107		if (fromatty) {
108			printf("timedc> ");
109			(void) fflush(stdout);
110		}
111		if (fgets(cmdline, sizeof(cmdline), stdin) == NULL)
112			quit();
113		if (cmdline[0] == 0)
114			break;
115		makeargv();
116		if (margv[0] == NULL)
117			continue;
118		c = getcmd(margv[0]);
119		if (c == (struct cmd *)-1) {
120			printf("?Ambiguous command\n");
121			continue;
122		}
123		if (c == NULL) {
124			printf("?Invalid command\n");
125			continue;
126		}
127		if (c->c_priv && getuid()) {
128			printf("?Privileged command\n");
129			continue;
130		}
131		(*c->c_handler)(margc, margv);
132	}
133	return 0;
134}
135
136void
137intr(int signo __unused)
138{
139	if (!fromatty)
140		exit(0);
141	longjmp(toplevel, 1);
142}
143
144
145static struct cmd *
146getcmd(char *name)
147{
148	register char *p, *q;
149	register struct cmd *c, *found;
150	register int nmatches, longest;
151	extern int NCMDS;
152
153	longest = 0;
154	nmatches = 0;
155	found = NULL;
156	for (c = cmdtab; c < &cmdtab[NCMDS]; c++) {
157		p = c->c_name;
158		for (q = name; *q == *p++; q++)
159			if (*q == 0)		/* exact match? */
160				return(c);
161		if (!*q) {			/* the name was a prefix */
162			if (q - name > longest) {
163				longest = q - name;
164				nmatches = 1;
165				found = c;
166			} else if (q - name == longest)
167				nmatches++;
168		}
169	}
170	if (nmatches > 1)
171		return((struct cmd *)-1);
172	return(found);
173}
174
175/*
176 * Slice a string up into argc/argv.
177 */
178void
179makeargv(void)
180{
181	register char *cp;
182	register char **argp = margv;
183
184	margc = 0;
185	for (cp = cmdline; margc < MAX_MARGV - 1 && *cp; ) {
186		while (isspace(*cp))
187			cp++;
188		if (*cp == '\0')
189			break;
190		*argp++ = cp;
191		margc += 1;
192		while (*cp != '\0' && !isspace(*cp))
193			cp++;
194		if (*cp == '\0')
195			break;
196		*cp++ = '\0';
197	}
198	*argp++ = NULL;
199}
200
201#define HELPINDENT (sizeof ("directory"))
202
203/*
204 * Help command.
205 */
206void
207help(int argc, char *argv[])
208{
209	register struct cmd *c;
210
211	if (argc == 1) {
212		register int i, j, w;
213		int columns, width = 0, lines;
214		extern int NCMDS;
215
216		printf("Commands may be abbreviated.  Commands are:\n\n");
217		for (c = cmdtab; c < &cmdtab[NCMDS]; c++) {
218			int len = strlen(c->c_name);
219
220			if (len > width)
221				width = len;
222		}
223		width = (width + 8) &~ 7;
224		columns = 80 / width;
225		if (columns == 0)
226			columns = 1;
227		lines = (NCMDS + columns - 1) / columns;
228		for (i = 0; i < lines; i++) {
229			for (j = 0; j < columns; j++) {
230				c = cmdtab + j * lines + i;
231				printf("%s", c->c_name);
232				if (c + lines >= &cmdtab[NCMDS]) {
233					printf("\n");
234					break;
235				}
236				w = strlen(c->c_name);
237				while (w < width) {
238					w = (w + 8) &~ 7;
239					putchar('\t');
240				}
241			}
242		}
243		return;
244	}
245	while (--argc > 0) {
246		register char *arg;
247		arg = *++argv;
248		c = getcmd(arg);
249		if (c == (struct cmd *)-1)
250			printf("?Ambiguous help command %s\n", arg);
251		else if (c == (struct cmd *)0)
252			printf("?Invalid help command %s\n", arg);
253		else
254			printf("%-*s\t%s\n", (int)HELPINDENT,
255				c->c_name, c->c_help);
256	}
257}
258