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