I got a lot of
[unix-history] / sbin / init.chmr / ttytab.c
CommitLineData
9a6eb889
NW
1/*
2 * Copyright (c) 1993 Christoph M. Robitschko
800ffe89
NW
3 * All rights reserved.
4 *
800ffe89
NW
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
9a6eb889
NW
15 * This product includes software developed by Christoph M. Robitschko
16 * 4. The name of the author may not be used to endorse or promote products
17 * derived from this software withough specific prior written permission
800ffe89 18 *
9a6eb889
NW
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
800ffe89
NW
29 */
30
31/*
32 * ttytab.c
33 * Everything that has to do with the getty table.
34 * This includes starting child precesses.
35 */
36
37#include <unistd.h>
38#include <stdlib.h>
39#include <string.h>
40#include <sys/types.h>
41#include <sys/signal.h>
42#include <sys/file.h>
43#include <ttyent.h>
44#include <syslog.h>
45#include <stdio.h>
46
47
48#include "init.h"
49#include "prototypes.h"
50#include "libutil.h"
51
52
53#ifdef __gcc__
54# define alloca __builtin_alloca
55#endif
56
57int checkstatus = DEF_CHECKSTATUS;
58int checktime = DEF_CHECKTIME;
59int def_waittimes[] = {0,0,0,30,60,300,1800};
60int *waittimes = def_waittimes;
61int nwaittimes = 7;
62
63
64/*
65 * FREE_TTY
66 * remove a ttytab entry from the list
67 */
68ttytab_t *
69free_tty(tab, tt)
70ttytab_t *tab, *tt;
71{
72char **s;
73
74
75 /* Delete the entry from utmp, make log to wtmp */
76 if (logout(tt->name))
77 logwtmp(tt->name, "", "");
78
79 /* unlink it from the list first, in case of unexpected signal */
80 if (tt->next)
81 tt->next->prev = tt->prev;
82 if (tt->prev)
83 tt->prev->next = tt->next;
84 else
85 tab = tt->next;
86
87 /* free the associated memory */
88 if (tt->name) free(tt->name);
89 if (tt->type) free(tt->type);
90 if (tt->argv) {
91 for (s = tt->argv; *s; s++)
92 free(*s);
93 free(tt->argv);
94 }
95 free(tt);
96
97 return(tab);
98}
99
100
101/*
102 * ENT_TO_TAB
103 * create or change a ttytab entry based on the information in a ttyent struct
104 */
105ttytab_t *
106ent_to_tab(ent, tt, tab, flags)
107const struct ttyent *ent;
108ttytab_t *tab, *tt;
109int flags;
110{
111char *argstr;
112
113
114 /* Do we really need this entry ? */
115 if (ent->ty_status & TTY_ON == 0)
116 return(tab);
117
118 Debug(4, "Processing tty entry %s", ent->ty_name);
119 /* Allocate a ttytab entry, if not already there */
120 if (!tt) {
121 tt = malloc(sizeof(*tt));
122 if (!tt)
123 goto kaaplotz;
124 tt->name = (char *)0;
125 tt->argv = (char **)0;
126 tt->type = (char *)0;
127 tt->intflags = INIT_NEW;
128 tt->pid = 0;
129 tt->failcount = 0;
130 tt->starttime = (time_t)0;
131 tt->next = tab;
132 tt->prev = (ttytab_t *)0;
133 if (tab)
134 tab->prev = tt;
135 tab = tt;
136 Debug(5, "Creating new ttytab entry");
137 } else
138 Debug(5, "Reusing existing ttytab entry");
139
140
141 tt->intflags |= (flags | INIT_SEEN);
142
143
144 /* fill each field in from the ttyent, if it has changed */
145 if (strcmp(ent->ty_name, tt->name)) {
146 Debug(5, "name differs: old=\"%s\" new=\"%s\"", tt->name, ent->ty_name);
147 if (tt->name) free(tt->name);
148 tt->name = newstring(ent->ty_name);
149 tt->intflags |= INIT_CHANGED;
150 }
151 if (flags & INIT_NODEV)
152 argstr = ent->ty_getty;
153 else {
154 if (!(argstr = alloca(strlen(ent->ty_getty) +strlen(tt->name) +2)))
155 goto kaaplotz;
9a6eb889
NW
156/* sprintf(argstr, "%s %s", ent->ty_getty, tt->name); */
157 strcpy(argstr, ent->ty_getty);
158 strcat(argstr, " ");
159 strcat(argstr, tt->name);
800ffe89
NW
160 }
161 if (argv_changed(argstr, (const char **)tt->argv)) {
162 if (tt->argv) {
163 char **s;
164
165 for (s = tt->argv; *s; s++)
166 free(*s);
167 free(tt->argv);
168 }
169 tt->argv = string_to_argv(argstr, (int *)0, (char **)0);
170 tt->intflags |= INIT_CHANGED;
171 Debug(5, "argv differs.");
172 }
173 if (strcmp(ent->ty_type, tt->type)) {
174 if (tt->type) free(tt->type);
175 tt->type = newstring(ent->ty_type);
176 tt->intflags |= INIT_CHANGED;
177 Debug(5, "type differs.");
178 }
179
180 if (!(tt->intflags & INIT_CHANGED)) {
181 Debug(5, "entry unchanged.");
182 } else
183 Debug(5, "entry has been changed.");
184 return(tab);
185
186
187kaaplotz:
188 syslog(LOG_ERR, "Out of memory in ent_to_tab");
189 callout(retrytime, CO_ENT2TAB, NULL);
190 return(tab);
191}
192
193
194
195/*
196 * ARGV_CHANGED
197 * compares a string and an argv
198 */
199int
200argv_changed(string, argv)
201const char *string;
202const char **argv;
203{
204const char *ss;
205const char **sa;
206
207
208 if (!argv)
209 return(1);
210 for (ss = string, sa = argv; *sa; sa++) {
211 register int len = strlen(*sa);
212 if (strncmp(*sa, ss, len))
213 return(1);
214 ss += len;
215 if ((*ss != ' ') && (*ss != '\t') && (*ss))
216 return(1);
217 while ((*ss == ' ') || (*ss == '\t')) ss++;
218 }
219 if (*ss) /* String longer than argv ? */
220 return(1);
221 else
222 return(0);
223}
224
225
226/*
227 * STRING_TO_ARGV
228 * breaks up a string into words. Speration characters are SPACE and TAB,
229 * unless prepended by a backslash \ or within double quotes ".
230 * Quotes and backslash can be escaped by an additional \.
231 * If errtext is non-NULL, it is set to point to an error message.
232 */
233char **
234string_to_argv(string, rargc, errtext)
235const char *string;
236int *rargc;
237char **errtext;
238{
239const char *s;
240char *buf, *t;
241int backslash, inquote;
242int argc, alloc_argc;
243char **argv;
244char **ra;
245
246
247 Debug(4, "string_to_argv(\"%s\")", string);
248 /*
249 * argv is allocated in chunks of ALLOC_ARGV pointers; if it runs
250 * out of space, it is realloc'ed with ALLOC_ARGV more pointers.
251 */
252 argc = 0;
253 argv = (char **)malloc(ALLOC_ARGV * sizeof(char *));
254 if (!argv) return(argv);
255 alloc_argc = ALLOC_ARGV;
256
257 if (errtext)
258 *errtext = (char *)0;
259
260 for (s = string; *s;) {
261 backslash = inquote = 0;
262 for (; (*s == ' ') || (*s == '\t'); s++); /* Skip blanks */
263 if (!(*s)) break;
264 if (!(buf = (char *)malloc(strlen(s)+1))) goto malloc_fail;
265 for (t=buf;; s++) {
266 if (backslash) {
267 backslash = 0;
268 *t++ = *s;
269 } else switch (*s) {
270 case '\\':
271 backslash = 1;
272 break;
273 case '\"':
274 inquote ^= 1;
275 break;
276 case '\0':
277 if (inquote && errtext)
278 *errtext = "Unmatched \".";
279 goto end_of_word;
280 case ' ': case '\t':
281 if (!inquote)
282 goto end_of_word;
283 /* no break */
284 default:
285 *t++ = *s;
286 }
287 }
288
289end_of_word:
290 *t = '\0';
291 if (!(argv[argc] = (char *)realloc(buf, strlen(buf)+1))) goto malloc_fail;
292
293 if (++argc >= alloc_argc) {
294 alloc_argc += ALLOC_ARGV;
295 if (!(ra = realloc(argv, alloc_argc * sizeof(char **))))
296 goto malloc_fail;
297 argv = ra;
298 }
299 }
300
301 /* Terminate argv with a NULL pointer and return */
302 argv[argc] = (char *)0;
303 if (rargc)
304 *rargc = argc;
9a6eb889 305#ifdef DEBUG
800ffe89
NW
306 if (debug > 5) {
307 for (ra = argv; *ra; ra++)
308 Debug(5, " \"%s\"", *ra);
309 Debug(5, " ");
310 }
9a6eb889 311#endif
800ffe89
NW
312 return(argv);
313
314malloc_fail:
315 /* free all so-far allocated memory and return a NULL pointer */
316 for (; *argv; argv++)
317 free(*argv);
318 free(argv);
319 return((char **)0);
320}
321
322
323
324/*
325 * DO_GETTY
326 * start a getty process for a ttytab entry
327 */
328int
329do_getty(tt, status)
330ttytab_t *tt;
331int status;
332{
333int pid;
334
335
336 if (!tt)
337 return(-1);
338 Debug(2, "do_getty for %s", tt->name);
339
340 if (tt->intflags & INIT_FAILSLEEP)
341 tt->intflags &= ~INIT_FAILSLEEP;
342 else {
343 /* Delete old entry from utmp, make log to wtmp */
344 if (logout(tt->name))
345 logwtmp(tt->name, "", "");
346
347 if ((checkstatus && status) || (checktime && (time(0) - tt->starttime <= checktime))) {
348 if (tt->intflags & INIT_FAILED) {
349 if (++tt->failcount >= nwaittimes)
350 tt->failcount = nwaittimes;
351 } else {
352 tt->intflags |= INIT_FAILED;
353 tt->failcount = 1;
354 }
355 if (waittimes[tt->failcount]) {
356 tt->intflags |= INIT_FAILSLEEP;
357 tt->pid = 0;
358 syslog(LOG_WARNING, "getty \"%s\" for %s failed, sleeping", tt->argv[0], tt->name);
359 callout (waittimes[tt->failcount], CO_GETTY, (void *)tt);
360 return(0);
361 }
362 } else
363 tt->intflags &= ~INIT_FAILED;
364 }
365
366
367#ifdef TESTRUN
368 return (0);
369#endif /* TESTRUN */
370
371 tt->starttime = time(0);
372 blocksig();
373 switch ((pid=fork())) {
374 case -1:
375 syslog(LOG_ERR, "fork failed for %s: %m", tt->name);
376 unblocksig();
377 callout(retrytime, CO_FORK, (void *)tt);
378 return (-1);
379 case 0:
380 signalsforchile();
381 iputenv("TERM", tt->type);
382 if (tt->intflags & INIT_OPEN) {
383 int fd;
384 char *device = alloca(strlen(tt->name) + sizeof("/dev/"));
9a6eb889
NW
385/* sprintf(device, "/dev/%s", tt->name); */
386 strcpy(device, "/dev/");
387 strcat(device, tt->name);
800ffe89
NW
388 (void)revoke (device);
389 closelog();
390 fd = open(device, O_RDWR);
391 if (fd < 0)
392 syslog(LOG_ERR, "open %s failed: %m", device);
393 if (login_tty(fd) < 0)
394 syslog(LOG_ERR, "login_tty for %s failed: %m", device);
395 }
396#ifdef CONFIGURE
397 setconf();
398#endif
399 closelog(); /* Necessary, because dup2 fails otherwise (?) */
400 if (tt->intflags & INIT_ARG0)
401 execve(tt->argv[0], tt->argv +1, ienviron);
402 else
403 execve(tt->argv[0], tt->argv, ienviron);
404 syslog(LOG_ERR, "Exec \"%s\" failed for %s: %m", tt->argv[0], tt->name);
405 _exit(1);
406 default:
407 tt->pid = pid;
408 unblocksig();
409 return(0);
410 }
411
412
413}