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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 23 /* All Rights Reserved */ 24 25 26 /* 27 * Copyright (c) 1997,1998,2002 by Sun Microsystems, Inc. 28 * All rights reserved. 29 */ 30 31 /*LINTLIBRARY*/ 32 33 /* 34 * dgrpent.c 35 * 36 * Contains functions that deal with the device-group table and are not for 37 * consumption by the general user population. 38 * 39 * Functions defined: 40 * _opendgrptab() Opens the device-group table for commands 41 * _setdgrptab() Rewinds the open device table 42 * _enddgrptab() Closes the open device table 43 * _getdgrptabent() Gets the next entry in the device table 44 * _freedgrptabent() Frees memory allocated to a device-table entry 45 * _getdgrprec() Gets a specific record from the device table 46 * _dgrptabpath() Gets the pathname of the device group file 47 */ 48 49 /* 50 * Header files 51 * <sys/types.h> System data types 52 * <unistd.h> Standard UNIX(r) definitions 53 * <stdio.h> Standard I/O Definitions 54 * <string.h> String handling definitions 55 * <ctype.h> Character types and macros 56 * <errno.h> Errorcode definitions 57 * <sys/stat.h> File status information 58 * <devmgmt.h> Global Device Management definitions 59 * "devtab.h" Local device table definitions 60 */ 61 62 #include <sys/types.h> 63 #include <unistd.h> 64 #include <stdio.h> 65 #include <string.h> 66 #include <ctype.h> 67 #include <errno.h> 68 #include <sys/stat.h> 69 #include <devmgmt.h> 70 #include "devtab.h" 71 #include <stdlib.h> 72 73 /* 74 * Local definitions 75 */ 76 77 78 /* 79 * Static data definitions: 80 * leftoff Addr of char to begin next parse using 81 * getfld(), getattrval(), getquoted() 82 * recbufsz The size of the buffer used for reading records 83 * recbuf Addr of malloc() buffer for reading records 84 * recnum Record number of next record to read 85 * xtndcnt Number of times the buffer has been extended 86 */ 87 88 static char *leftoff = NULL; 89 static int recbufsz = 0; 90 static char *recbuf = NULL; 91 static int recnum = 0; 92 static int xtndcnt = 0; 93 94 /* 95 * void _setdgrptab() 96 * 97 * This function rewinds the open device table so that the next 98 * _getdgrptabent() returns the first record in the device table. 99 * 100 * Arguments: None 101 * 102 * Returns: Void 103 */ 104 105 void 106 _setdgrptab(void) 107 { 108 /* If the device table file is open, rewind the file */ 109 if (oam_dgroup) { 110 rewind(oam_dgroup); 111 recnum = 0; 112 } 113 } 114 115 /* 116 * void _enddgrptab() 117 * 118 * This function closes the open device table. It resets the 119 * open device table external variable to NULL. 120 * 121 * Arguments: None 122 * 123 * Returns: Void 124 */ 125 126 void 127 _enddgrptab(void) 128 { 129 /* If the device table file is open, close it */ 130 if (oam_dgroup) { 131 (void) fclose(oam_dgroup); 132 recnum = 0; 133 oam_dgroup = NULL; 134 } 135 } 136 137 /* 138 * char *getfld(ptr, delims) 139 * char *ptr 140 * char *delims 141 * 142 * Notes: 143 * - Can't use "strtok()" because of its use of static data. The caller 144 * may be using strtok() and we'll really mess them up. 145 * - The function returns NULL if it didn't find any token -- '\0' can't 146 * be a delimiter using this algorithm. 147 */ 148 149 static char * 150 getfld( 151 char *ptr, /* String to parse */ 152 char *delims) /* List of delimiters */ 153 { 154 char *p, *q; 155 156 /* 157 * Figure out where to start. 158 * If given a pointer, use that. 159 * Otherwise, use where we left off. 160 */ 161 162 p = ptr ? ptr : leftoff; 163 164 165 /* 166 * If there's anything to parse, search the string for the first 167 * occurrence of any of the delimiters. If one is found, change it 168 * to '\0' and remember the place to start for next time. If not 169 * found, forget the restart address and prepare to return NULL 170 */ 171 172 if (p) { 173 while (*p && isspace((unsigned char)*p)) p++; 174 if (*p) { 175 q = p; 176 while (*q && !strchr(delims, *q)) q++; 177 if (*q) { 178 *q++ = '\0'; 179 leftoff = q; 180 } else leftoff = NULL; 181 } else leftoff = p = NULL; 182 } 183 184 /* Finished */ 185 return (p); 186 } 187 188 /* 189 * char *getnextrec() 190 * 191 * This function gets the next record from the input stream "oam_dgroup" 192 * and puts it in the device-group table record buffer (whose address is 193 * in "recbuf"). If the buffer is not allocated or is too small to 194 * accommodate the record, the function allocates more space to the 195 * buffer. 196 * 197 * Arguments: None 198 * 199 * Returns: char * 200 * The address of the buffer containing the record. 201 * 202 * Static Data Referenced: 203 * recbuf Address of the buffer containing records read from the 204 * device table file 205 * recbufsz Current size of the record buffer 206 * xtndcnt Number of times the record buffer has been extended 207 * oam_dgroup Device-group table stream, expected to be open for (at 208 * least) reading 209 * 210 * Notes: 211 * - The string returned in the buffer <buf> ALWAYS end in a '\n' (newline) 212 * character followed by a '\0' (null). 213 */ 214 215 static char * 216 getnextrec(void) 217 { 218 /* Automatic data */ 219 char *recp; /* Value to return */ 220 char *p; /* Temp pointer */ 221 int done; /* TRUE if we're finished */ 222 int reclen; /* Number of chars in record */ 223 224 225 /* If there's no buffer for records, try to get one */ 226 if (!recbuf) { 227 if (recbuf = malloc(DGRP_BUFSIZ)) { 228 recbufsz = DGRP_BUFSIZ; 229 xtndcnt = 0; 230 } else return (NULL); 231 } 232 233 234 /* Get the next record */ 235 recp = fgets(recbuf, recbufsz, oam_dgroup); 236 done = FALSE; 237 238 /* While we've something to return and we're not finished ... */ 239 while (recp && !done) { 240 241 /* If our return string isn't a null-string ... */ 242 if ((reclen = (int)strlen(recp)) != 0) { 243 244 /* If we have a complete record, we're finished */ 245 if (*(recp+reclen-1) == '\n') done = TRUE; 246 else while (!done) { 247 248 /* 249 * Need to complete the record. A complete record is one 250 * which is terminated by a new-line character 251 */ 252 253 /* If the buffer is full, expand it and continue reading */ 254 if (reclen == recbufsz-1) { 255 256 /* Have we reached our maximum extension count? */ 257 if (xtndcnt < XTND_MAXCNT) { 258 259 /* Expand the record buffer */ 260 if (p = realloc(recbuf, 261 (size_t)(recbufsz+DGRP_BUFINC))) { 262 263 /* Update buffer information */ 264 xtndcnt++; 265 recbuf = p; 266 recbufsz += DGRP_BUFINC; 267 268 } else { 269 270 /* Expansion failed */ 271 recp = NULL; 272 done = TRUE; 273 } 274 275 } else { 276 277 /* Maximum extend count exceeded. Insane table */ 278 recp = NULL; 279 done = TRUE; 280 } 281 282 } 283 284 /* Complete the record */ 285 if (!done) { 286 287 /* Read stuff into the expanded space */ 288 if (fgets(recbuf+reclen, recbufsz-reclen, oam_dgroup)) { 289 reclen = (int)strlen(recbuf); 290 recp = recbuf; 291 if (*(recp+reclen-1) == '\n') done = TRUE; 292 } else { 293 /* Read failed, corrupt record? */ 294 recp = NULL; 295 done = TRUE; 296 } 297 } 298 299 } /* End incomplete record handling */ 300 301 } else { 302 303 /* Read a null string? (corrupt table) */ 304 recp = NULL; 305 done = TRUE; 306 } 307 308 } /* while (recp && !done) */ 309 310 /* Return what we've got (if anything) */ 311 return (recp); 312 } 313 314 /* 315 * char *_dgrptabpath() 316 * 317 * Get the pathname of the device-group table file 318 * 319 * Arguments: None 320 * 321 * Returns: char * 322 * Returns the pathname to the device group table of (char *) NULL if 323 * there was a problem getting the memory needed to contain the 324 * pathname. 325 * 326 * Algorithm: 327 * 1. If OAM_DGRP is defined in the environment and is not 328 * defined as "", it returns the value of that environment 329 * variable. 330 * 2. Otherwise, use the devault pathname (as defined by the 331 * environment variable DGRP_PATH in <devmgmt.h>. 332 */ 333 334 335 char * 336 _dgrptabpath(void) 337 { 338 339 /* Automatic data */ 340 #ifdef DEBUG 341 char *path; /* Ptr to path in environment */ 342 #endif 343 char *rtnval; /* Ptr to value to return */ 344 345 346 /* 347 * If compiled with -DDEBUG=1, 348 * look for the pathname in the environment 349 */ 350 351 #ifdef DEBUG 352 if (((path = getenv(OAM_DGROUP)) != NULL) && (*path)) { 353 if (rtnval = malloc(strlen(path)+1)) 354 (void) strcpy(rtnval, path); 355 } else { 356 #endif 357 /* 358 * Use the default name. 359 */ 360 361 if (rtnval = malloc(strlen(DGRP_PATH)+1)) 362 (void) strcpy(rtnval, DGRP_PATH); 363 364 #ifdef DEBUG 365 } 366 #endif 367 368 /* Finished */ 369 return (rtnval); 370 } 371 372 /* 373 * int _opendgrptab(mode) 374 * char *mode 375 * 376 * The _opendgrptab() function opens a device-group table for a command. 377 * 378 * Arguments: 379 * mode The open mode to use to open the file. (i.e. "r" for 380 * reading, "w" for writing. See FOPEN(BA_OS) in SVID.) 381 * 382 * Returns: int 383 * TRUE if successful, FALSE otherwise 384 */ 385 386 int 387 _opendgrptab(char *mode) 388 { 389 /* Automatic data */ 390 char *dgrptabname; /* Ptr to the device-group table name */ 391 int rtnval; /* Value to return */ 392 393 rtnval = TRUE; 394 if (dgrptabname = _dgrptabpath()) { 395 if (oam_dgroup) (void) fclose(oam_dgroup); 396 if (oam_dgroup = fopen(dgrptabname, mode)) { 397 xtndcnt = 0; 398 recnum = 0; 399 } else rtnval = FALSE; /* :-( */ 400 } else rtnval = FALSE; /* :-( */ 401 return (rtnval); 402 } 403 404 /* 405 * struct dgrptabent *_getdgrptabent() 406 * 407 * This function returns the next entry in the device-group table. 408 * If no device-group table is open, it opens the standard device-group 409 * table and returns the first record in the table. 410 * 411 * Arguments: None. 412 * 413 * Returns: struct dgrptabent * 414 * Pointer to the next record in the device-group table, or 415 * (struct dgrptabent *) NULL if it was unable to open the file or there 416 * are no more records to read. "errno" reflects the situation. If 417 * errno is not changed and the function returns NULL, there are no more 418 * records to read. If errno is set, it indicates the error. 419 * 420 * Notes: 421 * - The caller should set "errno" to 0 before calling this function. 422 */ 423 424 struct dgrptabent * 425 _getdgrptabent(void) 426 { 427 /* Automatic data */ 428 struct dgrptabent *ent; /* Dev table entry structure */ 429 struct member *q, *r; /* Tmps for member structs */ 430 char *record; /* Record just read */ 431 char *p; /* Tmp char ptr */ 432 int done; /* TRUE if built an entry */ 433 434 435 /* Open the device-group table if it's not already open */ 436 if (!oam_dgroup) 437 if (!_opendgrptab("r")) 438 return (NULL); 439 440 441 /* Get space for the structure we're returning */ 442 if (!(ent = malloc(sizeof (struct dgrptabent)))) { 443 return (NULL); 444 } 445 446 done = FALSE; 447 while (!done && (record = getnextrec())) { 448 449 /* Is this a comment record or a data record */ 450 if (strchr("#\n", *record) || 451 isspace((unsigned char)*record)) { 452 453 /* 454 * Record is a comment record 455 */ 456 ent->comment = TRUE; 457 ent->entryno = recnum++; 458 459 /* Alloc space for the comment and save pointer in struct */ 460 if (ent->dataspace = malloc(strlen(record)+1)) { 461 (void) strcpy(ent->dataspace, record); 462 } else { 463 free(ent); 464 ent = NULL; 465 } 466 done = TRUE; 467 468 } else { 469 470 /* 471 * Record is a data record 472 */ 473 ent->comment = FALSE; 474 475 /* Extract the device-group name */ 476 if (p = getfld(record, ":")) { 477 478 /* Record is a proper record */ 479 done = TRUE; 480 ent->entryno = recnum++; 481 482 /* Copy device group name into malloc()ed space */ 483 if (!(ent->name = malloc(strlen(p)+1))) { 484 485 free(ent); 486 return (NULL); 487 } 488 (void) strcpy(ent->name, p); 489 490 /* 491 * Extract the membership from the membership list 492 */ 493 494 /* Get the 1st member */ 495 ent->dataspace = NULL; 496 while (((p = getfld(NULL, ",\n")) != NULL) && !(*p)) 497 ; 498 if (p) { 499 if (!(q = malloc(sizeof (struct member)))) { 500 501 free(ent->name); 502 free(ent); 503 return (NULL); 504 } 505 if (!(q->name = malloc(strlen(p)+1))) { 506 free(q); 507 free(ent->name); 508 free((char *)ent); 509 return (NULL); 510 } 511 (void) strcpy(q->name, p); 512 ent->membership = q; 513 q->next = NULL; 514 515 /* Get the rest of the members */ 516 while (p = getfld(NULL, ",\n")) 517 if (*p) { 518 if (!(r = malloc(sizeof (struct member)))) { 519 for (q = ent->membership; q; q = r) { 520 free(q->name); 521 r = q->next; 522 free(q); 523 } 524 free(ent->name); 525 free(ent); 526 return (NULL); 527 } 528 if (!(r->name = malloc(strlen(p)+1))) { 529 free(r); 530 for (q = ent->membership; q; q = r) { 531 free(q->name); 532 r = q->next; 533 free(q); 534 } 535 free(ent->name); 536 free(ent); 537 return (NULL); 538 } 539 540 q->next = r; 541 (void) strcpy(r->name, p); 542 r->next = NULL; 543 q = r; 544 } 545 546 } else { 547 /* No members */ 548 ent->membership = NULL; 549 } 550 551 } /* record contains a group name */ 552 553 } /* record is a data record */ 554 555 } /* while (!done && there's more records) */ 556 557 558 /* An entry read? If not, free alloc'd space and return NULL */ 559 if (!done) { 560 free(ent); 561 ent = NULL; 562 } 563 564 /* Finis */ 565 return (ent); 566 } 567 568 /* 569 * void _freedgrptabent(dgrptabent) 570 * struct dgrptabent *dgrptabent; 571 * 572 * This function frees space allocated to a device table entry. 573 * 574 * Arguments: 575 * struct dgrptabent *dgrptabent The structure whose space is to be 576 * freed. 577 * 578 * Returns: void 579 */ 580 581 void 582 _freedgrptabent(struct dgrptabent *ent) /* Structure to free */ 583 { 584 /* 585 * Automatic data 586 */ 587 588 struct member *p; /* Structure being freed */ 589 struct member *q; /* Next structure to free */ 590 591 /* 592 * Free the space allocated to the membership structure. 593 */ 594 595 if (!ent->comment) { 596 if ((q = ent->membership) != NULL) do { 597 p = q; 598 q = p->next; 599 if (p->name) free(p->name); 600 free(p); 601 } while (q); 602 603 /* Free the device group name */ 604 if (ent->name) free(ent->name); 605 } 606 607 /* Free the membership string */ 608 if (ent->dataspace) free(ent->dataspace); 609 } 610 611 /* 612 * struct dgrptabent *_getdgrprec(dgroup) 613 * char *dgroup 614 * 615 * Thie _getdgrprec() function returns a pointer to a structure that 616 * contains the information in the device-group table entry that describes 617 * the device-group <dgroup>. 618 * 619 * Arguments: 620 * char *dgroup A character-string describing the device-group whose 621 * record is to be retrieved from the device-group table. 622 * 623 * Returns: struct dgrptabent * 624 * A pointer to a structure describing the device group. 625 */ 626 627 struct dgrptabent * 628 _getdgrprec(char *dgroup) /* dgroup to search for */ 629 { 630 /* 631 * Automatic data 632 */ 633 634 struct dgrptabent *dgrprec; /* Pointer to current record */ 635 int found; /* FLAG, TRUE if found */ 636 637 638 /* 639 * Search the device-group table looking for the requested 640 * device group 641 */ 642 643 _setdgrptab(); 644 errno = 0; 645 found = FALSE; 646 while (!found && (dgrprec = _getdgrptabent())) { 647 if (!dgrprec->comment && strcmp(dgroup, dgrprec->name) == 0) 648 found = TRUE; 649 else _freedgrptabent(dgrprec); 650 } 651 652 /* Set up return codes if we've failed */ 653 if (!found) { 654 if (errno == 0) errno = EINVAL; 655 dgrprec = NULL; 656 } 657 658 /* Finis */ 659 return (dgrprec); 660 } 661