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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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) != 0) 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 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 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 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 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 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 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 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 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 * 716 currsys() 717 { 718 return(Systems[nsystems]); 719 } 720 721 /* 722 * return name of currently open Devices file 723 */ 724 GLOBAL char * 725 currdev() 726 { 727 return(Devices[ndevices]); 728 } 729 730 /* 731 * return name of currently open Dialers file 732 */ 733 GLOBAL char * 734 currdial() 735 { 736 return(Dialers[ndialers]); 737 } 738 739 /* 740 * set configuration parameters provided in Config file 741 */ 742 static void 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