1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28
29 #include "uucp.h"
30
31 #include <unistd.h>
32 #include "sysfiles.h"
33 #include <sys/stropts.h>
34
35 /*
36 * manage systems files (Systems, Devices, and Dialcodes families).
37 *
38 * also manage new file Devconfig, allows per-device setup.
39 * present use is to specify what streams modules to push/pop for
40 * AT&T TLI/streams network.
41 *
42 * TODO:
43 * call bsfix()?
44 * combine the 3 versions of everything (sys, dev, and dial) into one.
45 * allow arbitrary classes of service.
46 * need verifysys() for uucheck.
47 * nameserver interface?
48 * pass sysname (or 0) to getsysline(). (might want reg. exp. or NS processing
49 */
50
51 /* private variables */
52 static void tokenize(), nameparse(), setfile(), setioctl(),
53 scansys(), scancfg(), setconfig();
54 static int namematch(), nextdialers(), nextdevices(), nextsystems(), getaline();
55
56 /* pointer arrays might be dynamically allocated */
57 static char *Systems[64] = {0}; /* list of Systems files */
58 static char *Devices[64] = {0}; /* list of Devices files */
59 static char *Dialers[64] = {0}; /* list of Dialers files */
60 static char *Pops[64] = {0}; /* list of STREAMS modules to be popped */
61 static char *Pushes[64] = {0}; /* list of STREAMS modules to be pushed */
62
63 static int nsystems; /* index into list of Systems files */
64 static int ndevices; /* index into list of Devices files */
65 static int ndialers; /* index into list of Dialers files */
66 static int npops; /* index into list of STREAMS modules */
67 /*to be popped */
68 static int npushes; /* index into list of STREAMS modules */
69 /*to be pushed */
70
71 GLOBAL unsigned connecttime = CONNECTTIME;
72 GLOBAL unsigned expecttime = EXPECTTIME;
73 GLOBAL unsigned msgtime = MSGTIME;
74
75 static FILE *fsystems;
76 static FILE *fdevices;
77 static FILE *fdialers;
78
79 static char errformat[BUFSIZ];
80
81 /* this might be dynamically allocated */
82 #define NTOKENS 16
83 static char *tokens[NTOKENS], **tokptr;
84
85 /* export these */
86 EXTERN void sysreset(), devreset(), dialreset(), setdevcfg(), setservice();
87 EXTERN char *strsave();
88
89 /* import these */
90 extern char *strcpy(), *strtok(), *strchr(), *strsave();
91 EXTERN int eaccess();
92
93 /*
94 * setservice init's Systems, Devices, Dialers lists from Sysfiles
95 */
96 GLOBAL void
setservice(service)97 setservice(service)
98 char *service;
99 {
100 char *prev = _uu_setlocale(LC_ALL, "C");
101
102 setconfig();
103 scansys(service);
104 (void) _uu_resetlocale(LC_ALL, prev);
105 return;
106 }
107
108 /*
109 * setdevcfg init's Pops, Pushes lists from Devconfig
110 */
111
112 GLOBAL void
setdevcfg(service,device)113 setdevcfg(service, device)
114 char *service, *device;
115 {
116 char *prev = _uu_setlocale(LC_ALL, "C");
117
118 scancfg(service, device);
119 (void) _uu_resetlocale(LC_ALL, prev);
120 return;
121 }
122
123 /* administrative files access */
124 GLOBAL int
sysaccess(type)125 sysaccess(type)
126 int type;
127 {
128 switch (type) {
129
130 case ACCESS_SYSTEMS:
131 return(access(Systems[nsystems], R_OK));
132 case ACCESS_DEVICES:
133 return(access(Devices[ndevices], R_OK));
134 case ACCESS_DIALERS:
135 return(access(Dialers[ndialers], R_OK));
136 case EACCESS_SYSTEMS:
137 return(eaccess(Systems[nsystems], R_OK));
138 case EACCESS_DEVICES:
139 return(eaccess(Devices[ndevices], R_OK));
140 case EACCESS_DIALERS:
141 return(eaccess(Dialers[ndialers], R_OK));
142 default:
143 (void)sprintf(errformat, "bad access type %d", type);
144 logent(errformat, "sysaccess");
145 return(FAIL);
146 }
147 }
148
149
150 /*
151 * read Sysfiles, set up lists of Systems/Devices/Dialers file names.
152 * allow multiple entries for a given service, allow a service
153 * type to describe resources more than once, e.g., systems=foo:baz systems=bar.
154 */
155 static void
scansys(service)156 scansys(service)
157 char *service;
158 { FILE *f;
159 char *tok, buf[BUFSIZ];
160
161 Systems[0] = Devices[0] = Dialers[0] = NULL;
162 if ((f = fopen(SYSFILES, "r")) != 0) {
163 while (getaline(f, buf) > 0) {
164 /* got a (logical) line from Sysfiles */
165 /* strtok's of this buf continue in tokenize() */
166 tok = strtok(buf, " \t");
167 if (namematch("service=", tok, service)) {
168 tokenize();
169 nameparse();
170 }
171 }
172 (void) fclose(f);
173 }
174
175 /* if didn't find entries in Sysfiles, use defaults */
176 if (Systems[0] == NULL) {
177 Systems[0] = strsave(SYSTEMS);
178 ASSERT(Systems[0] != NULL, Ct_ALLOCATE, "scansys: Systems", 0);
179 Systems[1] = NULL;
180 }
181 if (Devices[0] == NULL) {
182 Devices[0] = strsave(DEVICES);
183 ASSERT(Devices[0] != NULL, Ct_ALLOCATE, "scansys: Devices", 0);
184 Devices[1] = NULL;
185 }
186 if (Dialers[0] == NULL) {
187 Dialers[0] = strsave(DIALERS);
188 ASSERT(Dialers[0] != NULL, Ct_ALLOCATE, "scansys: Dialers", 0);
189 Dialers[1] = NULL;
190 }
191 return;
192 }
193
194
195 /*
196 * read Devconfig. allow multiple entries for a given service, allow a service
197 * type to describe resources more than once, e.g., push=foo:baz push=bar.
198 */
199 static void
scancfg(service,device)200 scancfg(service, device)
201 char *service, *device;
202 { FILE *f;
203 char *tok, buf[BUFSIZ];
204
205 /* (re)initialize device-specific information */
206
207 npops = npushes = 0;
208 Pops[0] = Pushes[0] = NULL;
209 connecttime = CONNECTTIME;
210 expecttime = EXPECTTIME;
211 msgtime = MSGTIME;
212
213 if ((f = fopen(DEVCONFIG, "r")) != 0) {
214 while (getaline(f, buf) > 0) {
215 /* got a (logical) line from Devconfig */
216 /* strtok's of this buf continue in tokenize() */
217 tok = strtok(buf, " \t");
218 if (namematch("service=", tok, service)) {
219 tok = strtok((char *)0, " \t");
220 if ( namematch("device=", tok, device)) {
221 tokenize();
222 nameparse();
223 }
224 }
225 }
226 (void) fclose(f);
227 }
228
229 return;
230
231 }
232
233 /*
234 * given a file pointer and buffer, construct logical line in buffer
235 * (i.e., concatenate lines ending in '\'). return length of line
236 * ASSUMES that buffer is BUFSIZ long!
237 */
238
239 static int
getaline(f,line)240 getaline(f, line)
241 FILE *f;
242 char *line;
243 { char *lptr, *lend;
244
245 lptr = line;
246 while (fgets(lptr, (line + BUFSIZ) - lptr, f) != NULL) {
247 lend = lptr + strlen(lptr);
248 if (lend == lptr || lend[-1] != '\n')
249 /* empty buf or line too long! */
250 break;
251 *--lend = '\0'; /* lop off ending '\n' */
252 if ( lend == line ) /* empty line - ignore */
253 continue;
254 lptr = lend;
255 if (lend[-1] != '\\')
256 break;
257 /* continuation */
258 lend[-1] = ' ';
259 }
260 return(lptr - line);
261 }
262
263 /*
264 * given a label (e.g., "service=", "device="), a name ("cu", "uucico"),
265 * and a line: if line begins with the label and if the name appears
266 * in a colon-separated list of names following the label, return true;
267 * else return false
268 */
269 static int
namematch(label,line,name)270 namematch(label, line, name)
271 char *label, *line, *name;
272 { char *lend;
273
274 if (strncmp(label, line, strlen(label)) != SAME) {
275 return(FALSE); /* probably a comment line */
276 }
277 line += strlen(label);
278 if (*line == '\0')
279 return(FALSE);
280 /*
281 * can't use strtok() in the following because scansys(),
282 * scancfg() do an initializing call to strtok() before
283 * coming here and then CONTINUE calling strtok() in tokenize(),
284 * after returning from namematch().
285 */
286 while ((lend = strchr(line, ':')) != NULL) {
287 *lend = '\0';
288 if (strcmp(line, name) == SAME)
289 return(TRUE);
290 line = lend+1;
291 }
292 return(strcmp(line, name) == SAME);
293 }
294
295 /*
296 * tokenize() continues pulling tokens out of a buffer -- the
297 * initializing call to strtok must have been made before calling
298 * tokenize() -- and starts stuffing 'em into tokptr.
299 */
300 static void
tokenize()301 tokenize()
302 { char *tok;
303
304 tokptr = tokens;
305 while ((tok = strtok((char *) NULL, " \t")) != NULL) {
306 *tokptr++ = tok;
307 if (tokptr - tokens >= NTOKENS)
308 break;
309 }
310 *tokptr = NULL;
311 return;
312 }
313
314 /*
315 * look at top token in array: should be line of the form
316 * name=item1:item2:item3...
317 * if name is one we recognize, then call set[file|ioctl] to set up
318 * corresponding list. otherwise, log bad name.
319 */
320 static void
nameparse()321 nameparse()
322 { char **line, *equals;
323 int temp;
324
325 #define setuint(a,b,c) a = ( ((temp = atoi(b)) <= 0) ? (c) : temp )
326
327 for (line = tokens; (line - tokens) < NTOKENS && *line; line++) {
328 equals = strchr(*line, '=');
329 if (equals == NULL)
330 continue; /* may be meaningful someday? */
331 *equals = '\0';
332 /* ignore entry with empty rhs */
333 if (*++equals == '\0')
334 continue;
335 if (strcmp(*line, "systems") == SAME)
336 setfile(Systems, equals);
337 else if (strcmp(*line, "devices") == SAME)
338 setfile(Devices, equals);
339 else if (strcmp(*line, "dialers") == SAME)
340 setfile(Dialers, equals);
341 else if (strcmp(*line, "pop") == SAME)
342 setioctl(Pops, equals);
343 else if (strcmp(*line, "push") == SAME)
344 setioctl(Pushes, equals);
345 else if (strcmp(*line, "connecttime") == SAME)
346 setuint(connecttime, equals, CONNECTTIME);
347 else if (strcmp(*line, "expecttime") == SAME)
348 setuint(expecttime, equals, EXPECTTIME);
349 else if (strcmp(*line, "msgtime") == SAME)
350 setuint(msgtime, equals, MSGTIME);
351 else {
352 (void)sprintf(errformat,"unrecognized label %s",*line);
353 logent(errformat, "Sysfiles|Devconfig");
354 }
355 }
356 return;
357 }
358
359 /*
360 * given the list for a particular type (systems, devices,...)
361 * and a line of colon-separated files, add 'em to list
362 */
363
364 static void
setfile(type,line)365 setfile(type, line)
366 char **type, *line;
367 { char **tptr, *tok;
368 char expandpath[BUFSIZ];
369
370 if (*line == 0)
371 return;
372 tptr = type;
373 while (*tptr) /* skip over existing entries to*/
374 tptr++; /* concatenate multiple entries */
375
376 for (tok = strtok(line, ":"); tok != NULL;
377 tok = strtok((char *) NULL, ":")) {
378 expandpath[0] = '\0';
379 if ( *tok != '/' )
380 /* by default, file names are relative to SYSDIR */
381 sprintf(expandpath, "%s/", SYSDIR);
382 strcat(expandpath, tok);
383 if (eaccess(expandpath, R_OK) != 0)
384 /* if we can't read it, no point in adding to list */
385 continue;
386 *tptr = strsave(expandpath);
387 ASSERT(*tptr != NULL, Ct_ALLOCATE, "setfile: tptr", 0);
388 tptr++;
389 }
390 return;
391 }
392
393 /*
394 * given the list for a particular ioctl (push, pop)
395 * and a line of colon-separated modules, add 'em to list
396 */
397
398 static void
setioctl(type,line)399 setioctl(type, line)
400 char **type, *line;
401 { char **tptr, *tok;
402
403 if (*line == 0)
404 return;
405 tptr = type;
406 while (*tptr) /* skip over existing entries to*/
407 tptr++; /* concatenate multiple entries */
408 for (tok = strtok(line, ":"); tok != NULL;
409 tok = strtok((char *) NULL, ":")) {
410 *tptr = strsave(tok);
411 ASSERT(*tptr != NULL, Ct_ALLOCATE, "setioctl: tptr", 0);
412 tptr++;
413 }
414 return;
415 }
416
417 /*
418 * reset Systems files
419 */
420 GLOBAL void
sysreset()421 sysreset()
422 {
423 if (fsystems)
424 fclose(fsystems);
425 fsystems = NULL;
426 nsystems = 0;
427 devreset();
428 return;
429 }
430
431 /*
432 * reset Devices files
433 */
434 GLOBAL void
devreset()435 devreset()
436 {
437 if (fdevices)
438 fclose(fdevices);
439 fdevices = NULL;
440 ndevices = 0;
441 dialreset();
442 return;
443 }
444
445 /*
446 * reset Dialers files
447 */
448 GLOBAL void
dialreset()449 dialreset()
450 {
451 if (fdialers)
452 fclose(fdialers);
453 fdialers = NULL;
454 ndialers = 0;
455 return;
456 }
457
458 /*
459 * get next line from Systems file
460 * return TRUE if successful, FALSE if not
461 */
462 GLOBAL int
getsysline(buf,len)463 getsysline(buf, len)
464 char *buf;
465 {
466 char *prev = _uu_setlocale(LC_ALL, "C");
467
468 if (Systems[0] == NULL)
469 /* not initialized via setservice() - use default */
470 setservice("uucico");
471
472 /* initialize devices and dialers whenever a new line is read */
473 /* from systems */
474 devreset();
475 if (fsystems == NULL)
476 if (nextsystems() == FALSE) {
477 (void) _uu_resetlocale(LC_ALL, prev);
478 return(FALSE);
479 }
480
481 ASSERT(len >= BUFSIZ, "BUFFER TOO SMALL", "getsysline", 0);
482 for(;;) {
483 while (getaline(fsystems, buf) != NULL)
484 if ((*buf != '#') && (*buf != ' ') &&
485 (*buf != '\t') && (*buf != '\n')) {
486 (void) _uu_resetlocale(LC_ALL, prev);
487 return(TRUE);
488 }
489 if (nextsystems() == FALSE) {
490 (void) _uu_resetlocale(LC_ALL, prev);
491 return(FALSE);
492 }
493 }
494 }
495
496 /*
497 * move to next systems file. return TRUE if successful, FALSE if not
498 */
499 static int
nextsystems()500 nextsystems()
501 {
502 devreset();
503
504 if (fsystems != NULL) {
505 (void) fclose(fsystems);
506 nsystems++;
507 } else {
508 nsystems = 0;
509 }
510 for ( ; Systems[nsystems] != NULL; nsystems++)
511 if ((fsystems = fopen(Systems[nsystems], "r")) != NULL)
512 return(TRUE);
513 return(FALSE);
514 }
515
516 /*
517 * get next line from Devices file
518 * return TRUE if successful, FALSE if not
519 */
520 GLOBAL int
getdevline(buf,len)521 getdevline(buf, len)
522 char *buf;
523 {
524 char *prev = _uu_setlocale(LC_ALL, "C");
525
526 if (Devices[0] == NULL)
527 /* not initialized via setservice() - use default */
528 setservice("uucico");
529
530 if (fdevices == NULL)
531 if (nextdevices() == FALSE) {
532 (void) _uu_resetlocale(LC_ALL, prev);
533 return(FALSE);
534 }
535 for(;;) {
536 if (fgets(buf, len, fdevices) != NULL) {
537 (void) _uu_resetlocale(LC_ALL, prev);
538 return(TRUE);
539 }
540 if (nextdevices() == FALSE) {
541 (void) _uu_resetlocale(LC_ALL, prev);
542 return(FALSE);
543 }
544 }
545 }
546
547 /*
548 * move to next devices file. return TRUE if successful, FALSE if not
549 */
550 static int
nextdevices()551 nextdevices()
552 {
553 if (fdevices != NULL) {
554 (void) fclose(fdevices);
555 ndevices++;
556 } else {
557 ndevices = 0;
558 }
559 for ( ; Devices[ndevices] != NULL; ndevices++)
560 if ((fdevices = fopen(Devices[ndevices], "r")) != NULL)
561 return(TRUE);
562 return(FALSE);
563 }
564
565
566 /*
567 * get next line from Dialers file
568 * return TRUE if successful, FALSE if not
569 */
570
571 GLOBAL int
getdialline(buf,len)572 getdialline(buf, len)
573 char *buf;
574 {
575 char *prev = _uu_setlocale(LC_ALL, "C");
576
577 if (Dialers[0] == NULL)
578 /* not initialized via setservice() - use default */
579 setservice("uucico");
580
581 if (fdialers == NULL)
582 if (nextdialers() == FALSE) {
583 (void) _uu_resetlocale(LC_ALL, prev);
584 return(FALSE);
585 }
586 for(;;) {
587 if (fgets(buf, len, fdialers) != NULL) {
588 (void) _uu_resetlocale(LC_ALL, prev);
589 return(TRUE);
590 }
591 if (nextdialers() == FALSE) {
592 (void) _uu_resetlocale(LC_ALL, prev);
593 return(FALSE);
594 }
595 }
596 }
597
598 /*
599 * move to next dialers file. return TRUE if successful, FALSE if not
600 */
601 static int
nextdialers()602 nextdialers()
603 {
604 if (fdialers) {
605 (void) fclose(fdialers);
606 ndialers++;
607 } else {
608 ndialers = 0;
609 }
610
611 for ( ; Dialers[ndialers] != NULL; ndialers++)
612 if ((fdialers = fopen(Dialers[ndialers], "r")) != NULL)
613 return(TRUE);
614 return(FALSE);
615 }
616
617 /*
618 * get next module to be popped
619 * return TRUE if successful, FALSE if not
620 */
621 static int
getpop(buf,len,optional)622 getpop(buf, len, optional)
623 char *buf;
624 int len, *optional;
625 {
626 int slen;
627
628 if ( Pops[0] == NULL || Pops[npops] == NULL )
629 return(FALSE);
630
631 /* if the module name is enclosed in parentheses, */
632 /* is optional. set flag & strip parens */
633 slen = strlen(Pops[npops]) - 1;
634 if ( Pops[npops][0] == '(' && Pops[npops][slen] == ')' ) {
635 *optional = 1;
636 len = ( slen < len ? slen : len );
637 strncpy(buf, &(Pops[npops++][1]), len);
638 } else {
639 *optional = 0;
640 strncpy(buf, Pops[npops++], len);
641 }
642 buf[len-1] = '\0';
643 return(TRUE);
644 }
645
646 /*
647 * get next module to be pushed
648 * return TRUE if successful, FALSE if not
649 */
650 static int
getpush(buf,len)651 getpush(buf, len)
652 char *buf;
653 int len;
654 {
655 if ( Pushes[0] == NULL || Pushes[npushes] == NULL )
656 return(FALSE);
657 strncpy(buf, Pushes[npushes++], len);
658 return(TRUE);
659 }
660
661 /*
662 * pop/push requested modules
663 * return TRUE if successful, FALSE if not
664 */
665 GLOBAL int
pop_push(fd)666 pop_push(fd)
667 int fd;
668 {
669 char strmod[FMNAMESZ], onstream[FMNAMESZ];
670 int optional;
671 char *prev = _uu_setlocale(LC_ALL, "C");
672
673 /* check for streams modules to pop */
674 while ( getpop(strmod, sizeof(strmod), &optional) ) {
675 DEBUG(5, (optional ? "pop_push: optionally POPing %s\n"
676 : "pop_push: POPing %s\n" ), strmod);
677 if ( ioctl(fd, I_LOOK, onstream) == -1 ) {
678 DEBUG(5, "pop_push: I_LOOK on fd %d failed ", fd);
679 DEBUG(5, "errno %d\n", errno);
680 (void) _uu_resetlocale(LC_ALL, prev);
681 return(FALSE);
682 }
683 if ( strcmp(strmod, onstream) != SAME ) {
684 if ( optional )
685 continue;
686 DEBUG(5, "pop_push: I_POP: %s not there\n", strmod);
687 (void) _uu_resetlocale(LC_ALL, prev);
688 return(FALSE);
689 }
690 if ( ioctl(fd, I_POP, 0) == -1 ) {
691 DEBUG(5, "pop_push: I_POP on fd %d failed ", fd);
692 DEBUG(5, "errno %d\n", errno);
693 (void) _uu_resetlocale(LC_ALL, prev);
694 return(FALSE);
695 }
696 }
697
698 /* check for streams modules to push */
699 while ( getpush(strmod, sizeof(strmod)) ) {
700 DEBUG(5, "pop_push: PUSHing %s\n", strmod);
701 if ( ioctl(fd, I_PUSH, strmod) == -1 ) {
702 DEBUG(5, "pop_push: I_PUSH on fd %d failed ", fd);
703 DEBUG(5, "errno %d\n", errno);
704 (void) _uu_resetlocale(LC_ALL, prev);
705 return(FALSE);
706 }
707 }
708 (void) _uu_resetlocale(LC_ALL, prev);
709 return(TRUE);
710 }
711
712 /*
713 * return name of currently open Systems file
714 */
715 GLOBAL char *
currsys()716 currsys()
717 {
718 return(Systems[nsystems]);
719 }
720
721 /*
722 * return name of currently open Devices file
723 */
724 GLOBAL char *
currdev()725 currdev()
726 {
727 return(Devices[ndevices]);
728 }
729
730 /*
731 * return name of currently open Dialers file
732 */
733 GLOBAL char *
currdial()734 currdial()
735 {
736 return(Dialers[ndialers]);
737 }
738
739 /*
740 * set configuration parameters provided in Config file
741 */
742 static void
setconfig()743 setconfig()
744 {
745 FILE *f;
746 char buf[BUFSIZ];
747 char *tok;
748 extern char _ProtoCfg[];
749
750 if ((f = fopen(CONFIG, "r")) != 0) {
751 while (getaline(f, buf) > 0) {
752 /* got a (logical) line from Config file */
753 tok = strtok(buf, " \t");
754 if ( (tok != NULL) && (*tok != '#') ) {
755 /* got a token */
756
757 /* this probably should be table driven when
758 * the list of configurable parameters grows.
759 */
760 if (strncmp("Protocol=", tok, strlen("Protocol=")) == SAME) {
761 tok += strlen("Protocol=");
762 if ( *tok != '\0' ) {
763 if ( _ProtoCfg[0] != '\0' ) {
764 DEBUG(7, "Protocol string %s ", tok);
765 DEBUG(7, "overrides %s\n", _ProtoCfg);
766 }
767 strcpy(_ProtoCfg, tok);
768 }
769 } else {
770 DEBUG(7, "Unknown configuration parameter %s\n", tok);
771 }
772 }
773 }
774 }
775 }
776