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(char *buf, int len) 464 { 465 char *prev = _uu_setlocale(LC_ALL, "C"); 466 467 if (Systems[0] == NULL) 468 /* not initialized via setservice() - use default */ 469 setservice("uucico"); 470 471 /* initialize devices and dialers whenever a new line is read */ 472 /* from systems */ 473 devreset(); 474 if (fsystems == NULL) 475 if (nextsystems() == FALSE) { 476 (void) _uu_resetlocale(LC_ALL, prev); 477 return(FALSE); 478 } 479 480 ASSERT(len >= BUFSIZ, "BUFFER TOO SMALL", "getsysline", 0); 481 for(;;) { 482 while (getaline(fsystems, buf) != 0) 483 if ((*buf != '#') && (*buf != ' ') && 484 (*buf != '\t') && (*buf != '\n')) { 485 (void) _uu_resetlocale(LC_ALL, prev); 486 return(TRUE); 487 } 488 if (nextsystems() == FALSE) { 489 (void) _uu_resetlocale(LC_ALL, prev); 490 return(FALSE); 491 } 492 } 493 } 494 495 /* 496 * move to next systems file. return TRUE if successful, FALSE if not 497 */ 498 static int 499 nextsystems() 500 { 501 devreset(); 502 503 if (fsystems != NULL) { 504 (void) fclose(fsystems); 505 nsystems++; 506 } else { 507 nsystems = 0; 508 } 509 for ( ; Systems[nsystems] != NULL; nsystems++) 510 if ((fsystems = fopen(Systems[nsystems], "r")) != NULL) 511 return(TRUE); 512 return(FALSE); 513 } 514 515 /* 516 * get next line from Devices file 517 * return TRUE if successful, FALSE if not 518 */ 519 GLOBAL int 520 getdevline(char *buf, int len) 521 { 522 char *prev = _uu_setlocale(LC_ALL, "C"); 523 524 if (Devices[0] == NULL) 525 /* not initialized via setservice() - use default */ 526 setservice("uucico"); 527 528 if (fdevices == NULL) 529 if (nextdevices() == FALSE) { 530 (void) _uu_resetlocale(LC_ALL, prev); 531 return(FALSE); 532 } 533 for(;;) { 534 if (fgets(buf, len, fdevices) != NULL) { 535 (void) _uu_resetlocale(LC_ALL, prev); 536 return(TRUE); 537 } 538 if (nextdevices() == FALSE) { 539 (void) _uu_resetlocale(LC_ALL, prev); 540 return(FALSE); 541 } 542 } 543 } 544 545 /* 546 * move to next devices file. return TRUE if successful, FALSE if not 547 */ 548 static int 549 nextdevices() 550 { 551 if (fdevices != NULL) { 552 (void) fclose(fdevices); 553 ndevices++; 554 } else { 555 ndevices = 0; 556 } 557 for ( ; Devices[ndevices] != NULL; ndevices++) 558 if ((fdevices = fopen(Devices[ndevices], "r")) != NULL) 559 return(TRUE); 560 return(FALSE); 561 } 562 563 564 /* 565 * get next line from Dialers file 566 * return TRUE if successful, FALSE if not 567 */ 568 569 GLOBAL int 570 getdialline(char *buf, int len) 571 { 572 char *prev = _uu_setlocale(LC_ALL, "C"); 573 574 if (Dialers[0] == NULL) 575 /* not initialized via setservice() - use default */ 576 setservice("uucico"); 577 578 if (fdialers == NULL) 579 if (nextdialers() == FALSE) { 580 (void) _uu_resetlocale(LC_ALL, prev); 581 return(FALSE); 582 } 583 for(;;) { 584 if (fgets(buf, len, fdialers) != NULL) { 585 (void) _uu_resetlocale(LC_ALL, prev); 586 return(TRUE); 587 } 588 if (nextdialers() == FALSE) { 589 (void) _uu_resetlocale(LC_ALL, prev); 590 return(FALSE); 591 } 592 } 593 } 594 595 /* 596 * move to next dialers file. return TRUE if successful, FALSE if not 597 */ 598 static int 599 nextdialers() 600 { 601 if (fdialers) { 602 (void) fclose(fdialers); 603 ndialers++; 604 } else { 605 ndialers = 0; 606 } 607 608 for ( ; Dialers[ndialers] != NULL; ndialers++) 609 if ((fdialers = fopen(Dialers[ndialers], "r")) != NULL) 610 return(TRUE); 611 return(FALSE); 612 } 613 614 /* 615 * get next module to be popped 616 * return TRUE if successful, FALSE if not 617 */ 618 static int 619 getpop(buf, len, optional) 620 char *buf; 621 int len, *optional; 622 { 623 int slen; 624 625 if ( Pops[0] == NULL || Pops[npops] == NULL ) 626 return(FALSE); 627 628 /* if the module name is enclosed in parentheses, */ 629 /* is optional. set flag & strip parens */ 630 slen = strlen(Pops[npops]) - 1; 631 if ( Pops[npops][0] == '(' && Pops[npops][slen] == ')' ) { 632 *optional = 1; 633 len = ( slen < len ? slen : len ); 634 strncpy(buf, &(Pops[npops++][1]), len); 635 } else { 636 *optional = 0; 637 strncpy(buf, Pops[npops++], len); 638 } 639 buf[len-1] = '\0'; 640 return(TRUE); 641 } 642 643 /* 644 * get next module to be pushed 645 * return TRUE if successful, FALSE if not 646 */ 647 static int 648 getpush(buf, len) 649 char *buf; 650 int len; 651 { 652 if ( Pushes[0] == NULL || Pushes[npushes] == NULL ) 653 return(FALSE); 654 strncpy(buf, Pushes[npushes++], len); 655 return(TRUE); 656 } 657 658 /* 659 * pop/push requested modules 660 * return TRUE if successful, FALSE if not 661 */ 662 GLOBAL int 663 pop_push(fd) 664 int fd; 665 { 666 char strmod[FMNAMESZ], onstream[FMNAMESZ]; 667 int optional; 668 char *prev = _uu_setlocale(LC_ALL, "C"); 669 670 /* check for streams modules to pop */ 671 while ( getpop(strmod, sizeof(strmod), &optional) ) { 672 DEBUG(5, (optional ? "pop_push: optionally POPing %s\n" 673 : "pop_push: POPing %s\n" ), strmod); 674 if ( ioctl(fd, I_LOOK, onstream) == -1 ) { 675 DEBUG(5, "pop_push: I_LOOK on fd %d failed ", fd); 676 DEBUG(5, "errno %d\n", errno); 677 (void) _uu_resetlocale(LC_ALL, prev); 678 return(FALSE); 679 } 680 if ( strcmp(strmod, onstream) != SAME ) { 681 if ( optional ) 682 continue; 683 DEBUG(5, "pop_push: I_POP: %s not there\n", strmod); 684 (void) _uu_resetlocale(LC_ALL, prev); 685 return(FALSE); 686 } 687 if ( ioctl(fd, I_POP, 0) == -1 ) { 688 DEBUG(5, "pop_push: I_POP on fd %d failed ", fd); 689 DEBUG(5, "errno %d\n", errno); 690 (void) _uu_resetlocale(LC_ALL, prev); 691 return(FALSE); 692 } 693 } 694 695 /* check for streams modules to push */ 696 while ( getpush(strmod, sizeof(strmod)) ) { 697 DEBUG(5, "pop_push: PUSHing %s\n", strmod); 698 if ( ioctl(fd, I_PUSH, strmod) == -1 ) { 699 DEBUG(5, "pop_push: I_PUSH on fd %d failed ", fd); 700 DEBUG(5, "errno %d\n", errno); 701 (void) _uu_resetlocale(LC_ALL, prev); 702 return(FALSE); 703 } 704 } 705 (void) _uu_resetlocale(LC_ALL, prev); 706 return(TRUE); 707 } 708 709 /* 710 * return name of currently open Systems file 711 */ 712 GLOBAL char * 713 currsys() 714 { 715 return(Systems[nsystems]); 716 } 717 718 /* 719 * return name of currently open Devices file 720 */ 721 GLOBAL char * 722 currdev() 723 { 724 return(Devices[ndevices]); 725 } 726 727 /* 728 * return name of currently open Dialers file 729 */ 730 GLOBAL char * 731 currdial() 732 { 733 return(Dialers[ndialers]); 734 } 735 736 /* 737 * set configuration parameters provided in Config file 738 */ 739 static void 740 setconfig() 741 { 742 FILE *f; 743 char buf[BUFSIZ]; 744 char *tok; 745 extern char _ProtoCfg[]; 746 747 if ((f = fopen(CONFIG, "r")) != 0) { 748 while (getaline(f, buf) > 0) { 749 /* got a (logical) line from Config file */ 750 tok = strtok(buf, " \t"); 751 if ( (tok != NULL) && (*tok != '#') ) { 752 /* got a token */ 753 754 /* this probably should be table driven when 755 * the list of configurable parameters grows. 756 */ 757 if (strncmp("Protocol=", tok, strlen("Protocol=")) == SAME) { 758 tok += strlen("Protocol="); 759 if ( *tok != '\0' ) { 760 if ( _ProtoCfg[0] != '\0' ) { 761 DEBUG(7, "Protocol string %s ", tok); 762 DEBUG(7, "overrides %s\n", _ProtoCfg); 763 } 764 strcpy(_ProtoCfg, tok); 765 } 766 } else { 767 DEBUG(7, "Unknown configuration parameter %s\n", tok); 768 } 769 } 770 } 771 } 772 } 773