diff options
Diffstat (limited to 'getty.c')
-rw-r--r-- | getty.c | 1232 |
1 files changed, 0 insertions, 1232 deletions
diff --git a/getty.c b/getty.c deleted file mode 100644 index c6d0eb710..000000000 --- a/getty.c +++ /dev/null | |||
@@ -1,1232 +0,0 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* agetty.c - another getty program for Linux. By W. Z. Venema 1989 | ||
3 | Ported to Linux by Peter Orbaek <poe@daimi.aau.dk> | ||
4 | This program is freely distributable. The entire man-page used to | ||
5 | be here. Now read the real man-page agetty.8 instead. | ||
6 | |||
7 | -f option added by Eric Rasmussen <ear@usfirst.org> - 12/28/95 | ||
8 | |||
9 | 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org> | ||
10 | - added Native Language Support | ||
11 | |||
12 | 1999-05-05 Thorsten Kranzkowski <dl8bcu@gmx.net> | ||
13 | - enable hardware flow control before displaying /etc/issue | ||
14 | |||
15 | */ | ||
16 | |||
17 | #include <stdio.h> | ||
18 | #include <stdlib.h> | ||
19 | #include <unistd.h> | ||
20 | #include <string.h> | ||
21 | #include <sys/ioctl.h> | ||
22 | #include <errno.h> | ||
23 | #include <sys/stat.h> | ||
24 | #include <sys/signal.h> | ||
25 | #include <fcntl.h> | ||
26 | #include <stdarg.h> | ||
27 | #include <ctype.h> | ||
28 | #include <utmp.h> | ||
29 | #include <getopt.h> | ||
30 | #include <termios.h> | ||
31 | #include "busybox.h" | ||
32 | |||
33 | #define _PATH_LOGIN "/bin/login" | ||
34 | |||
35 | #ifdef linux | ||
36 | #include <sys/param.h> | ||
37 | #define USE_SYSLOG | ||
38 | #endif | ||
39 | |||
40 | extern void updwtmp(const char *filename, const struct utmp *ut); | ||
41 | |||
42 | /* If USE_SYSLOG is undefined all diagnostics go directly to /dev/console. */ | ||
43 | #ifdef USE_SYSLOG | ||
44 | #include <syslog.h> | ||
45 | #endif | ||
46 | |||
47 | |||
48 | /* | ||
49 | * Some heuristics to find out what environment we are in: if it is not | ||
50 | * System V, assume it is SunOS 4. | ||
51 | */ | ||
52 | |||
53 | #ifdef LOGIN_PROCESS /* defined in System V utmp.h */ | ||
54 | #define SYSV_STYLE /* select System V style getty */ | ||
55 | #endif | ||
56 | |||
57 | /* | ||
58 | * Things you may want to modify. | ||
59 | * | ||
60 | * If ISSUE is not defined, agetty will never display the contents of the | ||
61 | * /etc/issue file. You will not want to spit out large "issue" files at the | ||
62 | * wrong baud rate. Relevant for System V only. | ||
63 | * | ||
64 | * You may disagree with the default line-editing etc. characters defined | ||
65 | * below. Note, however, that DEL cannot be used for interrupt generation | ||
66 | * and for line editing at the same time. | ||
67 | */ | ||
68 | |||
69 | #ifdef SYSV_STYLE | ||
70 | #define ISSUE "/etc/issue" /* displayed before the login prompt */ | ||
71 | #include <sys/utsname.h> | ||
72 | #include <time.h> | ||
73 | #endif | ||
74 | |||
75 | #define LOGIN " login: " /* login prompt */ | ||
76 | |||
77 | /* Some shorthands for control characters. */ | ||
78 | |||
79 | #define CTL(x) (x ^ 0100) /* Assumes ASCII dialect */ | ||
80 | #define CR CTL('M') /* carriage return */ | ||
81 | #define NL CTL('J') /* line feed */ | ||
82 | #define BS CTL('H') /* back space */ | ||
83 | #define DEL CTL('?') /* delete */ | ||
84 | |||
85 | /* Defaults for line-editing etc. characters; you may want to change this. */ | ||
86 | |||
87 | #define DEF_ERASE DEL /* default erase character */ | ||
88 | #define DEF_INTR CTL('C') /* default interrupt character */ | ||
89 | #define DEF_QUIT CTL('\\') /* default quit char */ | ||
90 | #define DEF_KILL CTL('U') /* default kill char */ | ||
91 | #define DEF_EOF CTL('D') /* default EOF char */ | ||
92 | #define DEF_EOL 0 | ||
93 | #define DEF_SWITCH 0 /* default switch char */ | ||
94 | |||
95 | /* | ||
96 | * SunOS 4.1.1 termio is broken. We must use the termios stuff instead, | ||
97 | * because the termio -> termios translation does not clear the termios | ||
98 | * CIBAUD bits. Therefore, the tty driver would sometimes report that input | ||
99 | * baud rate != output baud rate. I did not notice that problem with SunOS | ||
100 | * 4.1. We will use termios where available, and termio otherwise. | ||
101 | */ | ||
102 | |||
103 | /* linux 0.12 termio is broken too, if we use it c_cc[VERASE] isn't set | ||
104 | properly, but all is well if we use termios?! */ | ||
105 | |||
106 | #ifdef TCGETS | ||
107 | #undef TCGETA | ||
108 | #undef TCSETA | ||
109 | #undef TCSETAW | ||
110 | #define termio termios | ||
111 | #define TCGETA TCGETS | ||
112 | #define TCSETA TCSETS | ||
113 | #define TCSETAW TCSETSW | ||
114 | #endif | ||
115 | |||
116 | /* | ||
117 | * This program tries to not use the standard-i/o library. This keeps the | ||
118 | * executable small on systems that do not have shared libraries (System V | ||
119 | * Release <3). | ||
120 | */ | ||
121 | #ifndef BUFSIZ | ||
122 | #define BUFSIZ 1024 | ||
123 | #endif | ||
124 | |||
125 | /* | ||
126 | * When multiple baud rates are specified on the command line, the first one | ||
127 | * we will try is the first one specified. | ||
128 | */ | ||
129 | |||
130 | #define FIRST_SPEED 0 | ||
131 | |||
132 | /* Storage for command-line options. */ | ||
133 | |||
134 | #define MAX_SPEED 10 /* max. nr. of baud rates */ | ||
135 | |||
136 | struct options { | ||
137 | int flags; /* toggle switches, see below */ | ||
138 | int timeout; /* time-out period */ | ||
139 | char *login; /* login program */ | ||
140 | char *tty; /* name of tty */ | ||
141 | char *initstring; /* modem init string */ | ||
142 | char *issue; /* alternative issue file */ | ||
143 | int numspeed; /* number of baud rates to try */ | ||
144 | int speeds[MAX_SPEED]; /* baud rates to be tried */ | ||
145 | }; | ||
146 | |||
147 | #define F_PARSE (1<<0) /* process modem status messages */ | ||
148 | #define F_ISSUE (1<<1) /* display /etc/issue */ | ||
149 | #define F_RTSCTS (1<<2) /* enable RTS/CTS flow control */ | ||
150 | #define F_LOCAL (1<<3) /* force local */ | ||
151 | #define F_INITSTRING (1<<4) /* initstring is set */ | ||
152 | #define F_WAITCRLF (1<<5) /* wait for CR or LF */ | ||
153 | #define F_CUSTISSUE (1<<6) /* give alternative issue file */ | ||
154 | #define F_NOPROMPT (1<<7) /* don't ask for login name! */ | ||
155 | |||
156 | /* Storage for things detected while the login name was read. */ | ||
157 | |||
158 | struct chardata { | ||
159 | int erase; /* erase character */ | ||
160 | int kill; /* kill character */ | ||
161 | int eol; /* end-of-line character */ | ||
162 | int parity; /* what parity did we see */ | ||
163 | int capslock; /* upper case without lower case */ | ||
164 | }; | ||
165 | |||
166 | /* Initial values for the above. */ | ||
167 | |||
168 | struct chardata init_chardata = { | ||
169 | DEF_ERASE, /* default erase character */ | ||
170 | DEF_KILL, /* default kill character */ | ||
171 | 13, /* default eol char */ | ||
172 | 0, /* space parity */ | ||
173 | 0, /* no capslock */ | ||
174 | }; | ||
175 | |||
176 | struct Speedtab { | ||
177 | long speed; | ||
178 | int code; | ||
179 | }; | ||
180 | |||
181 | static struct Speedtab speedtab[] = { | ||
182 | {50, B50}, | ||
183 | {75, B75}, | ||
184 | {110, B110}, | ||
185 | {134, B134}, | ||
186 | {150, B150}, | ||
187 | {200, B200}, | ||
188 | {300, B300}, | ||
189 | {600, B600}, | ||
190 | {1200, B1200}, | ||
191 | {1800, B1800}, | ||
192 | {2400, B2400}, | ||
193 | {4800, B4800}, | ||
194 | {9600, B9600}, | ||
195 | #ifdef B19200 | ||
196 | {19200, B19200}, | ||
197 | #endif | ||
198 | #ifdef B38400 | ||
199 | {38400, B38400}, | ||
200 | #endif | ||
201 | #ifdef EXTA | ||
202 | {19200, EXTA}, | ||
203 | #endif | ||
204 | #ifdef EXTB | ||
205 | {38400, EXTB}, | ||
206 | #endif | ||
207 | #ifdef B57600 | ||
208 | {57600, B57600}, | ||
209 | #endif | ||
210 | #ifdef B115200 | ||
211 | {115200, B115200}, | ||
212 | #endif | ||
213 | #ifdef B230400 | ||
214 | {230400, B230400}, | ||
215 | #endif | ||
216 | {0, 0}, | ||
217 | }; | ||
218 | |||
219 | void parse_args(int argc, char **argv, struct options *op); | ||
220 | void parse_speeds(struct options *op, char *arg); | ||
221 | void update_utmp(char *line); | ||
222 | void open_tty(char *tty, struct termio *tp, int local); | ||
223 | void termio_init(struct termio *tp, int speed, struct options *op); | ||
224 | void auto_baud(struct termio *tp); | ||
225 | void do_prompt(struct options *op, struct termio *tp); | ||
226 | void next_speed(struct termio *tp, struct options *op); | ||
227 | char *get_logname(struct options *op, struct chardata *cp, | ||
228 | |||
229 | struct termio *tp); | ||
230 | void termio_final(struct options *op, struct termio *tp, | ||
231 | |||
232 | struct chardata *cp); | ||
233 | int caps_lock(char *s); | ||
234 | int bcode(char *s); | ||
235 | static void error(const char *fmt, ...); | ||
236 | |||
237 | /* The following is used for understandable diagnostics. */ | ||
238 | |||
239 | char *progname; | ||
240 | |||
241 | /* Fake hostname for ut_host specified on command line. */ | ||
242 | char *fakehost = NULL; | ||
243 | |||
244 | /* ... */ | ||
245 | #ifdef DEBUGGING | ||
246 | #define debug(s) fprintf(dbf,s); fflush(dbf) | ||
247 | #define DEBUGTERM "/dev/ttyp0" | ||
248 | FILE *dbf; | ||
249 | #else | ||
250 | #define debug(s) /* nothing */ | ||
251 | #endif | ||
252 | |||
253 | int getty_main(int argc, char **argv) | ||
254 | { | ||
255 | char *logname = NULL; /* login name, given to /bin/login */ | ||
256 | struct chardata chardata; /* set by get_logname() */ | ||
257 | struct termio termio; /* terminal mode bits */ | ||
258 | static struct options options = { | ||
259 | F_ISSUE, /* show /etc/issue (SYSV_STYLE) */ | ||
260 | 0, /* no timeout */ | ||
261 | _PATH_LOGIN, /* default login program */ | ||
262 | "tty1", /* default tty line */ | ||
263 | "", /* modem init string */ | ||
264 | ISSUE, /* default issue file */ | ||
265 | 0, /* no baud rates known yet */ | ||
266 | }; | ||
267 | |||
268 | /* The BSD-style init command passes us a useless process name. */ | ||
269 | |||
270 | #ifdef SYSV_STYLE | ||
271 | progname = argv[0]; | ||
272 | #else | ||
273 | progname = "getty"; | ||
274 | #endif | ||
275 | |||
276 | #ifdef DEBUGGING | ||
277 | dbf = xfopen(DEBUGTERM, "w"); | ||
278 | |||
279 | { | ||
280 | int i; | ||
281 | |||
282 | for (i = 1; i < argc; i++) { | ||
283 | debug(argv[i]); | ||
284 | debug("\n"); | ||
285 | } | ||
286 | } | ||
287 | #endif | ||
288 | |||
289 | /* Parse command-line arguments. */ | ||
290 | |||
291 | parse_args(argc, argv, &options); | ||
292 | |||
293 | #ifdef __linux__ | ||
294 | setsid(); | ||
295 | #endif | ||
296 | |||
297 | /* Update the utmp file. */ | ||
298 | |||
299 | #ifdef SYSV_STYLE | ||
300 | update_utmp(options.tty); | ||
301 | #endif | ||
302 | |||
303 | debug("calling open_tty\n"); | ||
304 | /* Open the tty as standard { input, output, error }. */ | ||
305 | open_tty(options.tty, &termio, options.flags & F_LOCAL); | ||
306 | |||
307 | #ifdef __linux__ | ||
308 | { | ||
309 | int iv; | ||
310 | |||
311 | iv = getpid(); | ||
312 | if (ioctl(0, TIOCSPGRP, &iv) < 0) | ||
313 | perror_msg("ioctl() TIOCSPGRP call failed"); | ||
314 | } | ||
315 | #endif | ||
316 | /* Initialize the termio settings (raw mode, eight-bit, blocking i/o). */ | ||
317 | debug("calling termio_init\n"); | ||
318 | termio_init(&termio, options.speeds[FIRST_SPEED], &options); | ||
319 | |||
320 | /* write the modem init string and DON'T flush the buffers */ | ||
321 | if (options.flags & F_INITSTRING) { | ||
322 | debug("writing init string\n"); | ||
323 | write(1, options.initstring, strlen(options.initstring)); | ||
324 | } | ||
325 | |||
326 | if (!(options.flags & F_LOCAL)) { | ||
327 | /* go to blocking write mode unless -L is specified */ | ||
328 | fcntl(1, F_SETFL, fcntl(1, F_GETFL, 0) & ~O_NONBLOCK); | ||
329 | } | ||
330 | |||
331 | /* Optionally detect the baud rate from the modem status message. */ | ||
332 | debug("before autobaud\n"); | ||
333 | if (options.flags & F_PARSE) | ||
334 | auto_baud(&termio); | ||
335 | |||
336 | /* Set the optional timer. */ | ||
337 | if (options.timeout) | ||
338 | (void) alarm((unsigned) options.timeout); | ||
339 | |||
340 | /* optionally wait for CR or LF before writing /etc/issue */ | ||
341 | if (options.flags & F_WAITCRLF) { | ||
342 | char ch; | ||
343 | |||
344 | debug("waiting for cr-lf\n"); | ||
345 | while (read(0, &ch, 1) == 1) { | ||
346 | ch &= 0x7f; /* strip "parity bit" */ | ||
347 | #ifdef DEBUGGING | ||
348 | fprintf(dbf, "read %c\n", ch); | ||
349 | #endif | ||
350 | if (ch == '\n' || ch == '\r') | ||
351 | break; | ||
352 | } | ||
353 | } | ||
354 | |||
355 | chardata = init_chardata; | ||
356 | if (!(options.flags & F_NOPROMPT)) { | ||
357 | /* Read the login name. */ | ||
358 | debug("reading login name\n"); | ||
359 | /* while ((logname = get_logname(&options, &chardata, &termio)) == 0) */ | ||
360 | while ((logname = get_logname(&options, &chardata, &termio)) == | ||
361 | NULL) next_speed(&termio, &options); | ||
362 | } | ||
363 | |||
364 | /* Disable timer. */ | ||
365 | |||
366 | if (options.timeout) | ||
367 | (void) alarm(0); | ||
368 | |||
369 | /* Finalize the termio settings. */ | ||
370 | |||
371 | termio_final(&options, &termio, &chardata); | ||
372 | |||
373 | /* Now the newline character should be properly written. */ | ||
374 | |||
375 | (void) write(1, "\n", 1); | ||
376 | |||
377 | /* Let the login program take care of password validation. */ | ||
378 | |||
379 | (void) execl(options.login, options.login, "--", logname, (char *) 0); | ||
380 | error("%s: can't exec %s: %m", options.tty, options.login); | ||
381 | return (0); /* quiet GCC */ | ||
382 | } | ||
383 | |||
384 | /* parse-args - parse command-line arguments */ | ||
385 | |||
386 | void parse_args(argc, argv, op) | ||
387 | int argc; | ||
388 | char **argv; | ||
389 | struct options *op; | ||
390 | { | ||
391 | extern char *optarg; /* getopt */ | ||
392 | extern int optind; /* getopt */ | ||
393 | int c; | ||
394 | |||
395 | while (isascii(c = getopt(argc, argv, "I:LH:f:hil:mt:wn"))) { | ||
396 | switch (c) { | ||
397 | case 'I': | ||
398 | if (!(op->initstring = malloc(strlen(optarg)))) { | ||
399 | error("can't malloc initstring"); | ||
400 | break; | ||
401 | } | ||
402 | { | ||
403 | char ch, *p, *q; | ||
404 | int i; | ||
405 | |||
406 | /* copy optarg into op->initstring decoding \ddd | ||
407 | octal codes into chars */ | ||
408 | q = op->initstring; | ||
409 | p = optarg; | ||
410 | while (*p) { | ||
411 | if (*p == '\\') { /* know \\ means \ */ | ||
412 | p++; | ||
413 | if (*p == '\\') { | ||
414 | ch = '\\'; | ||
415 | p++; | ||
416 | } else { /* handle \000 - \177 */ | ||
417 | ch = 0; | ||
418 | for (i = 1; i <= 3; i++) { | ||
419 | if (*p >= '0' && *p <= '7') { | ||
420 | ch <<= 3; | ||
421 | ch += *p - '0'; | ||
422 | p++; | ||
423 | } else | ||
424 | break; | ||
425 | } | ||
426 | } | ||
427 | *q++ = ch; | ||
428 | } else { | ||
429 | *q++ = *p++; | ||
430 | } | ||
431 | } | ||
432 | *q = '\0'; | ||
433 | } | ||
434 | op->flags |= F_INITSTRING; | ||
435 | break; | ||
436 | |||
437 | case 'L': /* force local */ | ||
438 | op->flags |= F_LOCAL; | ||
439 | break; | ||
440 | case 'H': /* fake login host */ | ||
441 | fakehost = optarg; | ||
442 | break; | ||
443 | case 'f': /* custom issue file */ | ||
444 | op->flags |= F_CUSTISSUE; | ||
445 | op->issue = optarg; | ||
446 | break; | ||
447 | case 'h': /* enable h/w flow control */ | ||
448 | op->flags |= F_RTSCTS; | ||
449 | break; | ||
450 | case 'i': /* do not show /etc/issue */ | ||
451 | op->flags &= ~F_ISSUE; | ||
452 | break; | ||
453 | case 'l': | ||
454 | op->login = optarg; /* non-default login program */ | ||
455 | break; | ||
456 | case 'm': /* parse modem status message */ | ||
457 | op->flags |= F_PARSE; | ||
458 | break; | ||
459 | case 'n': | ||
460 | op->flags |= F_NOPROMPT; | ||
461 | break; | ||
462 | case 't': /* time out */ | ||
463 | if ((op->timeout = atoi(optarg)) <= 0) | ||
464 | error("bad timeout value: %s", optarg); | ||
465 | break; | ||
466 | case 'w': | ||
467 | op->flags |= F_WAITCRLF; | ||
468 | break; | ||
469 | default: | ||
470 | show_usage(); | ||
471 | } | ||
472 | } | ||
473 | debug("after getopt loop\n"); | ||
474 | if (argc < optind + 2) /* check parameter count */ | ||
475 | show_usage(); | ||
476 | |||
477 | /* we loosen up a bit and accept both "baudrate tty" and "tty baudrate" */ | ||
478 | if ('0' <= argv[optind][0] && argv[optind][0] <= '9') { | ||
479 | /* a number first, assume it's a speed (BSD style) */ | ||
480 | parse_speeds(op, argv[optind++]); /* baud rate(s) */ | ||
481 | op->tty = argv[optind]; /* tty name */ | ||
482 | } else { | ||
483 | op->tty = argv[optind++]; /* tty name */ | ||
484 | parse_speeds(op, argv[optind]); /* baud rate(s) */ | ||
485 | } | ||
486 | |||
487 | optind++; | ||
488 | if (argc > optind && argv[optind]) | ||
489 | setenv("TERM", argv[optind], 1); | ||
490 | |||
491 | debug("exiting parseargs\n"); | ||
492 | } | ||
493 | |||
494 | /* parse_speeds - parse alternate baud rates */ | ||
495 | |||
496 | void parse_speeds(op, arg) | ||
497 | struct options *op; | ||
498 | char *arg; | ||
499 | { | ||
500 | char *strtok(); | ||
501 | char *cp; | ||
502 | |||
503 | debug("entered parse_speeds\n"); | ||
504 | for (cp = strtok(arg, ","); cp != 0; cp = strtok((char *) 0, ",")) { | ||
505 | if ((op->speeds[op->numspeed++] = bcode(cp)) <= 0) | ||
506 | error("bad speed: %s", cp); | ||
507 | if (op->numspeed > MAX_SPEED) | ||
508 | error("too many alternate speeds"); | ||
509 | } | ||
510 | debug("exiting parsespeeds\n"); | ||
511 | } | ||
512 | |||
513 | #ifdef SYSV_STYLE | ||
514 | |||
515 | /* update_utmp - update our utmp entry */ | ||
516 | void update_utmp(line) | ||
517 | char *line; | ||
518 | { | ||
519 | struct utmp ut; | ||
520 | int mypid = getpid(); | ||
521 | long time(); | ||
522 | long lseek(); | ||
523 | #ifndef __UCLIBC__ | ||
524 | time_t t; | ||
525 | struct utmp *utp; | ||
526 | #endif | ||
527 | |||
528 | #if ! (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1)) | ||
529 | struct flock lock; | ||
530 | #endif | ||
531 | |||
532 | /* | ||
533 | * The utmp file holds miscellaneous information about things started by | ||
534 | * /sbin/init and other system-related events. Our purpose is to update | ||
535 | * the utmp entry for the current process, in particular the process type | ||
536 | * and the tty line we are listening to. Return successfully only if the | ||
537 | * utmp file can be opened for update, and if we are able to find our | ||
538 | * entry in the utmp file. | ||
539 | */ | ||
540 | |||
541 | #ifndef __UCLIBC__ | ||
542 | utmpname(_PATH_UTMP); | ||
543 | setutent(); | ||
544 | while ((utp = getutent()) | ||
545 | && !(utp->ut_type == INIT_PROCESS && utp->ut_pid == mypid)) /* nothing */ | ||
546 | ; | ||
547 | |||
548 | if (utp) { | ||
549 | memcpy(&ut, utp, sizeof(ut)); | ||
550 | } else { | ||
551 | /* some inits don't initialize utmp... */ | ||
552 | memset(&ut, 0, sizeof(ut)); | ||
553 | strncpy(ut.ut_id, line + 3, sizeof(ut.ut_id)); | ||
554 | } | ||
555 | /*endutent(); */ | ||
556 | |||
557 | strncpy(ut.ut_user, "LOGIN", sizeof(ut.ut_user)); | ||
558 | strncpy(ut.ut_line, line, sizeof(ut.ut_line)); | ||
559 | if (fakehost) | ||
560 | strncpy(ut.ut_host, fakehost, sizeof(ut.ut_host)); | ||
561 | time(&t); | ||
562 | ut.ut_time = t; | ||
563 | ut.ut_type = LOGIN_PROCESS; | ||
564 | ut.ut_pid = mypid; | ||
565 | |||
566 | pututline(&ut); | ||
567 | endutent(); | ||
568 | |||
569 | { | ||
570 | updwtmp(_PATH_WTMP, &ut); | ||
571 | } | ||
572 | #else /* not __linux__ */ | ||
573 | { | ||
574 | int ut_fd; | ||
575 | |||
576 | if ((ut_fd = open(_PATH_WTMP, 2)) < 0) { | ||
577 | error("%s: open for update: %m"), _PATH_WTMP; | ||
578 | } else { | ||
579 | long ut_size = sizeof(ut); /* avoid nonsense */ | ||
580 | |||
581 | while (read(ut_fd, (char *) &ut, sizeof(ut)) == sizeof(ut)) { | ||
582 | if (ut.ut_type == INIT_PROCESS && ut.ut_pid == mypid) { | ||
583 | ut.ut_type = LOGIN_PROCESS; | ||
584 | ut.ut_time = time((long *) 0); | ||
585 | (void) strncpy(ut.ut_name, "LOGIN", sizeof(ut.ut_name)); | ||
586 | (void) strncpy(ut.ut_line, line, sizeof(ut.ut_line)); | ||
587 | if (fakehost) | ||
588 | (void) strncpy(ut.ut_host, fakehost, sizeof(ut.ut_host)); | ||
589 | (void) lseek(ut_fd, -ut_size, 1); | ||
590 | (void) write(ut_fd, (char *) &ut, sizeof(ut)); | ||
591 | (void) close(ut_fd); | ||
592 | return; | ||
593 | } | ||
594 | } | ||
595 | error("%s: no utmp entry", line); | ||
596 | } | ||
597 | } | ||
598 | #endif /* __linux__ */ | ||
599 | } | ||
600 | |||
601 | #endif | ||
602 | |||
603 | /* open_tty - set up tty as standard { input, output, error } */ | ||
604 | void open_tty(tty, tp, local) | ||
605 | char *tty; | ||
606 | struct termio *tp; | ||
607 | int local; | ||
608 | { | ||
609 | /* Get rid of the present standard { output, error} if any. */ | ||
610 | |||
611 | (void) close(1); | ||
612 | (void) close(2); | ||
613 | errno = 0; /* ignore above errors */ | ||
614 | |||
615 | /* Set up new standard input, unless we are given an already opened port. */ | ||
616 | |||
617 | if (strcmp(tty, "-")) { | ||
618 | struct stat st; | ||
619 | |||
620 | /* Sanity checks... */ | ||
621 | |||
622 | if (chdir("/dev")) | ||
623 | error("/dev: chdir() failed: %m"); | ||
624 | if (stat(tty, &st) < 0) | ||
625 | error("/dev/%s: %m", tty); | ||
626 | if ((st.st_mode & S_IFMT) != S_IFCHR) | ||
627 | error("/dev/%s: not a character device", tty); | ||
628 | |||
629 | /* Open the tty as standard input. */ | ||
630 | |||
631 | (void) close(0); | ||
632 | errno = 0; /* ignore close(2) errors */ | ||
633 | |||
634 | debug("open(2)\n"); | ||
635 | if (open(tty, O_RDWR | O_NONBLOCK, 0) != 0) | ||
636 | error("/dev/%s: cannot open as standard input: %m", tty); | ||
637 | |||
638 | } else { | ||
639 | |||
640 | /* | ||
641 | * Standard input should already be connected to an open port. Make | ||
642 | * sure it is open for read/write. | ||
643 | */ | ||
644 | |||
645 | if ((fcntl(0, F_GETFL, 0) & O_RDWR) != O_RDWR) | ||
646 | error("%s: not open for read/write", tty); | ||
647 | } | ||
648 | |||
649 | /* Set up standard output and standard error file descriptors. */ | ||
650 | debug("duping\n"); | ||
651 | if (dup(0) != 1 || dup(0) != 2) /* set up stdout and stderr */ | ||
652 | error("%s: dup problem: %m", tty); /* we have a problem */ | ||
653 | |||
654 | /* | ||
655 | * The following ioctl will fail if stdin is not a tty, but also when | ||
656 | * there is noise on the modem control lines. In the latter case, the | ||
657 | * common course of action is (1) fix your cables (2) give the modem more | ||
658 | * time to properly reset after hanging up. SunOS users can achieve (2) | ||
659 | * by patching the SunOS kernel variable "zsadtrlow" to a larger value; | ||
660 | * 5 seconds seems to be a good value. | ||
661 | */ | ||
662 | |||
663 | if (ioctl(0, TCGETA, tp) < 0) | ||
664 | error("%s: ioctl: %m", tty); | ||
665 | |||
666 | /* | ||
667 | * It seems to be a terminal. Set proper protections and ownership. Mode | ||
668 | * 0622 is suitable for SYSV <4 because /bin/login does not change | ||
669 | * protections. SunOS 4 login will change the protections to 0620 (write | ||
670 | * access for group tty) after the login has succeeded. | ||
671 | */ | ||
672 | |||
673 | #ifdef DEBIAN | ||
674 | { | ||
675 | /* tty to root.dialout 660 */ | ||
676 | struct group *gr; | ||
677 | int id; | ||
678 | |||
679 | id = (gr = getgrnam("dialout")) ? gr->gr_gid : 0; | ||
680 | chown(tty, 0, id); | ||
681 | chmod(tty, 0660); | ||
682 | |||
683 | /* vcs,vcsa to root.sys 600 */ | ||
684 | if (!strncmp(tty, "tty", 3) && isdigit(tty[3])) { | ||
685 | char *vcs, *vcsa; | ||
686 | |||
687 | if (!(vcs = malloc(strlen(tty)))) | ||
688 | error("Can't malloc for vcs"); | ||
689 | if (!(vcsa = malloc(strlen(tty) + 1))) | ||
690 | error("Can't malloc for vcsa"); | ||
691 | strcpy(vcs, "vcs"); | ||
692 | strcpy(vcs + 3, tty + 3); | ||
693 | strcpy(vcsa, "vcsa"); | ||
694 | strcpy(vcsa + 4, tty + 3); | ||
695 | |||
696 | id = (gr = getgrnam("sys")) ? gr->gr_gid : 0; | ||
697 | chown(vcs, 0, id); | ||
698 | chmod(vcs, 0600); | ||
699 | chown(vcsa, 0, id); | ||
700 | chmod(vcs, 0600); | ||
701 | |||
702 | free(vcs); | ||
703 | free(vcsa); | ||
704 | } | ||
705 | } | ||
706 | #else | ||
707 | (void) chown(tty, 0, 0); /* root, sys */ | ||
708 | (void) chmod(tty, 0622); /* crw--w--w- */ | ||
709 | errno = 0; /* ignore above errors */ | ||
710 | #endif | ||
711 | } | ||
712 | |||
713 | /* termio_init - initialize termio settings */ | ||
714 | |||
715 | char gbuf[1024]; | ||
716 | char area[1024]; | ||
717 | |||
718 | void termio_init(tp, speed, op) | ||
719 | struct termio *tp; | ||
720 | int speed; | ||
721 | struct options *op; | ||
722 | { | ||
723 | |||
724 | /* | ||
725 | * Initial termio settings: 8-bit characters, raw-mode, blocking i/o. | ||
726 | * Special characters are set after we have read the login name; all | ||
727 | * reads will be done in raw mode anyway. Errors will be dealt with | ||
728 | * lateron. | ||
729 | */ | ||
730 | #ifdef __linux__ | ||
731 | /* flush input and output queues, important for modems! */ | ||
732 | (void) ioctl(0, TCFLSH, TCIOFLUSH); | ||
733 | #endif | ||
734 | |||
735 | tp->c_cflag = CS8 | HUPCL | CREAD | speed; | ||
736 | if (op->flags & F_LOCAL) { | ||
737 | tp->c_cflag |= CLOCAL; | ||
738 | } | ||
739 | |||
740 | tp->c_iflag = tp->c_lflag = tp->c_oflag = tp->c_line = 0; | ||
741 | tp->c_cc[VMIN] = 1; | ||
742 | tp->c_cc[VTIME] = 0; | ||
743 | |||
744 | /* Optionally enable hardware flow control */ | ||
745 | |||
746 | #ifdef CRTSCTS | ||
747 | if (op->flags & F_RTSCTS) | ||
748 | tp->c_cflag |= CRTSCTS; | ||
749 | #endif | ||
750 | |||
751 | (void) ioctl(0, TCSETA, tp); | ||
752 | |||
753 | /* go to blocking input even in local mode */ | ||
754 | fcntl(0, F_SETFL, fcntl(0, F_GETFL, 0) & ~O_NONBLOCK); | ||
755 | |||
756 | debug("term_io 2\n"); | ||
757 | } | ||
758 | |||
759 | /* auto_baud - extract baud rate from modem status message */ | ||
760 | void auto_baud(tp) | ||
761 | struct termio *tp; | ||
762 | { | ||
763 | int speed; | ||
764 | int vmin; | ||
765 | unsigned iflag; | ||
766 | char buf[BUFSIZ]; | ||
767 | char *bp; | ||
768 | int nread; | ||
769 | |||
770 | /* | ||
771 | * This works only if the modem produces its status code AFTER raising | ||
772 | * the DCD line, and if the computer is fast enough to set the proper | ||
773 | * baud rate before the message has gone by. We expect a message of the | ||
774 | * following format: | ||
775 | * | ||
776 | * <junk><number><junk> | ||
777 | * | ||
778 | * The number is interpreted as the baud rate of the incoming call. If the | ||
779 | * modem does not tell us the baud rate within one second, we will keep | ||
780 | * using the current baud rate. It is advisable to enable BREAK | ||
781 | * processing (comma-separated list of baud rates) if the processing of | ||
782 | * modem status messages is enabled. | ||
783 | */ | ||
784 | |||
785 | /* | ||
786 | * Use 7-bit characters, don't block if input queue is empty. Errors will | ||
787 | * be dealt with lateron. | ||
788 | */ | ||
789 | |||
790 | iflag = tp->c_iflag; | ||
791 | tp->c_iflag |= ISTRIP; /* enable 8th-bit stripping */ | ||
792 | vmin = tp->c_cc[VMIN]; | ||
793 | tp->c_cc[VMIN] = 0; /* don't block if queue empty */ | ||
794 | (void) ioctl(0, TCSETA, tp); | ||
795 | |||
796 | /* | ||
797 | * Wait for a while, then read everything the modem has said so far and | ||
798 | * try to extract the speed of the dial-in call. | ||
799 | */ | ||
800 | |||
801 | (void) sleep(1); | ||
802 | if ((nread = read(0, buf, sizeof(buf) - 1)) > 0) { | ||
803 | buf[nread] = '\0'; | ||
804 | for (bp = buf; bp < buf + nread; bp++) { | ||
805 | if (isascii(*bp) && isdigit(*bp)) { | ||
806 | if ((speed = bcode(bp))) { | ||
807 | tp->c_cflag &= ~CBAUD; | ||
808 | tp->c_cflag |= speed; | ||
809 | } | ||
810 | break; | ||
811 | } | ||
812 | } | ||
813 | } | ||
814 | /* Restore terminal settings. Errors will be dealt with lateron. */ | ||
815 | |||
816 | tp->c_iflag = iflag; | ||
817 | tp->c_cc[VMIN] = vmin; | ||
818 | (void) ioctl(0, TCSETA, tp); | ||
819 | } | ||
820 | |||
821 | /* do_prompt - show login prompt, optionally preceded by /etc/issue contents */ | ||
822 | void do_prompt(op, tp) | ||
823 | struct options *op; | ||
824 | struct termio *tp; | ||
825 | { | ||
826 | #ifdef ISSUE | ||
827 | FILE *fd; | ||
828 | int oflag; | ||
829 | int c; | ||
830 | struct utsname uts; | ||
831 | |||
832 | (void) uname(&uts); | ||
833 | #endif | ||
834 | |||
835 | (void) write(1, "\r\n", 2); /* start a new line */ | ||
836 | #ifdef ISSUE /* optional: show /etc/issue */ | ||
837 | if ((op->flags & F_ISSUE) && (fd = fopen(op->issue, "r"))) { | ||
838 | oflag = tp->c_oflag; /* save current setting */ | ||
839 | tp->c_oflag |= (ONLCR | OPOST); /* map NL in output to CR-NL */ | ||
840 | (void) ioctl(0, TCSETAW, tp); | ||
841 | |||
842 | |||
843 | while ((c = getc(fd)) != EOF) { | ||
844 | if (c == '\\') { | ||
845 | c = getc(fd); | ||
846 | |||
847 | switch (c) { | ||
848 | case 's': | ||
849 | (void) printf("%s", uts.sysname); | ||
850 | break; | ||
851 | |||
852 | case 'n': | ||
853 | (void) printf("%s", uts.nodename); | ||
854 | break; | ||
855 | |||
856 | case 'r': | ||
857 | (void) printf("%s", uts.release); | ||
858 | break; | ||
859 | |||
860 | case 'v': | ||
861 | (void) printf("%s", uts.version); | ||
862 | break; | ||
863 | |||
864 | case 'm': | ||
865 | (void) printf("%s", uts.machine); | ||
866 | break; | ||
867 | |||
868 | case 'o': | ||
869 | { | ||
870 | char domainname[256]; | ||
871 | |||
872 | getdomainname(domainname, sizeof(domainname)); | ||
873 | domainname[sizeof(domainname) - 1] = '\0'; | ||
874 | printf("%s", domainname); | ||
875 | } | ||
876 | break; | ||
877 | |||
878 | case 'd': | ||
879 | case 't': | ||
880 | { | ||
881 | char *weekday[] = { "Sun", "Mon", "Tue", "Wed", "Thu", | ||
882 | "Fri", "Sat" | ||
883 | }; | ||
884 | char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", | ||
885 | "Jun", "Jul", "Aug", "Sep", "Oct", | ||
886 | "Nov", "Dec" | ||
887 | }; | ||
888 | time_t now; | ||
889 | struct tm *tm; | ||
890 | |||
891 | (void) time(&now); | ||
892 | tm = localtime(&now); | ||
893 | |||
894 | if (c == 'd') | ||
895 | (void) printf("%s %s %d %d", | ||
896 | weekday[tm->tm_wday], | ||
897 | month[tm->tm_mon], tm->tm_mday, | ||
898 | tm->tm_year < | ||
899 | 70 ? tm->tm_year + | ||
900 | 2000 : tm->tm_year + 1900); | ||
901 | else | ||
902 | (void) printf("%02d:%02d:%02d", tm->tm_hour, | ||
903 | tm->tm_min, tm->tm_sec); | ||
904 | |||
905 | break; | ||
906 | } | ||
907 | |||
908 | case 'l': | ||
909 | (void) printf("%s", op->tty); | ||
910 | break; | ||
911 | |||
912 | case 'b': | ||
913 | { | ||
914 | int i; | ||
915 | |||
916 | for (i = 0; speedtab[i].speed; i++) { | ||
917 | if (speedtab[i].code == (tp->c_cflag & CBAUD)) { | ||
918 | printf("%ld", speedtab[i].speed); | ||
919 | break; | ||
920 | } | ||
921 | } | ||
922 | break; | ||
923 | } | ||
924 | case 'u': | ||
925 | case 'U': | ||
926 | { | ||
927 | int users = 0; | ||
928 | struct utmp *ut; | ||
929 | |||
930 | setutent(); | ||
931 | while ((ut = getutent())) | ||
932 | if (ut->ut_type == USER_PROCESS) | ||
933 | users++; | ||
934 | endutent(); | ||
935 | printf("%d ", users); | ||
936 | if (c == 'U') | ||
937 | printf((users == 1) ? "user" : "users"); | ||
938 | break; | ||
939 | } | ||
940 | default: | ||
941 | (void) putchar(c); | ||
942 | } | ||
943 | } else | ||
944 | (void) putchar(c); | ||
945 | } | ||
946 | fflush(stdout); | ||
947 | |||
948 | tp->c_oflag = oflag; /* restore settings */ | ||
949 | (void) ioctl(0, TCSETAW, tp); /* wait till output is gone */ | ||
950 | (void) fclose(fd); | ||
951 | } | ||
952 | #endif | ||
953 | #ifdef __linux__ | ||
954 | { | ||
955 | char hn[MAXHOSTNAMELEN + 1]; | ||
956 | |||
957 | (void) gethostname(hn, MAXHOSTNAMELEN); | ||
958 | write(1, hn, strlen(hn)); | ||
959 | } | ||
960 | #endif | ||
961 | (void) write(1, LOGIN, sizeof(LOGIN) - 1); /* always show login prompt */ | ||
962 | } | ||
963 | |||
964 | /* next_speed - select next baud rate */ | ||
965 | void next_speed(tp, op) | ||
966 | struct termio *tp; | ||
967 | struct options *op; | ||
968 | { | ||
969 | static int baud_index = FIRST_SPEED; /* current speed index */ | ||
970 | |||
971 | baud_index = (baud_index + 1) % op->numspeed; | ||
972 | tp->c_cflag &= ~CBAUD; | ||
973 | tp->c_cflag |= op->speeds[baud_index]; | ||
974 | (void) ioctl(0, TCSETA, tp); | ||
975 | } | ||
976 | |||
977 | /* get_logname - get user name, establish parity, speed, erase, kill, eol */ | ||
978 | /* return NULL on failure, logname on success */ | ||
979 | char *get_logname(op, cp, tp) | ||
980 | struct options *op; | ||
981 | struct chardata *cp; | ||
982 | struct termio *tp; | ||
983 | { | ||
984 | static char logname[BUFSIZ]; | ||
985 | char *bp; | ||
986 | char c; /* input character, full eight bits */ | ||
987 | char ascval; /* low 7 bits of input character */ | ||
988 | int bits; /* # of "1" bits per character */ | ||
989 | int mask; /* mask with 1 bit up */ | ||
990 | static char *erase[] = { /* backspace-space-backspace */ | ||
991 | "\010\040\010", /* space parity */ | ||
992 | "\010\040\010", /* odd parity */ | ||
993 | "\210\240\210", /* even parity */ | ||
994 | "\210\240\210", /* no parity */ | ||
995 | }; | ||
996 | |||
997 | /* Initialize kill, erase, parity etc. (also after switching speeds). */ | ||
998 | |||
999 | *cp = init_chardata; | ||
1000 | |||
1001 | /* Flush pending input (esp. after parsing or switching the baud rate). */ | ||
1002 | |||
1003 | (void) sleep(1); | ||
1004 | (void) ioctl(0, TCFLSH, TCIFLUSH); | ||
1005 | |||
1006 | /* Prompt for and read a login name. */ | ||
1007 | |||
1008 | for (*logname = 0; *logname == 0; /* void */ ) { | ||
1009 | |||
1010 | /* Write issue file and prompt, with "parity" bit == 0. */ | ||
1011 | |||
1012 | do_prompt(op, tp); | ||
1013 | |||
1014 | /* Read name, watch for break, parity, erase, kill, end-of-line. */ | ||
1015 | |||
1016 | for (bp = logname, cp->eol = 0; cp->eol == 0; /* void */ ) { | ||
1017 | |||
1018 | /* Do not report trivial EINTR/EIO errors. */ | ||
1019 | |||
1020 | if (read(0, &c, 1) < 1) { | ||
1021 | if (errno == EINTR || errno == EIO) | ||
1022 | exit(0); | ||
1023 | error("%s: read: %m", op->tty); | ||
1024 | } | ||
1025 | /* Do BREAK handling elsewhere. */ | ||
1026 | |||
1027 | if ((c == 0) && op->numspeed > 1) | ||
1028 | /* return (0); */ | ||
1029 | return NULL; | ||
1030 | |||
1031 | /* Do parity bit handling. */ | ||
1032 | |||
1033 | if (c != (ascval = (c & 0177))) { /* "parity" bit on ? */ | ||
1034 | for (bits = 1, mask = 1; mask & 0177; mask <<= 1) | ||
1035 | if (mask & ascval) | ||
1036 | bits++; /* count "1" bits */ | ||
1037 | cp->parity |= ((bits & 1) ? 1 : 2); | ||
1038 | } | ||
1039 | /* Do erase, kill and end-of-line processing. */ | ||
1040 | |||
1041 | switch (ascval) { | ||
1042 | case CR: | ||
1043 | case NL: | ||
1044 | *bp = 0; /* terminate logname */ | ||
1045 | cp->eol = ascval; /* set end-of-line char */ | ||
1046 | break; | ||
1047 | case BS: | ||
1048 | case DEL: | ||
1049 | case '#': | ||
1050 | cp->erase = ascval; /* set erase character */ | ||
1051 | if (bp > logname) { | ||
1052 | (void) write(1, erase[cp->parity], 3); | ||
1053 | bp--; | ||
1054 | } | ||
1055 | break; | ||
1056 | case CTL('U'): | ||
1057 | case '@': | ||
1058 | cp->kill = ascval; /* set kill character */ | ||
1059 | while (bp > logname) { | ||
1060 | (void) write(1, erase[cp->parity], 3); | ||
1061 | bp--; | ||
1062 | } | ||
1063 | break; | ||
1064 | case CTL('D'): | ||
1065 | exit(0); | ||
1066 | default: | ||
1067 | if (!isascii(ascval) || !isprint(ascval)) { | ||
1068 | /* ignore garbage characters */ ; | ||
1069 | } else if (bp - logname >= sizeof(logname) - 1) { | ||
1070 | error("%s: input overrun", op->tty); | ||
1071 | } else { | ||
1072 | (void) write(1, &c, 1); /* echo the character */ | ||
1073 | *bp++ = ascval; /* and store it */ | ||
1074 | } | ||
1075 | break; | ||
1076 | } | ||
1077 | } | ||
1078 | } | ||
1079 | /* Handle names with upper case and no lower case. */ | ||
1080 | |||
1081 | if ((cp->capslock = caps_lock(logname))) { | ||
1082 | for (bp = logname; *bp; bp++) | ||
1083 | if (isupper(*bp)) | ||
1084 | *bp = tolower(*bp); /* map name to lower case */ | ||
1085 | } | ||
1086 | return (logname); | ||
1087 | } | ||
1088 | |||
1089 | /* termio_final - set the final tty mode bits */ | ||
1090 | void termio_final(op, tp, cp) | ||
1091 | struct options *op; | ||
1092 | struct termio *tp; | ||
1093 | struct chardata *cp; | ||
1094 | { | ||
1095 | /* General terminal-independent stuff. */ | ||
1096 | |||
1097 | tp->c_iflag |= IXON | IXOFF; /* 2-way flow control */ | ||
1098 | tp->c_lflag |= ICANON | ISIG | ECHO | ECHOE | ECHOK | ECHOKE; | ||
1099 | /* no longer| ECHOCTL | ECHOPRT */ | ||
1100 | tp->c_oflag |= OPOST; | ||
1101 | /* tp->c_cflag = 0; */ | ||
1102 | tp->c_cc[VINTR] = DEF_INTR; /* default interrupt */ | ||
1103 | tp->c_cc[VQUIT] = DEF_QUIT; /* default quit */ | ||
1104 | tp->c_cc[VEOF] = DEF_EOF; /* default EOF character */ | ||
1105 | tp->c_cc[VEOL] = DEF_EOL; | ||
1106 | #ifdef __linux__ | ||
1107 | tp->c_cc[VSWTC] = DEF_SWITCH; /* default switch character */ | ||
1108 | #else | ||
1109 | tp->c_cc[VSWTCH] = DEF_SWITCH; /* default switch character */ | ||
1110 | #endif | ||
1111 | |||
1112 | /* Account for special characters seen in input. */ | ||
1113 | |||
1114 | if (cp->eol == CR) { | ||
1115 | tp->c_iflag |= ICRNL; /* map CR in input to NL */ | ||
1116 | tp->c_oflag |= ONLCR; /* map NL in output to CR-NL */ | ||
1117 | } | ||
1118 | tp->c_cc[VERASE] = cp->erase; /* set erase character */ | ||
1119 | tp->c_cc[VKILL] = cp->kill; /* set kill character */ | ||
1120 | |||
1121 | /* Account for the presence or absence of parity bits in input. */ | ||
1122 | |||
1123 | switch (cp->parity) { | ||
1124 | case 0: /* space (always 0) parity */ | ||
1125 | break; | ||
1126 | case 1: /* odd parity */ | ||
1127 | tp->c_cflag |= PARODD; | ||
1128 | /* FALLTHROUGH */ | ||
1129 | case 2: /* even parity */ | ||
1130 | tp->c_cflag |= PARENB; | ||
1131 | tp->c_iflag |= INPCK | ISTRIP; | ||
1132 | /* FALLTHROUGH */ | ||
1133 | case (1 | 2): /* no parity bit */ | ||
1134 | tp->c_cflag &= ~CSIZE; | ||
1135 | tp->c_cflag |= CS7; | ||
1136 | break; | ||
1137 | } | ||
1138 | /* Account for upper case without lower case. */ | ||
1139 | |||
1140 | if (cp->capslock) { | ||
1141 | tp->c_iflag |= IUCLC; | ||
1142 | tp->c_lflag |= XCASE; | ||
1143 | tp->c_oflag |= OLCUC; | ||
1144 | } | ||
1145 | /* Optionally enable hardware flow control */ | ||
1146 | |||
1147 | #ifdef CRTSCTS | ||
1148 | if (op->flags & F_RTSCTS) | ||
1149 | tp->c_cflag |= CRTSCTS; | ||
1150 | #endif | ||
1151 | |||
1152 | /* Finally, make the new settings effective */ | ||
1153 | |||
1154 | if (ioctl(0, TCSETA, tp) < 0) | ||
1155 | error("%s: ioctl: TCSETA: %m", op->tty); | ||
1156 | } | ||
1157 | |||
1158 | /* caps_lock - string contains upper case without lower case */ | ||
1159 | /* returns 1 if true, 0 if false */ | ||
1160 | int caps_lock(s) | ||
1161 | char *s; | ||
1162 | { | ||
1163 | int capslock; | ||
1164 | |||
1165 | for (capslock = 0; *s; s++) { | ||
1166 | if (islower(*s)) | ||
1167 | return (0); | ||
1168 | if (capslock == 0) | ||
1169 | capslock = isupper(*s); | ||
1170 | } | ||
1171 | return (capslock); | ||
1172 | } | ||
1173 | |||
1174 | /* bcode - convert speed string to speed code; return 0 on failure */ | ||
1175 | int bcode(s) | ||
1176 | char *s; | ||
1177 | { | ||
1178 | struct Speedtab *sp; | ||
1179 | long speed = atol(s); | ||
1180 | |||
1181 | for (sp = speedtab; sp->speed; sp++) | ||
1182 | if (sp->speed == speed) | ||
1183 | return (sp->code); | ||
1184 | return (0); | ||
1185 | } | ||
1186 | |||
1187 | /* error - report errors to console or syslog; only understands %s and %m */ | ||
1188 | |||
1189 | #define str2cpy(b,s1,s2) strcat(strcpy(b,s1),s2) | ||
1190 | |||
1191 | /* | ||
1192 | * output error messages | ||
1193 | */ | ||
1194 | static void error(const char *fmt, ...) | ||
1195 | { | ||
1196 | va_list va_alist; | ||
1197 | char buf[256], *bp; | ||
1198 | |||
1199 | #ifndef USE_SYSLOG | ||
1200 | int fd; | ||
1201 | #endif | ||
1202 | |||
1203 | #ifdef USE_SYSLOG | ||
1204 | buf[0] = '\0'; | ||
1205 | bp = buf; | ||
1206 | #else | ||
1207 | strncpy(buf, progname, 256); | ||
1208 | strncat(buf, ": ", 256); | ||
1209 | buf[255] = 0; | ||
1210 | bp = buf + strlen(buf); | ||
1211 | #endif | ||
1212 | |||
1213 | va_start(va_alist, fmt); | ||
1214 | vsnprintf(bp, 256 - strlen(buf), fmt, va_alist); | ||
1215 | buf[255] = 0; | ||
1216 | va_end(va_alist); | ||
1217 | |||
1218 | #ifdef USE_SYSLOG | ||
1219 | openlog(progname, LOG_PID, LOG_AUTH); | ||
1220 | syslog(LOG_ERR, buf); | ||
1221 | closelog(); | ||
1222 | #else | ||
1223 | strncat(bp, "\r\n", 256 - strlen(buf)); | ||
1224 | buf[255] = 0; | ||
1225 | if ((fd = open("/dev/console", 1)) >= 0) { | ||
1226 | write(fd, buf, strlen(buf)); | ||
1227 | close(fd); | ||
1228 | } | ||
1229 | #endif | ||
1230 | (void) sleep((unsigned) 10); /* be kind to init(8) */ | ||
1231 | exit(1); | ||
1232 | } | ||