|
|
1.1 root 1: /* /sccs/src/cmd/uucp/s.uugetty.c
2: uugetty.c 1.3 8/30/84 17:38:06
3: */
4: #include "uucp.h"
5: VERSION(@(#)uugetty.c 1.3);
6:
7: /* @(#)getty.c 1.5 */
8: /* This program, uugetty, is the standard getty modified */
9: /* to allow a tty line to be used by uucp/cu or a dial in. */
10: /* For it to work with 801/212 dialers, */
11: /* put an entry into inittab like */
12: /* 30:2:respawn:/usr/lib/uucp/uugetty -t 60 cul04 1200 */
13: /* For direct lines, or intelligent modems use */
14: /* 30:2:respawn:/usr/lib/uucp/uugetty -r -t 60 cul04 1200 */
15: /* When this line is used, the Systems file that is */
16: /* used to call into it must have the following script */
17: /* "" \r\d\r\d\r\d\r in:--in: ... */
18: /* This is because the uugetty expects to read a character */
19: /* before the login message is output. */
20:
21: /* It will only work on USG systems at least 5.0 or systems */
22: /* that permit kill(0, pid). */
23: /* This scheme was proposed by Larry Wehr and works as follows: */
24: /* The fopen of the line hangs until carrier is detected. */
25: /* At this point, uugetty attempts to create a LCK..line file */
26: /* If if fails, that means that uucico or cu are using the line. */
27: /* In this case, just do a busy wait, periodically checking */
28: /* for the LCK..line file. When it goes away, then exit and */
29: /* a new uugetty will be spawned. */
30: /* If it succeeds, then this is someone logging in--do normal */
31: /* getty processing. */
32: /* NOTE: */
33: /* When the person hangs up (login case) the LCK..line file */
34: /* will remain, but this is ok because the ulockf() function */
35: /* used by uucico and uugetty and cu check the pid in the LCK */
36: /* file and if it doesn't exist, the LCK file is removed when */
37: /* it is needed. */
38: /* Also, uugetty always sets the owner of the line to uucp. */
39: /* This is so that uucico/cu can get at the line. (The new */
40: /* cu will run setuid uucp--or this will not work.) */
41: /* */
42: /* There is an additional option for direct lines and lines */
43: /* that have intelligent modems (ones that return on open */
44: /* immediately. The -r option means wait for one character */
45: /* before putting out the login message. If the character */
46: /* comes in, then check the LCK file and proceed as above. */
47:
48:
49: /* getty - sets up speed, various terminal flags, line discipline, */
50: /* and waits for new prospective user to enter name, before */
51: /* calling "login". */
52: /* */
53: /* Usage: getty [-r] [-h] [-t time] line speed_label terminal */
54: /* line_disc */
55: /* */
56: /* -h says don't hangup by dropping carrier during the */
57: /* initialization phase. Normally carrier is dropped to */
58: /* make the dataswitch release the line. */
59: /* -t says timeout after the number of seconds in "time" have */
60: /* elapsed even if nothing is typed. This is useful */
61: /* for making sure dialup lines release if someone calls */
62: /* in and then doesn't actually login in. */
63: /* -r says wait for a character before putting out login message */
64: /* (This is for uugetty.c with intelligent modems */
65: /* "line" is the device in "/dev". */
66: /* "speed_label" is a pointer into the "/etc/getty_defs" */
67: /* where the definition for the speeds and */
68: /* other associated flags are to be found. */
69: /* "terminal" is the name of the terminal type. */
70: /* "line_disc" is the name of the line discipline. */
71: /* */
72: /* Usage: getty -c gettydefs_like_file */
73: /* */
74: /* The "-c" flag is used to have "getty" check a gettydefs file. */
75: /* "getty" parses the entire file and prints out its findings so */
76: /* that the user can make sure that the file contains the proper */
77: /* information. */
78: /* */
79:
80: /* dummies for using uucp .o routines */
81: void assert(){}
82: cleanup(){}
83: void logent(){} /* so we can load ulockf() */
84:
85: /* undefine DEBUG - it is defined in uucp.h */
86: #undef DEBUG
87:
88: #include <utmp.h>
89: #include <sys/crtctl.h>
90:
91: #define TRUE 1
92: #define FALSE 0
93: #define FAILURE -1
94:
95: #define SUCCESS 0
96: #define ID 1
97: #define IFLAGS 2
98: #define FFLAGS 3
99: #define MESSAGE 4
100: #define NEXTID 5
101:
102: #define ACTIVE 1
103: #define FINISHED 0
104:
105: #define ABORT 0177 /* Delete */
106: #define QUIT ('\\'&037) /* ^\ */
107: #define ERASE '#'
108: #define BACKSPACE '\b'
109: #define KILL '@'
110:
111: #ifdef OSS
112: /* The following three characters are the standard OSS erase, */
113: /* kill, and abort characters. */
114:
115: #define STDERASE '_'
116: #define STDKILL '$'
117: #define STDABORT '&'
118: #endif
119:
120: #define control(x) (x&037)
121:
122: #define GOODNAME 1
123: #define NONAME 0
124: #define BADSPEED -1
125:
126: #ifndef fioctl
127: #define fioctl(x,y,z) ioctl(fileno(x),y,z)
128: #endif
129:
130: struct Gdef {
131: char *g_id; /* identification for modes & speeds */
132: struct termio g_iflags; /* initial terminal flags */
133: struct termio g_fflags; /* final terminal flags */
134: char *g_message; /* login message */
135: char *g_nextid; /* next id if this speed is wrong */
136: };
137:
138: #define MAXIDLENGTH 15 /* Maximum length the "g_id" and "g_nextid" \
139: * strings can take. Longer ones will be \
140: * truncated. \
141: */
142: #define MAXMESSAGE 79 /* Maximum length the "g_message" string \
143: * can be. Longer ones are truncated. \
144: */
145:
146: /* Maximum length of line in /etc/gettydefs file and the maximum */
147: /* length of the user response to the "login" message. */
148:
149: #define MAXLINE 255
150: #define MAXARGS 64 /* Maximum number of arguments that can be \
151: * passed to "login" \
152: */
153:
154: struct Symbols {
155: char *s_symbol; /* Name of symbol */
156: unsigned s_value ; /* Value of symbol */
157: };
158:
159: /* The following four symbols define the "SANE" state. */
160:
161: #define ISANE (BRKINT|IGNPAR|ISTRIP|ICRNL|IXON)
162: #define OSANE (OPOST|ONLCR)
163: #define CSANE (CS7|PARENB|CREAD)
164: #define LSANE (ISIG|ICANON|ECHO|ECHOK)
165:
166: /* Modes set with the TCSETAW ioctl command. */
167:
168: struct Symbols imodes[] = {
169: "IGNBRK", IGNBRK,
170: "BRKINT", BRKINT,
171: "IGNPAR", IGNPAR,
172: "PARMRK", PARMRK,
173: "INPCK", INPCK,
174: "ISTRIP", ISTRIP,
175: "INLCR", INLCR,
176: "IGNCR", IGNCR,
177: "ICRNL", ICRNL,
178: "IUCLC", IUCLC,
179: "IXON", IXON,
180: "IXANY", IXANY,
181: "IXOFF", IXOFF,
182: NULL, 0
183: };
184:
185: struct Symbols omodes[] = {
186: "OPOST", OPOST,
187: "OLCUC", OLCUC,
188: "ONLCR", ONLCR,
189: "OCRNL", OCRNL,
190: "ONOCR", ONOCR,
191: "ONLRET", ONLRET,
192: "OFILL", OFILL,
193: "OFDEL", OFDEL,
194: "NLDLY", NLDLY,
195: "NL0", NL0,
196: "NL1", NL1,
197: "CRDLY", CRDLY,
198: "CR0", CR0,
199: "CR1", CR1,
200: "CR2", CR2,
201: "CR3", CR3,
202: "TABDLY", TABDLY,
203: "TAB0", TAB0,
204: "TAB1", TAB1,
205: "TAB2", TAB2,
206: "TAB3", TAB3,
207: "BSDLY", BSDLY,
208: "BS0", BS0,
209: "BS1", BS1,
210: "VTDLY", VTDLY,
211: "VT0", VT0,
212: "VT1", VT1,
213: "FFDLY", FFDLY,
214: "FF0", FF0,
215: "FF1", FF1,
216: NULL, 0
217: };
218:
219: struct Symbols cmodes[] = {
220: "B0", B0,
221: "B50", B50,
222: "B75", B75,
223: "B110", B110,
224: "B134", B134,
225: "B150", B150,
226: "B200", B200,
227: "B300", B300,
228: "B600", B600,
229: "B1200", B1200,
230: "B1800", B1800,
231: "B2400", B2400,
232: "B4800", B4800,
233: "B9600", B9600,
234: #ifdef EXTA
235: "EXTA", EXTA,
236: #endif
237: #ifdef EXTB
238: "EXTB", EXTB,
239: #endif
240: #ifdef B19200
241: "B19200", B19200,
242: #endif
243: #ifdef B38400
244: "B38400", B38400,
245: #endif
246: "CS5", CS5,
247: "CS6", CS6,
248: "CS7", CS7,
249: "CS8", CS8,
250: "CSTOPB", CSTOPB,
251: "CREAD", CREAD,
252: "PARENB", PARENB,
253: "PARODD", PARODD,
254: "HUPCL", HUPCL,
255: "CLOCAL", CLOCAL,
256: NULL, 0
257: };
258:
259: struct Symbols lmodes[] = {
260: "ISIG", ISIG,
261: "ICANON", ICANON,
262: "XCASE", XCASE,
263: "ECHO", ECHO,
264: "ECHOE", ECHOE,
265: "ECHOK", ECHOK,
266: "ECHONL", ECHONL,
267: "NOFLSH", NOFLSH,
268: NULL, 0
269: };
270:
271: /* Terminal types set with the LDSETT ioctl command. */
272:
273: struct Symbols terminals[] = {
274: "none", TERM_NONE,
275: #ifdef TERM_V10
276: "vt100", TERM_V10,
277: #endif
278: #ifdef TERM_H45
279: "hp45", TERM_H45,
280: #endif
281: #ifdef TERM_C10
282: "c100", TERM_C100,
283: #endif
284: #ifdef TERM_TEX
285: "tektronix", TERM_TEX,
286: "tek", TERM_TEX,
287: #endif
288: #ifdef TERM_D40
289: "ds40-1", TERM_D40,
290: #endif
291: #ifdef TERM_V61
292: "vt61", TERM_V61,
293: #endif
294: #ifdef TERM_TEC
295: "tec", TERM_TEC,
296: #endif
297: NULL, 0
298: };
299:
300: /* Line disciplines set by the TIOCSETD ioctl command. */
301:
302: #ifndef LDISC0
303: #define LDISC0 0
304: #endif
305:
306: struct Symbols linedisc[] = {
307: "LDISC0", LDISC0,
308: NULL, 0
309: };
310:
311: /* If the /etc/gettydefs file can't be opened, the following */
312: /* default is used. */
313:
314: struct Gdef DEFAULT = {
315: "default",
316: ICRNL,0,B300+CREAD+HUPCL,0,
317: LDISC0,ABORT,QUIT,ERASE,KILL,'\0','\0','\0','\0',
318: ICRNL,OPOST+ONLCR+NLDLY+TAB3,B300+CS7+CREAD+HUPCL,
319: ISIG+ICANON+ECHO+ECHOE+ECHOK,
320: LDISC0,ABORT,QUIT,ERASE,KILL,'\0','\0','\0','\0',
321: "LOGIN: ",
322: "default"
323: };
324:
325: #ifndef DEBUG
326: char *CTTY = "/dev/syscon";
327: #else
328: char *CTTY = "/dev/sysconx";
329: #endif
330:
331: char *ISSUE_FILE = "/etc/issue";
332: char *GETTY_DEFS = "/etc/gettydefs";
333:
334: int check = {
335: FALSE
336: };
337: char *checkgdfile; /* Name of gettydefs file during
338: * check mode.
339: */
340:
341: main(argc,argv)
342: int argc;
343: char **argv;
344: {
345: char *line;
346: register struct Gdef *speedef;
347: char oldspeed[MAXIDLENGTH+1],newspeed[MAXIDLENGTH+1];
348: extern struct Gdef *find_def();
349: int termtype,lined;
350: extern char *ISSUE_FILE,*GETTY_DEFS;
351: extern int check;
352: int hangup,timeout;
353: extern char *checkgdfile;
354: extern struct Symbols *search(),terminals[],linedisc[];
355: extern int timedout();
356: register struct Symbols *answer;
357: char user[MAXLINE],*largs[MAXARGS],*ptr,buffer[MAXLINE];
358: int wait_read = FALSE; /* wait for read before output "login" */
359: FILE *fp;
360: FILE *fdup();
361: struct utsname utsname;
362: struct termcb termcb;
363: struct termio termio;
364: static char clrscreen[2] = {
365: ESC,CS
366: };
367: struct stat statb;
368: char lckname[MAXNAMESIZE]; /* lock file name LCK..line */
369:
370: signal(SIGINT,SIG_IGN);
371: signal(SIGQUIT,SIG_DFL);
372:
373: hangup = TRUE;
374: timeout = 0;
375: while(--argc && **++argv == '-') {
376: for(ptr = *argv + 1; *ptr;ptr++) switch(*ptr) {
377: case 'h':
378: hangup = FALSE;
379: break;
380: case 'r':
381: wait_read = TRUE;
382: break;
383: case 't':
384: if(isdigit(*++ptr)) {
385: sscanf(ptr,"%d",&timeout);
386:
387: /* Advance "ptr" so that it is pointing to the last digit of the */
388: /* timeout argument. */
389: while(isdigit(*++ptr));
390: ptr--;
391: } else if(--argc) {
392: if(isdigit(*(ptr = *++argv)))
393: sscanf(ptr,"%d",&timeout);
394: else error("getty: timeout argument invalid. \"%s\"\n", *argv);
395: }
396: break;
397:
398: /* Check a "gettydefs" file mode. */
399: case 'c':
400: signal(SIGINT,SIG_DFL);
401: if(--argc == 0) {
402: fprintf(stderr,
403: "Check Mode Usage: getty -c gettydefs-like-file\n");
404: exit(1);
405: }
406: check = TRUE;
407: checkgdfile = *++argv;
408:
409: /* Attempt to open the check gettydefs file. */
410: if((fp = fopen(checkgdfile,"r")) == NULL) {
411: fprintf(stderr,"Cannot open %s\n",checkgdfile);
412: exit(1);
413: }
414: fclose(fp);
415:
416: /* Call "find_def" to check the check file. With the "check" flag */
417: /* set, it will parse the entire file, printing out the results. */
418: find_def(NULL);
419: exit(0);
420: default:
421: break;
422: }
423: }
424:
425: /* There must be at least one argument. If there isn't, complain */
426: /* and then die after 20 seconds. The 20 second sleep is to keep */
427: /* "init" from working too hard. */
428: if(argc < 1) {
429: error("getty: no terminal line specified.\n");
430: sleep(20);
431: exit(1);
432: } else line = *argv;
433:
434: /* If a "speed_label" was provided, search for it in the */
435: /* "getty_defs" file. If none was provided, take the first entry */
436: /* of the "getty_defs" file as the initial settings. */
437: if(--argc > 0 ) {
438: if((speedef = find_def(*++argv)) == NULL) {
439: error("getty: unable to find %s in \"%s\".\n",
440: *argv,GETTY_DEFS);
441:
442: /* Use the default value instead. */
443: speedef = find_def(NULL);
444: }
445: } else speedef = find_def(NULL);
446:
447: /* If a terminal type was supplied, try to find it in list. */
448: if(--argc > 0) {
449: if((answer = search(*++argv,terminals)) == NULL) {
450: error("getty: %s is an undefined terminal type.\n",
451: *argv);
452: termtype = TERM_NONE;
453: } else termtype = answer->s_value;
454: } else termtype = TERM_NONE;
455:
456: /* If a line discipline was supplied, try to find it in list. */
457: if(--argc > 0) {
458: if((answer = search(*++argv,linedisc)) == NULL) {
459: error("getty: %s is an undefined line discipline.\n",
460: *argv);
461: lined = LDISC0;
462: } else lined = answer->s_value;
463: } else lined = LDISC0;
464:
465: /* Perform "utmp" accounting. */
466: account(line);
467:
468: /* Attempt to open standard input, output, and error on specified */
469: /* line. */
470: chdir("/dev");
471:
472: /* Code added for shared line - input/output */
473: /* For use by uucico/cu/ct */
474: /* Method: -- wait for open */
475: /* When success, check to see if LCK..line exists */
476: /* If it does, that means that uucico/cu/ct is */
477: /* using the line, so busy wait and exit when */
478: /* the LCK..line file goes away */
479: /* If no LCK..line file, normal processing-- */
480: /* close the line and use openline() as usual */
481: /* If the -r option, wait for first character also. */
482:
483: /* Change the ownership of the terminal line to uucp and set */
484: /* the protections to only allow uucp to read the line. */
485: stat(line,&statb);
486: chown(line,UUCPUID,statb.st_gid); /* for uugetty use uucp uid */
487: chmod(line,0622);
488:
489: (void) close(0);
490: (void)fclose(stdin);
491: (void) close(1);
492: (void) close(2);
493: (void) fclose(stdout);
494: (void) fclose(stderr);
495: if ( (fopen(line, "r+")) == NULL) { /* this opens stdin */
496: error("getty: cannot open \"%s\". errno: %d\n",line,errno);
497: sleep(20);
498: exit(1);
499: }
500: if (wait_read) { /* wait to read the first character */
501: /* Set the terminal type and line discipline. */
502: setupline(speedef,termtype,lined);
503: /*
504: * Check for read failure or and EOT sent
505: * (EOT may come from a cu on the other side.)
506: * This code is to prevent the situation of
507: * "login" program getting started here while
508: * a uugetty is running on the other end of the
509: * line.
510: * NOTE: Cu on a direct line when ~. is encountered will
511: * send EOTs to the other side. EOT=\004
512: */
513: if ( read(0, buffer, 1) < 0
514: || *buffer == '\004') {
515: (void) fclose(stdin);
516: sleep(10);
517: exit(0);
518: }
519: }
520:
521: if (mlock(line)) { /* There is a lock file already */
522: /* some process is using the line for output */
523: (void) fclose(stdin);
524: (void) sprintf(lckname, "%s.%s", LOCKPRE, line);
525: for (;;) { /* busy wait for LCK..line to go away */
526: sleep(60);
527: if (checkLock(lckname) == 0) /* LCK..line gone */
528: break;
529: }
530: exit(0);
531: }
532:
533: openline(line,speedef,termtype,lined,hangup);
534:
535: /* Loop until user is successful in requesting login. */
536: for(;;) {
537:
538: /* If there is no terminal type, just advance a line. */
539: if(termtype == TERM_NONE) {
540:
541: /* A bug in the stdio package requires that the first output on */
542: /* the newly reopened stderr stream be a putc rather than an */
543: /* fprintf. */
544: putc('\r',stderr);
545: putc('\n',stderr);
546:
547: /* If there is a terminal type, clear the screen with the common */
548: /* crt language. Note that the characters have to be written in */
549: /* one write, and hence can't go through standard io, which is */
550: /* currently unbuffered. */
551: } else write(fileno(stderr),clrscreen,sizeof(clrscreen));
552:
553: /* If getty is supposed to die if no one logs in after a */
554: /* predetermined amount of time, set the timer. */
555: if(timeout) {
556: signal(SIGALRM,timedout);
557: alarm(timeout);
558: }
559:
560: #ifdef SYS_NAME
561: /* Generate a message with the system identification in it. */
562: if (uname(&utsname) != FAILURE) {
563: sprintf(buffer,"%.9s\r\n", utsname.nodename);
564:
565: #ifdef UPPERCASE_ONLY
566: /* Make all the alphabetics upper case. */
567: for (ptr= buffer; *ptr;ptr++) *ptr = tolower(*ptr);
568: #endif
569: fputs(buffer,stderr);
570: }
571:
572: /* Print out the issue file. */
573: if ((fp = fopen(ISSUE_FILE,"r")) != NULL) {
574: while ((ptr = fgets(buffer,sizeof(buffer),fp)) != NULL) {
575: fputs(ptr,stderr);
576:
577: /* In "raw" mode, a carriage return must be supplied at the end of */
578: /* each line. */
579: putc('\r',stderr);
580: }
581: fclose(fp);
582: }
583: #endif
584:
585: /* Print the login message. */
586: fprintf(stderr,"%s",speedef->g_message);
587:
588: /* Get the user's typed response and respond appropriately. */
589: switch(getname(user,&termio)) {
590: case GOODNAME:
591: if (timeout) alarm(0);
592:
593: /* If a terminal type was specified, keep only those parts of */
594: /* the gettydef final settings which were not explicitely turned */
595: /* on when the terminal type was set. */
596: if (termtype != TERM_NONE) {
597: termio.c_iflag |= (ISTRIP|ICRNL|IXON|IXANY)
598: | (speedef->g_fflags.c_iflag
599: & ~(ISTRIP|ICRNL|IXON|IXANY));
600: termio.c_oflag |= (OPOST|ONLCR)
601: | (speedef->g_fflags.c_oflag
602: & ~(OPOST|ONLCR));
603: termio.c_cflag = speedef->g_fflags.c_cflag;
604: termio.c_lflag = (ISIG|ICANON|ECHO|ECHOE|ECHOK)
605: | (speedef->g_fflags.c_lflag
606: & ~(ISIG|ICANON|ECHO|ECHOE|ECHOK));
607: } else {
608: termio.c_iflag |= speedef->g_fflags.c_iflag;
609: termio.c_oflag |= speedef->g_fflags.c_oflag;
610: termio.c_cflag |= speedef->g_fflags.c_cflag;
611: termio.c_lflag |= speedef->g_fflags.c_lflag;
612: }
613: termio.c_line = lined;
614: fioctl(stdin,TCSETAW,&termio);
615:
616: /* Parse the input line from the user, breaking it at white */
617: /* spaces. */
618: largs[0] = "login";
619: parse(user,&largs[1],MAXARGS-1);
620:
621: /* Exec "login". */
622:
623: #ifndef DEBUG
624: execv("/bin/login",largs);
625: exit(1);
626: #else
627: exit(0);
628: #endif
629:
630: /* If the speed supplied was bad, try the next speed in the list. */
631: case BADSPEED:
632:
633: /* Save the name of the old speed definition incase new one is */
634: /* bad. Copy the new speed out of the static so that "find_def" */
635: /* won't overwrite it in the process of looking for new entry. */
636: strcpy(oldspeed,speedef->g_id);
637: strcpy(newspeed,speedef->g_nextid);
638: if ((speedef = find_def(newspeed)) == NULL) {
639: error("getty: pointer to next speed in entry %s is bad.\n",
640: oldspeed);
641:
642: /* In case of error, go back to the original entry. */
643: if((speedef = find_def(oldspeed)) == NULL) {
644:
645: /* If the old entry has disappeared, then quit and let next "getty" try. */
646: error("getty: unable to find %s again.\n",
647: oldspeed);
648: exit(1);
649: }
650: }
651:
652: /* Setup the terminal for the new information. */
653: setupline(speedef,termtype,lined);
654: break;
655:
656: /* If no name was supplied, not nothing, but try again. */
657: case NONAME:
658: break;
659: }
660: }
661: }
662:
663: account(line)
664: char *line;
665: {
666: register int ownpid;
667: register struct utmp *u;
668: extern struct utmp *getutent(), *pututline();
669: register FILE *fp;
670:
671: /* Look in "utmp" file for our own entry and change it to LOGIN. */
672: ownpid = getpid();
673:
674: while ((u = getutent()) != NULL) {
675:
676: /* Is this our own entry? */
677: if (u->ut_type == INIT_PROCESS && u->ut_pid == ownpid) {
678: strncpy(u->ut_line,line,sizeof(u->ut_line));
679: strncpy(u->ut_user,"LOGIN",sizeof(u->ut_user));
680: u->ut_type = LOGIN_PROCESS;
681:
682: /* Write out the updated entry. */
683: pututline(u);
684: break;
685: }
686: }
687:
688: /* If we were successful in finding an entry for ourself in the */
689: /* utmp file, then attempt to append to the end of the wtmp file. */
690: if (u != NULL && (fp = fopen(WTMP_FILE,"r+")) != NULL) {
691: fseek(fp,0L,2); /* Seek to end of file */
692: fwrite(u,sizeof(*u),1,fp);
693: fclose(fp);
694: }
695:
696: /* Close the utmp file. */
697: endutent();
698: }
699:
700: /* "search" scans through a table of Symbols trying to find a */
701: /* match for the supplied string. If it does, it returns the */
702: /* pointer to the Symbols structure, otherwise it returns NULL. */
703:
704: struct Symbols *search(target,symbols)
705: register char *target;
706: register struct Symbols *symbols;
707: {
708:
709: /* Each symbol array terminates with a null pointer for an */
710: /* "s_symbol". Scan until a match is found, or the null pointer */
711: /* is reached. */
712: for (;symbols->s_symbol != NULL; symbols++)
713: if (strcmp(target,symbols->s_symbol) == 0) return(symbols);
714: return(NULL);
715: }
716:
717: error(format,arg1,arg2,arg3,arg4)
718: char *format;
719: int arg1,arg2,arg3,arg4;
720: {
721: register FILE *fp;
722:
723: if ((fp = fopen(CTTY,"w")) == NULL) return;
724: else {
725: fprintf(fp,format,arg1,arg2,arg3,arg4);
726: fclose(fp);
727: }
728: }
729:
730: openline(line,speedef,termtype,lined,hangup)
731: register char *line;
732: register struct Gdef *speedef;
733: int termtype,lined,hangup;
734: {
735: register FILE *fpin,*fp;
736: extern int errno;
737:
738: close(1);
739: close(2);
740: fclose(stdout);
741: fclose(stderr);
742:
743: fdup(stdin);
744: fdup(stdin);
745: setbuf(stdin,NULL);
746: setbuf(stdout,NULL);
747: setbuf(stderr,NULL);
748:
749: /* Unless getty is being invoked by ct, make sure that DTR has been */
750: /* dropped and reasserted */
751: if (hangup) hang_up_line();
752:
753: /* Set the terminal type and line discipline. */
754: setupline(speedef,termtype,lined);
755: }
756:
757: #ifdef HANGUP
758:
759: hang_up_line()
760: {
761: struct termio termio;
762:
763: fioctl(stdin,TCGETA,&termio);
764: termio.c_cflag &= ~CBAUD;
765: termio.c_cflag |= B0;
766: fioctl(stdin,TCSETAF,&termio);
767: sleep(1);
768: }
769: #else
770: hang_up_line()
771: {
772: }
773: #endif
774:
775: timedout()
776: {
777: exit(1);
778: }
779:
780: setupline(speedef,termtype,lined)
781: register struct Gdef *speedef;
782: int termtype,lined;
783: {
784: struct termio termio;
785: struct termcb termcb;
786: unsigned short timer;
787:
788: /* Set the terminal type to "none", which will clear all old */
789: /* special flags, if a terminal type was set from before. */
790: termcb.st_flgs = 0;
791: termcb.st_termt = TERM_NONE;
792: termcb.st_vrow = 0;
793: fioctl(stdin,LDSETT,&termcb);
794: termcb.st_termt = termtype;
795: fioctl(stdin,LDSETT,&termcb);
796:
797: /* Get the current state of the modes and such for the terminal. */
798: fioctl(stdin,TCGETA,&termio);
799: if (termtype != TERM_NONE) {
800:
801: /* If there is a terminal type, take away settings so that */
802: /* terminal is "raw" and "no echo". Also take away the orginal */
803: /* speed setting. */
804: termio.c_iflag = 0;
805: termio.c_cflag &= ~(CSIZE|PARENB|CBAUD);
806: termio.c_cflag |= CS8|CREAD|HUPCL;
807: termio.c_lflag &= ~(ISIG|ICANON|ECHO|ECHOE|ECHOK);
808:
809: /* Add in the speed. */
810: termio.c_cflag |= (speedef->g_iflags.c_cflag & CBAUD);
811: } else {
812: termio.c_iflag = speedef->g_iflags.c_iflag;
813: termio.c_oflag = speedef->g_iflags.c_oflag;
814: termio.c_cflag = speedef->g_iflags.c_cflag;
815: termio.c_lflag = speedef->g_iflags.c_lflag;
816: }
817:
818: /* Make sure that raw reads are 1 character at a time with no */
819: /* timeout. */
820: termio.c_cc[VMIN] = 1;
821: termio.c_cc[VTIME] = 0;
822:
823: /* Add the line discipline. */
824: termio.c_line = lined;
825: fioctl(stdin,TCSETAF,&termio);
826:
827: /* Pause briefly while terminal settles. */
828: for(timer=0; ++timer != 0;);
829: }
830:
831: /* "getname" picks up the user's name from the standard input. */
832: /* It makes certain */
833: /* determinations about the modes that should be set up for the */
834: /* terminal depending upon what it sees. If it sees all UPPER */
835: /* case characters, it sets the IUCLC & OLCUC flags. If it sees */
836: /* a line terminated with a <linefeed>, it sets ICRNL. If it sees */
837: /* the user using the "standard" OSS erase, kill, abort, or line */
838: /* termination characters ( '_','$','&','/','!' respectively) */
839: /* it resets the erase, kill, and end of line characters. */
840:
841: int getname(user,termio)
842: char *user;
843: struct termio *termio;
844: {
845: register char *ptr,c;
846: register int rawc;
847: int upper,lower;
848:
849: /* Get the previous modes, erase, and kill characters and speeds. */
850: fioctl(stdin,TCGETA,termio);
851:
852: /* Set the flags to 0 and the erase and kill to the standard */
853: /* characters. */
854: termio->c_iflag &= ICRNL;
855: termio->c_oflag = 0;
856: termio->c_cflag = 0;
857: termio->c_lflag &= ECHO;
858: for (ptr= (char*)termio->c_cc; ptr < (char*)&termio->c_cc[NCC];)
859: *ptr++ = NULL;
860: termio->c_cc[VINTR] = ABORT;
861: termio->c_cc[VQUIT] = QUIT;
862: termio->c_cc[VERASE] = ERASE;
863: termio->c_cc[VKILL] = KILL;
864: termio->c_cc[VEOF] = ('D'&037);
865: ptr = user;
866: upper = 0;
867: lower = 0;
868: do {
869:
870: /* If it isn't possible to read line, exit. */
871: if ((rawc = getc(stdin)) == EOF) exit(0);
872:
873: /* If a null character was typed, return 0. */
874: if ((c = (rawc & 0177)) == '\0') return(BADSPEED);
875:
876: /* Echo the character if ECHO is off. */
877: if( (termio->c_lflag&ECHO) == 0 )
878: putc(rawc,stdout);
879: #ifdef OSS
880: if (c == ERASE || c == BACKSPACE) {
881:
882: /* Store this character as the "erase" character. */
883: termio->c_cc[VERASE] = c;
884: #else
885: if (c == ERASE) {
886: #endif
887:
888: /* If there is anything to erase, erase a character. */
889: if (ptr > user) --ptr;
890: }
891:
892: #ifdef OSS
893: else if (c == STDERASE) {
894: if (ptr > user) --ptr;
895:
896: /* Set up the "standard OSS" erase, kill, etc. characters. */
897: termio->c_cc[VINTR] = STDABORT;
898: termio->c_cc[VERASE] = STDERASE;
899: termio->c_cc[VKILL] = STDKILL;
900: termio->c_cc[VEOL] = '/';
901: termio->c_cc[VEOL2] = '!';
902: }
903: #endif
904:
905: /* If the character is a kill line or abort character, reset the */
906: /* line. */
907: else if (c == KILL || c == ABORT || c == control('U')) {
908: ptr = user;
909: fputs("\r\n",stdout);
910:
911: /* Make sure the erase, kill, etc. are set to the UNIX standard. */
912: termio->c_cc[VINTR] = ABORT;
913: termio->c_cc[VERASE] = ERASE;
914: termio->c_cc[VKILL] = KILL;
915: termio->c_cc[VEOL] = '\0';
916: termio->c_cc[VEOL2] = '\0';
917: }
918:
919: #ifdef OSS
920: else if (c == STDKILL || c == STDABORT) {
921: ptr = user;
922:
923: /* Set up the "standard OSS" erase, kill, etc. characters. */
924: termio->c_cc[VINTR] = STDABORT;
925: termio->c_cc[VERASE] = STDERASE;
926: termio->c_cc[VKILL] = STDKILL;
927: termio->c_cc[VEOL] = '/';
928: termio->c_cc[VEOL2] = '!';
929: }
930: #endif
931:
932: /* If the character is lower case, increment the flag for lower case. */
933: else if (islower(c)) {
934: lower++;
935: *ptr++ = c;
936: }
937:
938: /* If the character is upper case, increment the flag. */
939: else if (isupper(c)) {
940: upper++;
941: *ptr++ = c;
942: }
943:
944: /* Just store all other characters. */
945: else *ptr++ = c;
946: }
947:
948: /* Continue the above loop until a line terminator is found or */
949: /* until user name array is full. */
950:
951: #ifdef OSS
952: while (c != '\n' && c != '\r' && c != '/' && c != '!' &&
953: ptr < (user + MAXLINE));
954: #else
955: while (c != '\n' && c != '\r'
956: && ptr < (user + MAXLINE));
957: #endif
958:
959: /* Remove the last character from name. */
960: *--ptr = '\0';
961: if (ptr == user) return(NONAME);
962:
963: #ifdef OSS
964: /* If the line was terminated with one of the printing OSS line */
965: /* termination characters or is a <cr>, add a <newline>. */
966: if (c == '/' || c == '!') {
967: putc('\n',stdout);
968:
969: /* Set up the "standard OSS" erase, kill, etc. characters. */
970: termio->c_cc[VINTR] = STDABORT;
971: termio->c_cc[VERASE] = STDERASE;
972: termio->c_cc[VKILL] = STDKILL;
973: termio->c_cc[VEOL] = '/';
974: termio->c_cc[VEOL2] = '!';
975: } else
976: #endif
977: if (c == '\r') putc('\n',stdout);
978:
979: /* If the line terminated with a <lf>, put ICRNL and ONLCR into */
980: /* into the modes. */
981: if (c == '\r') {
982: termio->c_iflag |= ICRNL;
983: termio->c_oflag |= ONLCR;
984:
985: /* When line ends with a <lf>, then add the <cr>. */
986: } else putc('\r',stdout);
987:
988: /* Set the upper-lower case conversion switchs if only upper */
989: /* case characters were seen in the login and no lower case. */
990: /* Also convert all the upper case characters to lower case. */
991:
992: if (upper > 0 && lower == 0) {
993: termio->c_iflag |= IUCLC;
994: termio->c_oflag |= OLCUC;
995: termio->c_lflag |= XCASE;
996: for (ptr=user; *ptr; ptr++)
997: if (*ptr >= 'A' && *ptr <= 'Z' ) *ptr += ('a' - 'A');
998: }
999: return(GOODNAME);
1000: }
1001:
1002: /* "find_def" scans "/etc/gettydefs" for a string with the */
1003: /* requested "id". If the "id" is NULL, then the first entry is */
1004: /* taken, hence the first entry must be the default entry. */
1005: /* If a match for the "id" is found, then the line is parsed and */
1006: /* the Gdef structure filled. Errors in parsing generate error */
1007: /* messages on the system console. */
1008:
1009: struct Gdef *find_def(id)
1010: char *id;
1011: {
1012: register struct Gdef *gptr;
1013: register char *ptr,c;
1014: FILE *fp;
1015: int i,input,state,size,rawc,field;
1016: char oldc,*optr,quoted(),*gdfile;
1017: char line[MAXLINE+1];
1018: static struct Gdef def;
1019: extern struct Gdef DEFAULT;
1020: static char d_id[MAXIDLENGTH+1],d_nextid[MAXIDLENGTH+1];
1021: static char d_message[MAXMESSAGE+1];
1022: extern char *GETTY_DEFS;
1023: extern char *getword(),*fields(),*speed();
1024: extern int check;
1025: extern char *checkgdfile;
1026: static char *states[] = {
1027: "","id","initial flags","final flags","message","next id"
1028: };
1029:
1030: /* Decide whether to read the real /etc/gettydefs or the supplied */
1031: /* check file. */
1032: if (check) gdfile = checkgdfile;
1033: else gdfile = GETTY_DEFS;
1034:
1035: /* Open the "/etc/gettydefs" file. Be persistent. */
1036: for (i=0; i < 3;i++) {
1037: if ((fp = fopen(gdfile,"r")) != NULL) break;
1038: else sleep(3); /* Wait a little and then try again. */
1039: }
1040:
1041: /* If unable to open, complain and then use the built in default. */
1042: if (fp == NULL) {
1043: error("getty: can't open \"%s\".\n",gdfile);
1044: return(&DEFAULT);
1045: }
1046:
1047: /* Start searching for the line with the proper "id". */
1048: input = ACTIVE;
1049: do {
1050: for(ptr= line,oldc='\0'; ptr < &line[sizeof(line)] &&
1051: (rawc = getc(fp)) != EOF; ptr++,oldc = c) {
1052: c = *ptr = rawc;
1053:
1054: /* Search for two \n's in a row. */
1055: if (c == '\n' && oldc == '\n') break;
1056: }
1057:
1058: /* If we didn't end with a '\n' or EOF, then the line is too long. */
1059: /* Skip over the remainder of the stuff in the line so that we */
1060: /* start correctly on next line. */
1061: if (rawc != EOF && c != '\n') {
1062: for (oldc='\0'; (rawc = getc(fp)) != EOF;oldc=c) {
1063: c = rawc;
1064: if (c == '\n' && oldc != '\n') break;
1065: }
1066: if (check) fprintf(stdout,"Entry too long.\n");
1067: }
1068:
1069: /* If we ended at the end of the file, then if there is no */
1070: /* input, break out immediately otherwise set the "input" */
1071: /* flag to FINISHED so that the "do" loop will terminate. */
1072: if (rawc == EOF) {
1073: if (ptr == line) break;
1074: else input = FINISHED;
1075: }
1076:
1077: /* If the last character stored was an EOF or '\n', replace it */
1078: /* with a '\0'. */
1079: if (*ptr == (EOF & 0377) || *ptr == '\n') *ptr = '\0';
1080:
1081: /* If the buffer is full, then make sure there is a null after the */
1082: /* last character stored. */
1083: else *++ptr == '\0';
1084: if (check) fprintf(stdout,"\n**** Next Entry ****\n%s\n",line);
1085:
1086: /* If line starts with #, treat as comment */
1087: if(line[0] == '#') continue;
1088:
1089: /* Initialize "def" and "gptr". */
1090: gptr = &def;
1091: gptr->g_id = (char*)NULL;
1092: gptr->g_iflags.c_iflag = 0;
1093: gptr->g_iflags.c_oflag = 0;
1094: gptr->g_iflags.c_cflag = 0;
1095: gptr->g_iflags.c_lflag = 0;
1096: gptr->g_fflags.c_iflag = 0;
1097: gptr->g_fflags.c_oflag = 0;
1098: gptr->g_fflags.c_cflag = 0;
1099: gptr->g_fflags.c_lflag = 0;
1100: gptr->g_message = (char*)NULL;
1101: gptr->g_nextid = (char*)NULL;
1102:
1103: /* Now that we have the complete line, scan if for the various */
1104: /* fields. Advance to new field at each unquoted '#'. */
1105: for (state=ID,ptr= line; state != FAILURE && state != SUCCESS;) {
1106: switch(state) {
1107: case ID:
1108:
1109: /* Find word in ID field and move it to "d_id" array. */
1110: strncpy(d_id,getword(ptr,&size),MAXIDLENGTH);
1111: gptr->g_id = d_id;
1112:
1113: /* Move to the next field. If there is anything but white space */
1114: /* following the id up until the '#', then set state to FAILURE. */
1115: ptr += size;
1116: while (isspace(*ptr)) ptr++;
1117: if (*ptr != '#') {
1118: field = state;
1119: state = FAILURE;
1120: } else {
1121: ptr++; /* Skip the '#' */
1122: state = IFLAGS;
1123: }
1124: break;
1125:
1126: /* Extract the "g_iflags" */
1127: case IFLAGS:
1128: if ((ptr = fields(ptr,&gptr->g_iflags)) == NULL) {
1129: field = state;
1130: state = FAILURE;
1131: } else {
1132: gptr->g_iflags.c_iflag &= ICRNL;
1133: if((gptr->g_iflags.c_cflag & CSIZE) == 0)
1134: gptr->g_iflags.c_cflag |= CS8;
1135: gptr->g_iflags.c_cflag |= CREAD|HUPCL;
1136: gptr->g_iflags.c_lflag &= ~(ISIG|ICANON
1137: |XCASE|ECHOE|ECHOK);
1138: ptr++;
1139: state = FFLAGS;
1140: }
1141: break;
1142:
1143: /* Extract the "g_fflags". */
1144: case FFLAGS:
1145: if ((ptr = fields(ptr,&gptr->g_fflags)) == NULL) {
1146: field = state;
1147: state = FAILURE;
1148: } else {
1149:
1150: /* Force the CREAD mode in regardless of what the user specified. */
1151: gptr->g_fflags.c_cflag |= CREAD;
1152: ptr++;
1153: state = MESSAGE;
1154: }
1155: break;
1156:
1157: /* Take the entire next field as the "login" message. */
1158: /* Follow usual quoting procedures for control characters. */
1159: case MESSAGE:
1160: for (optr= d_message; (c = *ptr) != '\0'
1161: && c != '#';ptr++) {
1162:
1163: /* If the next character is a backslash, then get the quoted */
1164: /* character as one item. */
1165: if (c == '\\') {
1166: c = quoted(ptr,&size);
1167: /* -1 accounts for ++ that takes place later. */
1168: ptr += size - 1;
1169: }
1170:
1171: /* If there is room, store the next character in d_message. */
1172: if (optr < &d_message[MAXMESSAGE])
1173: *optr++ = c;
1174: }
1175:
1176: /* If we ended on a '#', then all is okay. Move state to NEXTID. */
1177: /* If we didn't, then set state to FAILURE. */
1178: if (c == '#') {
1179: gptr->g_message = d_message;
1180: state = NEXTID;
1181:
1182: /* Make sure message is null terminated. */
1183: *optr++ = '\0';
1184: ptr++;
1185: } else {
1186: field = state;
1187: state = FAILURE;
1188: }
1189: break;
1190:
1191: /* Finally get the "g_nextid" field. If this is successful, then */
1192: /* the line parsed okay. */
1193: case NEXTID:
1194:
1195: /* Find the first word in the field and save it as the next id. */
1196: strncpy(d_nextid,getword(ptr,&size),MAXIDLENGTH);
1197: gptr->g_nextid = d_nextid;
1198:
1199: /* There should be nothing else on the line. Starting after the */
1200: /* word found, scan to end of line. If anything beside white */
1201: /* space, set state to FAILURE. */
1202: ptr += size;
1203: while (isspace(*ptr)) ptr++;
1204: if (*ptr != '\0') {
1205: field = state;
1206: state = FAILURE;
1207: } else state = SUCCESS;
1208: break;
1209: }
1210: }
1211:
1212: /* If a line was successfully picked up and parsed, compare the */
1213: /* "g_id" field with the "id" we are looking for. */
1214: if (state == SUCCESS) {
1215:
1216: /* If there is an "id", compare them. */
1217: if (id != NULL) {
1218: if (strcmp(id,gptr->g_id) == 0) {
1219: fclose(fp);
1220: return(gptr);
1221: }
1222:
1223: /* If there is no "id", then return this first successfully */
1224: /* parsed line outright. */
1225: } else if (check == FALSE) {
1226: fclose(fp);
1227: return(gptr);
1228:
1229: /* In check mode print out the results of the parsing. */
1230: } else {
1231: fprintf(stdout,"id: %s\n",gptr->g_id);
1232: fprintf(stdout,"initial flags:\niflag- %o oflag- %o cflag- %o lflag- %o\n",
1233: gptr->g_iflags.c_iflag,
1234: gptr->g_iflags.c_oflag,
1235: gptr->g_iflags.c_cflag,
1236: gptr->g_iflags.c_lflag);
1237: fprintf(stdout,"final flags:\niflag- %o oflag- %o cflag- %o lflag- %o\n",
1238: gptr->g_fflags.c_iflag,
1239: gptr->g_fflags.c_oflag,
1240: gptr->g_fflags.c_cflag,
1241: gptr->g_fflags.c_lflag);
1242: fprintf(stdout,"message: %s\n",gptr->g_message);
1243: fprintf(stdout,"next id: %s\n",gptr->g_nextid);
1244: }
1245:
1246: /* If parsing failed in check mode, complain, otherwise ignore */
1247: /* the bad line. */
1248: } else if (check) {
1249: *++ptr = '\0';
1250: fprintf(stdout,"Parsing failure in the \"%s\" field\n\
1251: %s<--error detected here\n",
1252: states[field],line);
1253: }
1254: } while (input == ACTIVE);
1255:
1256: /* If no match was found, then return NULL. */
1257: fclose(fp);
1258: return(NULL);
1259: }
1260:
1261: char *getword(ptr,size)
1262: register char *ptr;
1263: int *size;
1264: {
1265: register char *optr,c;
1266: char quoted();
1267: static char word[MAXIDLENGTH+1];
1268: int qsize;
1269:
1270: /* Skip over all white spaces including quoted spaces and tabs. */
1271: for (*size=0; isspace(*ptr) || *ptr == '\\';) {
1272: if (*ptr == '\\') {
1273: c = quoted(ptr,&qsize);
1274: (*size) += qsize;
1275: ptr += qsize+1;
1276:
1277: /* If this quoted character is not a space or a tab or a newline */
1278: /* then break. */
1279: if (isspace(c) == 0) break;
1280: } else {
1281: (*size)++;
1282: ptr++;
1283: }
1284: }
1285:
1286: /* Put all characters from here to next white space or '#' or '\0' */
1287: /* into the word, up to the size of the word. */
1288: for (optr= word,*optr='\0'; isspace(*ptr) == 0 &&
1289: *ptr != '\0' && *ptr != '#'; ptr++,(*size)++) {
1290:
1291: /* If the character is quoted, analyze it. */
1292: if (*ptr == '\\') {
1293: c = quoted(ptr,&qsize);
1294: (*size) += qsize;
1295: ptr += qsize;
1296: } else c = *ptr;
1297:
1298: /* If there is room, add this character to the word. */
1299: if (optr < &word[MAXIDLENGTH+1] ) *optr++ = c;
1300: }
1301:
1302: /* Make sure the line is null terminated. */
1303: *optr++ = '\0';
1304: return(word);
1305: }
1306:
1307: /* "quoted" takes a quoted character, starting at the quote */
1308: /* character, and returns a single character plus the size of */
1309: /* the quote string. "quoted" recognizes the following as */
1310: /* special, \n,\r,\v,\t,\b,\f as well as the \nnn notation. */
1311:
1312: char quoted(ptr,qsize)
1313: char *ptr;
1314: int *qsize;
1315: {
1316: register char c,*rptr;
1317: register int i;
1318:
1319: rptr = ptr;
1320: switch(*++rptr) {
1321: case 'n':
1322: c = '\n';
1323: break;
1324: case 'r':
1325: c = '\r';
1326: break;
1327: case 'v':
1328: c = '\013';
1329: break;
1330: case 'b':
1331: c = '\b';
1332: break;
1333: case 't':
1334: c = '\t';
1335: break;
1336: case 'f':
1337: c = '\f';
1338: break;
1339: default:
1340:
1341: /* If this is a numeric string, take up to three characters of */
1342: /* it as the value of the quoted character. */
1343: if (*rptr >= '0' && *rptr <= '7') {
1344: for (i=0,c=0; i < 3;i++) {
1345: c = c*8 + (*rptr - '0');
1346: if (*++rptr < '0' || *rptr > '7') break;
1347: }
1348: rptr--;
1349:
1350: /* If the character following the '\\' is a NULL, back up the */
1351: /* ptr so that the NULL won't be missed. The sequence */
1352: /* backslash null is essentually illegal. */
1353: } else if (*rptr == '\0') {
1354: c = '\0';
1355: rptr--;
1356:
1357: /* In all other cases the quoting does nothing. */
1358: } else c = *rptr;
1359: break;
1360: }
1361:
1362: /* Compute the size of the quoted character. */
1363: (*qsize) = rptr - ptr + 1;
1364: return(c);
1365: }
1366:
1367: /* "fields" picks up the words in the next field and converts all */
1368: /* recognized words into the proper mask and puts it in the target */
1369: /* field. */
1370:
1371: char *fields(ptr,termio)
1372: register char *ptr;
1373: struct termio *termio;
1374: {
1375: extern struct Symbols imodes[],omodes[],cmodes[],lmodes[];
1376: extern struct Symbols *search();
1377: register struct Symbols *symbol;
1378: char *word,*getword();
1379: int size;
1380: extern int check;
1381:
1382: termio->c_iflag = 0;
1383: termio->c_oflag = 0;
1384: termio->c_cflag = 0;
1385: termio->c_lflag = 0;
1386: while (*ptr != '#' && *ptr != '\0') {
1387:
1388: /* Pick up the next word in the sequence. */
1389: word = getword(ptr,&size);
1390:
1391: /* If there is a word, scan the two mode tables for it. */
1392: if (*word != '\0') {
1393:
1394: /* If the word is the special word "SANE", put in all the flags */
1395: /* that are needed for SANE tty behavior. */
1396: if (strcmp(word,"SANE") == 0) {
1397: termio->c_iflag |= ISANE;
1398: termio->c_oflag |= OSANE;
1399: termio->c_cflag |= CSANE;
1400: termio->c_lflag |= LSANE;
1401: } else if ((symbol = search(word,imodes)) != NULL)
1402: termio->c_iflag |= symbol->s_value;
1403: else if ((symbol = search(word,omodes)) != NULL)
1404: termio->c_oflag |= symbol->s_value;
1405: else if ((symbol = search(word,cmodes)) != NULL)
1406: termio->c_cflag |= symbol->s_value;
1407: else if ((symbol = search(word,lmodes)) != NULL)
1408: termio->c_lflag |= symbol->s_value;
1409: else if (check) fprintf(stdout,"Undefined: %s\n",word);
1410: }
1411:
1412: /* Advance pointer to after the word. */
1413: ptr += size;
1414: }
1415:
1416: /* If we didn't end on a '#', return NULL, otherwise return the */
1417: /* updated pointer. */
1418: return(*ptr != '#' ? NULL : ptr);
1419: }
1420:
1421: /* "parse" breaks up the user's response into seperate arguments */
1422: /* and fills the supplied array with those arguments. Quoting */
1423: /* with the backspace is allowed. */
1424:
1425: parse(string,args,cnt)
1426: char *string,**args;
1427: int cnt;
1428: {
1429: register char *ptrin,*ptrout;
1430: register int i;
1431: extern char quoted();
1432: int qsize;
1433:
1434: for (i=0; i < cnt; i++) args[i] = (char *)NULL;
1435: for (ptrin = ptrout = string,i=0; *ptrin != '\0' && i < cnt; i++) {
1436:
1437: /* Skip excess white spaces between arguments. */
1438: while(*ptrin == ' ' || *ptrin == '\t') {
1439: ptrin++;
1440: ptrout++;
1441: }
1442:
1443: /* Save the address of the argument if there is something there. */
1444: if (*ptrin == '\0') break;
1445: else args[i] = ptrout;
1446:
1447: /* Span the argument itself. The '\' character causes quoting */
1448: /* of the next character to take place (except for '\0'). */
1449: while (*ptrin != '\0') {
1450:
1451: /* Is this the quote character? */
1452: if (*ptrin == '\\') {
1453: *ptrout++ = quoted(ptrin,&qsize);
1454: ptrin += qsize;
1455:
1456: /* Is this the end of the argument? If so quit loop. */
1457: } else if (*ptrin == ' ' || *ptrin == '\t') {
1458: ptrin++;
1459: break;
1460:
1461: /* If this is a normal letter of the argument, save it, advancing */
1462: /* the pointers at the same time. */
1463: } else *ptrout++ = *ptrin++;
1464: }
1465:
1466: /* Null terminate the string. */
1467: *ptrout++ = '\0';
1468: }
1469: }
1470:
1471: FILE *fdup(fp)
1472: register FILE *fp;
1473: {
1474: register int newfd;
1475: register char *mode;
1476:
1477: /* Dup the file descriptor for the specified stream and then */
1478: /* convert it to a stream pointer with the modes of the original */
1479: /* stream pointer. */
1480: if ((newfd = dup(fileno(fp))) != FAILURE) {
1481:
1482: /* Determine the proper mode. If the old file was _IORW, then */
1483: /* use the "r+" option, if _IOREAD, the "r" option, or if _IOWRT */
1484: /* the "w" option. Note that since none of these force an lseek */
1485: /* by "fdopen", the dupped file pointer will be at the same spot */
1486: /* as the original. */
1487: if (fp->_flag & _IORW) mode = "r+";
1488: else if (fp->_flag & _IOREAD) mode = "r";
1489: else if (fp->_flag & _IOWRT) mode = "w";
1490:
1491: /* Something is wrong, close dupped descriptor and return NULL. */
1492: else {
1493: close(newfd);
1494: return(NULL);
1495: }
1496:
1497: /* Now have fdopen finish the job of establishing a new file pointer. */
1498: return(fdopen(newfd,mode));
1499: } else return(NULL);
1500: }
1501:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.