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