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