Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / usr.sbin / lpr / lpc / lpc.c
blobffa859a1d66228405c9b8ff5cb2af162195ae44f
1 /* $NetBSD: lpc.c,v 1.24 2008/07/21 13:36:58 lukem Exp $ */
3 /*
4 * Copyright (c) 1983, 1993
5 * The Regents of the University of California. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
33 #include <sys/cdefs.h>
34 #ifndef lint
35 __COPYRIGHT("@(#) Copyright (c) 1983, 1993\
36 The Regents of the University of California. All rights reserved.");
37 #if 0
38 static char sccsid[] = "@(#)lpc.c 8.3 (Berkeley) 4/28/95";
39 #else
40 __RCSID("$NetBSD: lpc.c,v 1.24 2008/07/21 13:36:58 lukem Exp $");
41 #endif
42 #endif /* not lint */
44 #include <sys/param.h>
46 #include <dirent.h>
47 #include <signal.h>
48 #include <setjmp.h>
49 #include <syslog.h>
50 #include <histedit.h>
51 #include <unistd.h>
52 #include <stdlib.h>
53 #include <stdio.h>
54 #include <ctype.h>
55 #include <string.h>
56 #include <grp.h>
57 #include <err.h>
58 #include "lp.h"
59 #include "lpc.h"
60 #include "extern.h"
62 #ifndef LPR_OPER
63 #define LPR_OPER "operator" /* group name of lpr operators */
64 #endif
67 * lpc -- line printer control program
70 #define MAX_MARGV 20
71 int fromatty;
73 char *cmdline;
74 int margc;
75 char *margv[MAX_MARGV];
76 int top;
77 uid_t uid, euid;
79 jmp_buf toplevel;
81 History *hist;
82 HistEvent he;
83 EditLine *elptr;
85 static void cmdscanner(int);
86 static struct cmd *getcmd(const char *);
87 static void intr(int);
88 static void makeargv(void);
89 static int ingroup(const char *);
90 int main(int, char *p[]);
91 const char *prompt(void);
92 static int parse(char *, char *p[], int);
94 int
95 main(int argc, char *argv[])
97 euid = geteuid();
98 uid = getuid();
99 seteuid(uid);
100 setprogname(argv[0]);
101 openlog("lpd", 0, LOG_LPR);
103 if (--argc > 0) {
104 argv++;
105 exit(!parse(*argv, argv, argc));
107 fromatty = isatty(fileno(stdin));
108 top = setjmp(toplevel) == 0;
109 if (top)
110 signal(SIGINT, intr);
111 for (;;) {
112 cmdscanner(top);
113 top = 1;
117 static int
118 parse(char *arg, char **pargv, int pargc)
120 struct cmd *c;
122 c = getcmd(arg);
123 if (c == (struct cmd *)-1) {
124 printf("?Ambiguous command\n");
125 return(0);
127 if (c == 0) {
128 printf("?Invalid command\n");
129 return(0);
131 if (c->c_priv && getuid() && ingroup(LPR_OPER) == 0) {
132 printf("?Privileged command\n");
133 return(0);
135 (*c->c_handler)(pargc, pargv);
136 return(1);
139 static void
140 intr(int signo)
142 el_end(elptr);
143 history_end(hist);
144 if (!fromatty)
145 exit(0);
146 longjmp(toplevel, 1);
149 const char *
150 prompt(void)
152 return ("lpc> ");
156 * Command parser.
158 static void
159 cmdscanner(int tp)
161 int scratch;
162 const char *elline;
164 if (!tp)
165 putchar('\n');
166 hist = history_init();
167 history(hist, &he, H_SETSIZE, 100); /* 100 elt history buffer */
169 elptr = el_init(getprogname(), stdin, stdout, stderr);
170 el_set(elptr, EL_EDITOR, "emacs");
171 el_set(elptr, EL_PROMPT, prompt);
172 el_set(elptr, EL_HIST, history, hist);
173 el_source(elptr, NULL);
175 for (;;) {
176 cmdline = NULL;
177 do {
178 if (((elline = el_gets(elptr, &scratch)) != NULL)
179 && (scratch != 0)) {
180 history(hist, &he, H_ENTER, elline);
181 cmdline = strdup(elline);
182 makeargv();
183 } else {
184 margc = 0;
185 break;
187 } while (margc == 0);
188 if (margc == 0)
189 quit(0, NULL);
190 if (!parse(cmdline, margv, margc)) {
191 if (cmdline != NULL)
192 free(cmdline);
193 continue;
195 fflush(stdout);
196 if (cmdline != NULL)
197 free(cmdline);
199 longjmp(toplevel, 0);
202 static struct cmd *
203 getcmd(const char *name)
205 const char *p, *q;
206 struct cmd *c, *found;
207 int nmatches, longest;
209 longest = 0;
210 nmatches = 0;
211 found = 0;
212 for (c = cmdtab; (p = c->c_name) != NULL; c++) {
213 for (q = name; *q == *p++; q++)
214 if (*q == 0) /* exact match? */
215 return(c);
216 if (!*q) { /* the name was a prefix */
217 if (q - name > longest) {
218 longest = q - name;
219 nmatches = 1;
220 found = c;
221 } else if (q - name == longest)
222 nmatches++;
225 if (nmatches > 1)
226 return((struct cmd *)-1);
227 return(found);
231 * Slice a string up into argc/argv.
233 static void
234 makeargv(void)
236 char *cp;
237 char **argp = margv;
238 int n = 0;
239 size_t s;
241 s = strlen(cmdline) + 1;
242 margc = 0;
243 for (cp = cmdline; *cp && (size_t)(cp - cmdline) < s && n < MAX_MARGV; n++) {
244 while (isspace((unsigned char)*cp))
245 cp++;
246 if (*cp == '\0')
247 break;
248 *argp++ = cp;
249 margc += 1;
250 while (*cp != '\0' && !isspace((unsigned char)*cp))
251 cp++;
252 if (*cp == '\0')
253 break;
254 *cp++ = '\0';
256 *argp++ = 0;
259 #define HELPINDENT (sizeof ("directory"))
262 * Help command.
264 void
265 help(int argc, char *argv[])
267 struct cmd *c;
269 if (argc == 1) {
270 size_t i, j, w;
271 size_t columns, width = 0, lines;
273 printf("Commands may be abbreviated. Commands are:\n\n");
274 for (c = cmdtab; c->c_name; c++) {
275 size_t len = strlen(c->c_name);
277 if (len > width)
278 width = len;
280 width = (width + 8) &~ 7;
281 columns = 80 / width;
282 if (columns == 0)
283 columns = 1;
284 lines = (NCMDS + columns - 1) / columns;
285 for (i = 0; i < lines; i++) {
286 for (j = 0; j < columns; j++) {
287 c = cmdtab + j * lines + i;
288 printf("%s", c->c_name);
289 if (c + lines >= &cmdtab[NCMDS - 1]) {
290 printf("\n");
291 break;
293 w = strlen(c->c_name);
294 while (w < width) {
295 w = (w + 8) &~ 7;
296 putchar('\t');
300 return;
302 while (--argc > 0) {
303 char *arg;
304 arg = *++argv;
305 c = getcmd(arg);
306 if (c == (struct cmd *)-1)
307 printf("?Ambiguous help command %s\n", arg);
308 else if (c == (struct cmd *)0)
309 printf("?Invalid help command %s\n", arg);
310 else
311 printf("%-*s\t%s\n", (int)HELPINDENT,
312 c->c_name, c->c_help);
317 * return non-zero if the user is a member of the given group
319 static int
320 ingroup(const char *grname)
322 static struct group *gptr = NULL;
323 static gid_t groups[NGROUPS];
324 static int ngroups;
325 gid_t gid;
326 int i;
328 if (gptr == NULL) {
329 if ((gptr = getgrnam(grname)) == NULL) {
330 warnx("Warning: unknown group `%s'",
331 grname);
332 return(0);
334 ngroups = getgroups(NGROUPS, groups);
335 if (ngroups < 0)
336 err(1, "getgroups");
338 gid = gptr->gr_gid;
339 for (i = 0; i < ngroups; i++)
340 if (gid == groups[i])
341 return(1);
342 return(0);