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