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 /* 23 * Copyright (c) 1996-1997, by Sun Microsystems, Inc. 24 * All Rights reserved. 25 */ 26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 27 /* All Rights Reserved */ 28 29 30 #pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.2 */ 31 /* LINTLIBRARY */ 32 33 /* 34 * putdgrp.c 35 * 36 * Global Definitions: 37 * _putdgrptabrec() Write a device-group record to a stream 38 * _rmdgrptabrec() Remove a device-group table record 39 * _rmdgrpmems() Remove specific members from a device group 40 * _adddgrptabrec() Add a device-group record to the table 41 */ 42 43 /* 44 * G L O B A L R E F E R E N C E S 45 * 46 * Header Files 47 * Externals Referenced 48 */ 49 50 /* 51 * Header Files 52 * <sys/types.h> UNIX System Data Types 53 * <stdio.h> Standard I/O definitions 54 * <fcntl.h> Definitions for file control 55 * <errno.h> Error handling definitions 56 * <string.h> String Handling Definitions 57 * <unistd.h> Standard UNIX(r) Definitions 58 * <devmgmt.h> Device Management Definitions 59 * "devtab.h" Local Device Management Definitions 60 */ 61 62 #include <sys/types.h> 63 #include <sys/stat.h> 64 #include <stdio.h> 65 #include <fcntl.h> 66 #include <errno.h> 67 #include <string.h> 68 #include <unistd.h> 69 #include <stdlib.h> 70 #include <devmgmt.h> 71 #include "devtab.h" 72 73 /* 74 * L O C A L D E F I N I T I O N S 75 * TDGTABNM Name of the temporary device-group table (in the 76 * directory of the existing table) 77 * TDGTABNMLN Number of characters added to the directory 78 * name -- the length of the device-group table temp name 79 */ 80 81 #define TDGTABNM "%sdgroup.%6.6d" 82 #define TDGTABNMLN 13 83 84 85 /* 86 * Static functions 87 * lkdgrptab Locks the device-group table 88 * unlkdgrptab Unlocks the device-group table 89 * mkdgrptabent Builds a device-group table entry from the alias and the 90 * list of attr=val pairs given 91 * opennewdgrptab Opens a new device-group table (as a temp file) 92 * mknewdgrptab Makes the temp device-group table the new dgrptab 93 * rmnewdgrptab Remove the temporary device-group table and free space 94 * allocated to the filename of that file. 95 */ 96 97 static int lkdgrptab(char *o_mode, short lktype); 98 static int unlkdgrptab(void); 99 static struct dgrptabent *mkdgrptabent(char *dgroup, char **members); 100 static FILE *opennewdgrptab(char **pname); 101 static int mknewdgrptab(char *tempname); 102 static int rmnewdgrptab(char *tempname); 103 104 /* 105 * FILE *opennewdgrptab(pname) 106 * char **pname 107 * 108 * Generates a temporary device-group table name from the existing 109 * device-group table name (in the same directory) and opens that 110 * file for writing. It puts a pointer to the malloc()ed space 111 * containing the temp device-group table's name at the place 112 * referenced by <pname>. 113 * 114 * Arguments: 115 * pname Pointer to the char * to contain the address of the name 116 * of the temporary file 117 * 118 * Returns: FILE * 119 * A pointer to the opened stream or (FILE *) NULL if an error occurred. 120 * If an error occurred, "errno" will be set to reflect the problem. 121 */ 122 123 static FILE * 124 opennewdgrptab(char **pname) /* A(ptr to temp filename's path) */ 125 { 126 char *oldname; /* Ptr to the dgrptab name */ 127 char *buf; /* Ptr to the temp file's name */ 128 char *dirname; /* Directory containing dgrptab */ 129 char *p; /* Ptr to last '/' in dgrptab name */ 130 int fd; /* Opened file descriptor */ 131 FILE *fp; /* Opened file pointer */ 132 struct stat64 sbuf; /* stat buf for old dgrptab file */ 133 134 135 /* Initializations */ 136 fp = NULL; 137 138 /* Get the name of the device-group table */ 139 if (oldname = _dgrptabpath()) { 140 /* 141 * It is possible for us to have sufficient permissions to create 142 * the new file without having sufficient permissions to write the 143 * original dgrptab file. For consistency with the operations which 144 * modify the original file by writing it directly we require write 145 * permissions for the original file in order to make a new one. 146 */ 147 if ((fd = open(oldname, O_WRONLY)) == -1) 148 return (NULL); 149 150 if (fstat64(fd, &sbuf) == -1) { 151 (void) close(fd); 152 return (NULL); 153 } 154 (void) close(fd); 155 156 /* Get the directory that the device-group table lives in */ 157 if (p = strrchr(oldname, '/')) { 158 *(p+1) = '\0'; 159 dirname = oldname; 160 } else 161 dirname = "./"; 162 163 /* Get space for the temp dgrptab pathname */ 164 if (buf = malloc(TDGTABNMLN+strlen(dirname)+1)) { 165 166 /* 167 * Build the name of the temp dgrptab and open the 168 * file. We must reset the owner, group and perms to those 169 * of the original dgrptab file. 170 */ 171 (void) sprintf(buf, TDGTABNM, dirname, getpid()); 172 if (fp = fopen(buf, "w")) { 173 *pname = buf; 174 (void) fchmod(fileno(fp), sbuf.st_mode & 0777); 175 (void) fchown(fileno(fp), sbuf.st_uid, sbuf.st_gid); 176 } else { 177 free(buf); 178 } 179 } 180 181 /* Free the space containing the dgrptab's name */ 182 free(oldname); 183 } 184 185 /* Finished. Return what we've got */ 186 return (fp); 187 } 188 189 /* 190 * int rmnewdgrptab(tempname) 191 * char *tempname 192 * 193 * Unlink the temp dgrptab and free the memory allocated to 194 * contain the name of that file 195 * 196 * Arguments: 197 * tempname Name of the temporary file 198 * 199 * Returns: int 200 * TRUE if successful, FALSE otherwise 201 */ 202 203 static int 204 rmnewdgrptab(char *tempname) 205 { 206 /* Automatic data */ 207 int noerr; 208 209 /* Unlink the temporary file */ 210 noerr = (unlink(tempname) == 0); 211 free(tempname); 212 213 /* Finished */ 214 return (noerr); 215 } 216 217 /* 218 * int mknewdgrptab(tempname) 219 * char *tempname 220 * 221 * Make the temporary device-group table the new system 222 * device-group table 223 * 224 * Arguments: 225 * tempname Name of the temporary file 226 * 227 * Returns: int 228 * TRUE if successful, FALSE otherwise 229 * 230 * Notes: 231 * - Need to use rename() someday instead of link()/unlink() 232 * - This code is somewhat ineffecient in that asks for the name 233 * of the device-group table more than once. Done so that we don't 234 * have to manage that space, but this may be somewhat lazy. 235 */ 236 237 static int 238 mknewdgrptab(char *tempname) /* Ptr to name of temp dgrp tab */ 239 { 240 char *dgrpname; /* Ptr to the dgrptab's name */ 241 int noerr; /* FLAG, TRUE if all's well */ 242 243 /* Get the dgrptab's pathname */ 244 if (dgrpname = _dgrptabpath()) { 245 246 /* Unlink the existing file */ 247 if (unlink(dgrpname) == 0) { 248 249 /* Make the temp file the real device-group table */ 250 noerr = (link(tempname, dgrpname) == 0) ? TRUE : FALSE; 251 252 /* Remove the temp file */ 253 if (noerr) noerr = rmnewdgrptab(tempname); 254 255 } else noerr = FALSE; /* unlink() failed */ 256 257 /* Free the dgrptab's name */ 258 free(dgrpname); 259 260 } else noerr = FALSE; /* dgrptabpath() failed */ 261 262 /* Finished. Return success indicator */ 263 return (noerr); 264 } 265 266 /* 267 * int lkdgrptab(o_mode, lktype) 268 * char *o_mode 269 * short lktype 270 * 271 * Lock the device-group table for writing. If it isn't available, it 272 * waits until it is. 273 * 274 * Arguments: 275 * o_mode The open() mode to use when opening the device-group table 276 * lktype The type of lock to apply 277 * 278 * Returns: int 279 * TRUE if successful, FALSE with errno set otherwise 280 */ 281 282 static int 283 lkdgrptab( 284 char *o_mode, /* Open mode */ 285 short lktype) /* Lock type */ 286 { 287 /* Automatic data */ 288 struct flock lockinfo; /* File locking structure */ 289 int noerr; /* FLAG, TRUE if no error */ 290 int olderrno; /* Former value of errno */ 291 292 293 /* Close the device-group table (if it's open) */ 294 _enddgrptab(); 295 296 /* Open the device-group table for read/append */ 297 noerr = TRUE; 298 if (_opendgrptab(o_mode)) { 299 300 /* 301 * Lock the device-group table (for writing). If it's not 302 * available, wait until it is, then close and open the 303 * table (modify and delete change the table!) and try 304 * to lock it again 305 */ 306 307 /* Build the locking structure */ 308 lockinfo.l_type = lktype; 309 lockinfo.l_whence = 0; 310 lockinfo.l_start = 0L; 311 lockinfo.l_len = 0L; 312 olderrno = errno; 313 314 /* Keep on going until we lock the file or an error happens */ 315 while ((fcntl(fileno(oam_dgroup), F_SETLK, &lockinfo) == -1) && 316 !noerr) { 317 318 /* 319 * fcntl() failed. 320 * If errno=EACCES, it's because the file's locked by someone 321 * else. Wait for the file to be unlocked, then close and 322 * reopen the file and try the lock again. 323 */ 324 325 if (errno == EACCES) { 326 if (fcntl(fileno(oam_dgroup), F_SETLKW, &lockinfo) == -1) 327 noerr = FALSE; 328 else { 329 _enddgrptab(); 330 if (!_opendgrptab(o_mode)) noerr = FALSE; 331 else errno = olderrno; 332 } 333 334 } else noerr = FALSE; /* fcntl() failed hard */ 335 336 } /* End while (fcntl() && !noerr) */ 337 338 /* Don't keep file open if an error happened */ 339 if (!noerr) _enddgrptab(); 340 341 } else noerr = FALSE; /* _opendgrptab() failed */ 342 343 /* Done */ 344 return (noerr); 345 } 346 347 /* 348 * int unlkdgrptab() 349 * 350 * Unlock the locked device-group table. 351 * 352 * Arguments: None 353 * 354 * Returns: int 355 * Whatever fcntl() returns... 356 */ 357 358 static int 359 unlkdgrptab(void) 360 { 361 /* Automatic data */ 362 struct flock lockinfo; /* Locking structure */ 363 int noerr; /* FLAG, TRUE if all's well */ 364 365 /* Build the locking structure */ 366 lockinfo.l_type = F_UNLCK; /* Lock type */ 367 lockinfo.l_whence = 0; /* Count from top of file */ 368 lockinfo.l_start = 0L; /* From beginning */ 369 lockinfo.l_len = 0L; /* Length of locked data */ 370 371 /* Unlock it */ 372 noerr = (fcntl(fileno(oam_dgroup), F_SETLK, &lockinfo) != -1); 373 _enddgrptab(); 374 375 /* Finished */ 376 return (noerr); 377 } 378 379 /* 380 * struct dgrptabent *mkdgrptabent(dgroup, members) 381 * char *dgroup 382 * char **members 383 * 384 * This function builds a struct dgrptabent structure describing the 385 * device-group <dgroup> so that it contains the members in the 386 * membership list <members>. 387 * 388 * Arguments: 389 * dgroup The device-group being added to the device-group table 390 * members The members of the device-group 391 * 392 * Returns: struct dgrptabent * 393 * A completed struct dgrptabent structure containing the description 394 * of the device group. The structure, and all of the data in the 395 * structure are each in space allocated using the malloc() function 396 * and should be freed using the free() function (or the _freedgrptabent() 397 * function. 398 */ 399 400 static struct dgrptabent * 401 mkdgrptabent( 402 char *dgroup, /* Device-group being created (or modified) */ 403 char **members) /* Members to add to that entry */ 404 { 405 /* Automatic data */ 406 struct dgrptabent *ent; /* Ptr to struct we're making */ 407 struct member *prev; /* Ptr to prev attr/val struct */ 408 struct member *member; /* Ptr to current struct */ 409 char **pp; /* Ptr into list of ptrs */ 410 int noerr; /* TRUE if all's well */ 411 412 413 /* No problems (yet) */ 414 noerr = TRUE; 415 416 /* Get space for the structure */ 417 if (ent = malloc(sizeof (struct dgrptabent))) { 418 419 /* Fill in default values */ 420 ent->name = NULL; /* alias */ 421 ent->entryno = 0; /* Entry no. */ 422 ent->comment = FALSE; /* data rec */ 423 ent->dataspace = NULL; /* string */ 424 ent->membership = NULL; /* attr list */ 425 426 /* Fill in the device-group name */ 427 if (ent->name = malloc(strlen(dgroup)+1)) { 428 (void) strcpy(ent->name, dgroup); 429 430 /* Add membership to the structure */ 431 prev = NULL; 432 if ((pp = members) != NULL) 433 while (*pp && noerr) { 434 435 if (member = malloc(sizeof (struct member))) { 436 437 if (member->name = malloc(strlen(*pp)+1)) { 438 (void) strcpy(member->name, *pp); 439 if (prev) prev->next = member; 440 else ent->membership = member; 441 member->next = NULL; 442 prev = member; 443 } else { 444 noerr = FALSE; 445 free(member); 446 } 447 } else noerr = FALSE; 448 pp++; 449 } /* End membership processing loop */ 450 451 } else noerr = FALSE; /* malloc() failed */ 452 453 /* 454 * If there was a problem, clean up the mess we've made 455 */ 456 457 if (!noerr) { 458 459 _freedgrptabent(ent); 460 ent = NULL; 461 462 } /* if (noerr) */ 463 464 } else noerr = FALSE; /* if (malloc(dgrptabent space)) */ 465 466 /* Finished */ 467 return (ent); 468 } 469 470 /* 471 * int _putdgrptabrec(stream, rec) 472 * FILE *stream 473 * struct dgrptabent *rec 474 * 475 * Write a device-group table record containing the information in the 476 * struct dgrptab structure <rec> to the current position of the 477 * standard I/O stream <stream>. 478 * 479 * Arguments: 480 * stream The stream to write to 481 * rec The structure containing the information to write 482 * 483 * Returns: int 484 * The number of characters written or EOF if there was some error. 485 */ 486 487 int 488 _putdgrptabrec( 489 FILE *stream, /* Stream to write to */ 490 struct dgrptabent *rec) /* Record to write */ 491 { 492 /* Automatic Data */ 493 struct member *mem; /* Ptr to attr/val pair */ 494 char *buf; /* Allocated buffer */ 495 char *p; /* Temp char pointer */ 496 char *q; /* Temp char pointer */ 497 int count; /* Number of chars written */ 498 int size; /* Size of needed buffer */ 499 500 501 /* Comment or data record? */ 502 if (rec->comment) count = fputs(rec->dataspace, stream); 503 else { 504 505 /* 506 * Record is a data record 507 */ 508 509 /* Figure out the amount of space the record needs */ 510 size = (int)strlen(rec->name) + 1; /* "name:" */ 511 if ((mem = rec->membership) != NULL) 512 do { /* members */ 513 /* "membername " or "membername\n" */ 514 size += (int)strlen(mem->name) + 1; 515 } while ((mem = mem->next) != NULL); /* Next attr/val */ 516 else 517 size++; /* Count trailing '\n' if empty grp */ 518 519 520 /* Alloc space for the record */ 521 if (buf = malloc((size_t) size+1)) { 522 523 /* Initializations */ 524 p = buf; 525 526 /* Write the device-group name */ 527 q = rec->name; 528 while (*q) *p++ = *q++; 529 *p++ = ':'; 530 531 /* Write the membership list */ 532 if ((mem = rec->membership) != NULL) do { 533 q = mem->name; 534 while (*q) *p++ = *q++; 535 if ((mem = mem->next) != NULL) *p++ = ','; 536 } while (mem); 537 538 /* Terminate the record */ 539 *p++ = '\n'; 540 *p = '\0'; 541 542 /* Write the record */ 543 count = fputs(buf, stream); 544 free(buf); 545 } else 546 count = EOF; /* malloc() failed */ 547 } 548 549 /* Finished */ 550 return (count); 551 } 552 553 /* 554 * int _adddgrptabrec(dgrp, members) 555 * char *dgrp 556 * char **members 557 * 558 * If <dgrp> doesn't exist, this function adds a record to the 559 * device-group table for that device-group. That record will 560 * have the name <dgrp> and will have a membership described in 561 * the list referenced by <members>. The record is added to the 562 * end of the table. 563 * 564 * If <dgrp> already exists in the table, the function adds the 565 * members in the <members> list to the group's membership. 566 * 567 * Arguments: 568 * dgrp The name of the device-group being added to the 569 * device-group table. 570 * members A pointer to the first item of the list of members 571 * in the device-group being added to the table. 572 * (This value may be (char **) NULL). 573 * 574 * Returns: int 575 * TRUE if successful, FALSE with "errno" set otherwise. 576 */ 577 578 int 579 _adddgrptabrec( 580 char *dgrp, /* Devgrp to add to the table */ 581 char **members) /* Members for that devgrp */ 582 { 583 /* Automatic data */ 584 struct dgrptabent *ent; /* Ptr to dev tab entry */ 585 struct dgrptabent *new; /* Ptr to new dev tab info */ 586 struct dgrptabent *p; /* Temp ptr to dev tab info */ 587 struct member *pm, *qm, *rm; /* Tmp ptrs to struct member */ 588 FILE *fd; /* File descr, temp file */ 589 char *path; /* Ptr to new devtab name */ 590 int olderrno; /* Errno on entry */ 591 int noerr; /* FLAG, TRUE if all's well */ 592 593 594 /* Make a structure describing the new information */ 595 if ((new = mkdgrptabent(dgrp, members)) == NULL) 596 return (FALSE); 597 598 /* 599 * Lock the device-group table. This only returns if the 600 * table is locked or some error occurred. It waits until the 601 * table is available. 602 */ 603 if (!lkdgrptab("a+", F_WRLCK)) { 604 _freedgrptabent(new); 605 return (FALSE); 606 } 607 608 /* 609 * If the device-group is already in the table, add 610 * the specified members 611 */ 612 613 noerr = TRUE; 614 olderrno = errno; 615 if (ent = _getdgrprec(dgrp)) { 616 617 /* Any members to add? If not, do nothing. */ 618 if (new->membership) { 619 620 /* Any existing members? */ 621 if ((pm = ent->membership) != NULL) { 622 623 /* Find the end of the existing membership list */ 624 while (pm->next) pm = pm->next; 625 626 /* Append the new members to the membership list */ 627 pm->next = new->membership; 628 629 /* Remove any duplicates */ 630 for (pm = ent->membership; pm; pm = pm->next) { 631 qm = pm; 632 while ((rm = qm->next) != NULL) { 633 if (strcmp(pm->name, rm->name) == 0) { 634 qm->next = rm->next; 635 free(rm->name); 636 free(rm); 637 } else qm = rm; 638 } 639 } 640 } else ent->membership = new->membership; 641 642 /* No members in the new list any more */ 643 new->membership = NULL; 644 645 /* 646 * Make a new device-group table, replacing the 647 * record for the specified device-group 648 */ 649 650 _setdgrptab(); /* Rewind existing table */ 651 652 /* Open a temp file */ 653 if (fd = opennewdgrptab(&path)) { 654 655 /* While there's more records and no error ... */ 656 while (((p = _getdgrptabent()) != NULL) && noerr) { 657 658 /* 659 * If this isn't the record we're replacing, 660 * write it to the temporary file. Otherwise, 661 * write the updated record 662 */ 663 664 if (ent->entryno != p->entryno) 665 noerr = _putdgrptabrec(fd, p) != EOF; 666 else noerr = _putdgrptabrec(fd, ent) != EOF; 667 _freedgrptabent(p); 668 } 669 670 /* Fix the files */ 671 if (noerr) { 672 (void) fclose(fd); 673 noerr = mknewdgrptab(path); 674 } else { 675 (void) fclose(fd); 676 (void) rmnewdgrptab(path); 677 } 678 } /* if (opennewdgrptab()) */ 679 680 } /* If there's members to add */ 681 682 /* Free the memory associated with the updated entry */ 683 _freedgrptabent(ent); 684 } 685 686 /* 687 * Otherwise, add the device-group to the end of the table 688 */ 689 690 else if (errno == EINVAL) { 691 errno = olderrno; 692 if (fseek(oam_dgroup, 0, SEEK_END) == 0) 693 noerr = (_putdgrptabrec(oam_dgroup, new) != EOF); 694 } else noerr = FALSE; 695 696 /* Finished */ 697 (void) unlkdgrptab(); /* Unlock the file */ 698 _freedgrptabent(new); /* Free the new dgrptab info struct */ 699 return (noerr); /* Return with success indicator */ 700 } 701 702 /* 703 * int _rmdgrptabrec(dgrp) 704 * char *dgrp 705 * 706 * This function removes the record in the device-group table 707 * for the specified device-group. 708 * 709 * Arguments: 710 * dgrp The device-group to be removed 711 * 712 * Returns: int 713 * Success indicator: TRUE if successful, FALSE with errno set otherwise. 714 */ 715 716 int 717 _rmdgrptabrec(char *dgrp) /* Device-group to remove */ 718 { 719 /* Automatic data */ 720 struct dgrptabent *ent; /* Entry to remove */ 721 struct dgrptabent *p; /* Entry being copied */ 722 FILE *fd; /* Temp file's file descriptor */ 723 char *path; /* Pathname of temp file */ 724 int noerr; /* FLAG, TRUE if all's well */ 725 726 noerr = TRUE; 727 if (!lkdgrptab("r", F_WRLCK)) 728 return (FALSE); 729 if (ent = _getdgrprec(dgrp)) { 730 _setdgrptab(); 731 if (fd = opennewdgrptab(&path)) { 732 while (((p = _getdgrptabent()) != NULL) && noerr) { 733 if (ent->entryno != p->entryno) 734 noerr = _putdgrptabrec(fd, p) != EOF; 735 _freedgrptabent(p); 736 } 737 if (noerr) { 738 (void) fclose(fd); 739 noerr = mknewdgrptab(path); 740 } else { 741 (void) fclose(fd); 742 (void) rmnewdgrptab(path); 743 } 744 } else noerr = FALSE; 745 _freedgrptabent(ent); 746 } else noerr = FALSE; 747 (void) unlkdgrptab(); 748 return (noerr); 749 } 750 751 /* 752 * int _rmdgrpmems(dgrp, mems, notfounds) 753 * char *dgrp 754 * char **mems 755 * char ***notfounds 756 * 757 * Remove the specified members from the membership of the specified 758 * device-group. Any members not found in that device-group are 759 * returned in the list referenced by <notfounds>. 760 * 761 * Arguments: 762 * dgrp The device-group from which members are to be removed 763 * mems The address of the first element in the list of 764 * members to remove. This list is terminated by 765 * (char *) NULL. 766 * notfounds The place to put the address of the list of addresses 767 * referencing the requested members that were not 768 * members of the specified device-group 769 * 770 * Returns: int 771 * TRUE if successful, FALSE with errno set otherwise. 772 */ 773 774 int 775 _rmdgrpmems( 776 char *dgrp, /* Device-group to modify */ 777 char **mems, /* Members to remove */ 778 char ***notfounds) /* Members req'd but not found */ 779 { 780 /* Automatic data */ 781 struct dgrptabent *ent; /* Entry to modify */ 782 struct dgrptabent *p; /* Entry being copied */ 783 struct member *pm; /* Ptr to member being examined */ 784 struct member *prev; /* Ptr to previous member */ 785 char **nflst; /* Ptr to not-found list */ 786 char **pnf; /* Ptr into not-found list */ 787 char **pp; /* Ptr into members-to-rm list */ 788 FILE *fd; /* Temp file's file descriptor */ 789 char *path; /* Pathname of temp file */ 790 int noerr; /* TRUE if all's well */ 791 int found; /* TRUE if member is in membership */ 792 int i; /* Temp counter */ 793 794 noerr = TRUE; 795 796 /* Lock the device-group table */ 797 if (!lkdgrptab("r", F_WRLCK)) 798 return (FALSE); 799 800 /* Nothing is "not found" yet */ 801 *notfounds = NULL; 802 803 /* Get the entry we're to modify */ 804 if (ent = _getdgrprec(dgrp)) { 805 806 /* Allocate space for the not-found list */ 807 i = 1; 808 if (mems) 809 for (pp = mems; *pp; pp++) 810 i++; 811 if (nflst = malloc(i*sizeof (char *))) { 812 pnf = nflst; 813 *pnf = NULL; 814 815 /* For each member to remove ... (if any) */ 816 if (mems) 817 for (pp = mems; *pp; pp++) { 818 819 found = FALSE; 820 821 /* Compare against each member in the membership list */ 822 pm = ent->membership; 823 prev = NULL; 824 while (pm && !found) { 825 826 if (strcmp(*pp, pm->name) == 0) { 827 828 /* Found. Remove from linked list */ 829 if (prev) prev->next = pm->next; 830 else ent->membership = pm->next; 831 if (pm->name) free(pm->name); 832 free(pm); 833 found = TRUE; 834 835 } else { 836 837 /* Bump to the next member */ 838 prev = pm; 839 pm = pm->next; 840 841 } 842 843 } /* For each member in the group */ 844 845 /* 846 * If the requested member-to-remove wasn't found, 847 * add it to the list of not-found members 848 */ 849 if (!found) { 850 if (*pnf = malloc(strlen(*pp)+1)) { 851 (void) strcpy(*pnf++, *pp); 852 *pnf = NULL; 853 } else noerr = FALSE; 854 } 855 856 } /* for (each requested member to remove */ 857 858 _setdgrptab(); /* Rewind existing table */ 859 860 if (fd = opennewdgrptab(&path)) { 861 while (((p = _getdgrptabent()) != NULL) && noerr) { 862 if (ent->entryno != p->entryno) 863 noerr = _putdgrptabrec(fd, p) != EOF; 864 else noerr = _putdgrptabrec(fd, ent) != EOF; 865 _freedgrptabent(p); 866 } 867 if (noerr) { 868 (void) fclose(fd); 869 noerr = mknewdgrptab(path); 870 } else { 871 (void) fclose(fd); 872 (void) rmnewdgrptab(path); 873 } 874 } else noerr = FALSE; /* if (opennewdgrptab()) */ 875 876 /* 877 * If there was no error but there was requested members 878 * that weren't found, set the not-found list and the error 879 * information. Otherwise, free the not-found list 880 */ 881 882 if (noerr && (pnf != nflst)) { 883 *notfounds = nflst; 884 errno = ENODEV; 885 noerr = FALSE; 886 } else { 887 for (pnf = nflst; *pnf; pnf++) free(*pnf); 888 free(nflst); 889 if (!noerr) *notfounds = NULL; 890 } 891 } else noerr = FALSE; 892 893 /* Free the description of the modified device group */ 894 _freedgrptabent(ent); 895 896 } else noerr = FALSE; /* _getdgrprec() failed */ 897 898 /* Unlock the original device-group table */ 899 (void) unlkdgrptab(); 900 return (noerr); 901 } 902