dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / libadm / common / putdgrp.c
blobcb038be7d062c96f1f6df141fa6d4b19b7cb983b
1 /*
2 * CDDL HEADER START
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.
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.
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]
20 * CDDL HEADER END
23 * Copyright (c) 1996-1997, by Sun Microsystems, Inc.
24 * All Rights reserved.
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
30 * Copyright 2010 Nexenta Systems, Inc. All rights reserved.
33 /* LINTLIBRARY */
36 * putdgrp.c
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
46 * G L O B A L R E F E R E N C E S
48 * Header Files
49 * Externals Referenced
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
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"
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)
81 #define TDGTABNM "%sdgroup.%6.6d"
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.
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);
104 * FILE *opennewdgrptab(pname)
105 * char **pname
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>.
113 * Arguments:
114 * pname Pointer to the char * to contain the address of the name
115 * of the temporary file
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.
122 static FILE *
123 opennewdgrptab(char **pname) /* A(ptr to temp filename's path) */
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 */
134 /* Initializations */
135 fp = NULL;
137 /* Get the name of the device-group table */
138 if (oldname = _dgrptabpath()) {
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.
148 if ((fd = open(oldname, O_WRONLY)) == -1)
149 return (NULL);
151 if (fstat64(fd, &sbuf) == -1) {
152 (void) close(fd);
153 return (NULL);
155 (void) close(fd);
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 = "./";
164 /* Get space for the temp dgrptab pathname */
165 if (asprintf(&buf, TDGTABNM, dirname, getpid()) >= 0) {
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.
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);
182 /* Free the space containing the dgrptab's name */
183 free(oldname);
186 /* Finished. Return what we've got */
187 return (fp);
191 * int rmnewdgrptab(tempname)
192 * char *tempname
194 * Unlink the temp dgrptab and free the memory allocated to
195 * contain the name of that file
197 * Arguments:
198 * tempname Name of the temporary file
200 * Returns: int
201 * TRUE if successful, FALSE otherwise
204 static int
205 rmnewdgrptab(char *tempname)
207 /* Automatic data */
208 int noerr;
210 /* Unlink the temporary file */
211 noerr = (unlink(tempname) == 0);
212 free(tempname);
214 /* Finished */
215 return (noerr);
219 * int mknewdgrptab(tempname)
220 * char *tempname
222 * Make the temporary device-group table the new system
223 * device-group table
225 * Arguments:
226 * tempname Name of the temporary file
228 * Returns: int
229 * TRUE if successful, FALSE otherwise
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.
238 static int
239 mknewdgrptab(char *tempname) /* Ptr to name of temp dgrp tab */
241 char *dgrpname; /* Ptr to the dgrptab's name */
242 int noerr; /* FLAG, TRUE if all's well */
244 /* Get the dgrptab's pathname */
245 if (dgrpname = _dgrptabpath()) {
247 /* Unlink the existing file */
248 if (unlink(dgrpname) == 0) {
250 /* Make the temp file the real device-group table */
251 noerr = (link(tempname, dgrpname) == 0) ? TRUE : FALSE;
253 /* Remove the temp file */
254 if (noerr)
255 noerr = rmnewdgrptab(tempname);
257 } else {
258 noerr = FALSE; /* unlink() failed */
261 /* Free the dgrptab's name */
262 free(dgrpname);
264 } else {
265 noerr = FALSE; /* dgrptabpath() failed */
268 /* Finished. Return success indicator */
269 return (noerr);
273 * int lkdgrptab(o_mode, lktype)
274 * char *o_mode
275 * short lktype
277 * Lock the device-group table for writing. If it isn't available, it
278 * waits until it is.
280 * Arguments:
281 * o_mode The open() mode to use when opening the device-group table
282 * lktype The type of lock to apply
284 * Returns: int
285 * TRUE if successful, FALSE with errno set otherwise
288 static int
289 lkdgrptab(
290 char *o_mode, /* Open mode */
291 short lktype) /* Lock type */
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 */
299 /* Close the device-group table (if it's open) */
300 _enddgrptab();
302 /* Open the device-group table for read/append */
303 noerr = TRUE;
304 if (_opendgrptab(o_mode)) {
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
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;
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) {
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.
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;
344 } else
345 noerr = FALSE; /* fcntl() failed hard */
347 } /* End while (fcntl() && !noerr) */
349 /* Don't keep file open if an error happened */
350 if (!noerr) _enddgrptab();
352 } else
353 noerr = FALSE; /* _opendgrptab() failed */
355 /* Done */
356 return (noerr);
360 * int unlkdgrptab()
362 * Unlock the locked device-group table.
364 * Arguments: None
366 * Returns: int
367 * Whatever fcntl() returns...
370 static int
371 unlkdgrptab(void)
373 /* Automatic data */
374 struct flock lockinfo; /* Locking structure */
375 int noerr; /* FLAG, TRUE if all's well */
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 */
383 /* Unlock it */
384 noerr = (fcntl(fileno(oam_dgroup), F_SETLK, &lockinfo) != -1);
385 _enddgrptab();
387 /* Finished */
388 return (noerr);
392 * struct dgrptabent *mkdgrptabent(dgroup, members)
393 * char *dgroup
394 * char **members
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>.
400 * Arguments:
401 * dgroup The device-group being added to the device-group table
402 * members The members of the device-group
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.
412 static struct dgrptabent *
413 mkdgrptabent(
414 char *dgroup, /* Device-group being created (or modified) */
415 char **members) /* Members to add to that entry */
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 */
425 /* No problems (yet) */
426 noerr = TRUE;
428 /* Get space for the structure */
429 if (ent = malloc(sizeof (struct dgrptabent))) {
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 */
438 /* Fill in the device-group name */
439 if (ent->name = malloc(strlen(dgroup)+1)) {
440 (void) strcpy(ent->name, dgroup);
442 /* Add membership to the structure */
443 prev = NULL;
444 if ((pp = members) != NULL)
445 while (*pp && noerr) {
447 if (member = malloc(sizeof (struct member))) {
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);
459 } else noerr = FALSE;
460 pp++;
461 } /* End membership processing loop */
463 } else noerr = FALSE; /* malloc() failed */
466 * If there was a problem, clean up the mess we've made
469 if (!noerr) {
471 _freedgrptabent(ent);
472 ent = NULL;
474 } /* if (noerr) */
476 } else noerr = FALSE; /* if (malloc(dgrptabent space)) */
478 /* Finished */
479 return (ent);
483 * int _putdgrptabrec(stream, rec)
484 * FILE *stream
485 * struct dgrptabent *rec
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>.
491 * Arguments:
492 * stream The stream to write to
493 * rec The structure containing the information to write
495 * Returns: int
496 * The number of characters written or EOF if there was some error.
500 _putdgrptabrec(
501 FILE *stream, /* Stream to write to */
502 struct dgrptabent *rec) /* Record to write */
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 */
513 /* Comment or data record? */
514 if (rec->comment)
515 count = fputs(rec->dataspace, stream);
516 else {
519 * Record is a data record
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 */
533 /* Alloc space for the record */
534 if (buf = malloc((size_t) size+1)) {
536 /* Initializations */
537 p = buf;
539 /* Write the device-group name */
540 q = rec->name;
541 while (*q) *p++ = *q++;
542 *p++ = ':';
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);
551 /* Terminate the record */
552 *p++ = '\n';
553 *p = '\0';
555 /* Write the record */
556 count = fputs(buf, stream);
557 free(buf);
558 } else
559 count = EOF; /* malloc() failed */
562 /* Finished */
563 return (count);
567 * int _adddgrptabrec(dgrp, members)
568 * char *dgrp
569 * char **members
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.
577 * If <dgrp> already exists in the table, the function adds the
578 * members in the <members> list to the group's membership.
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).
587 * Returns: int
588 * TRUE if successful, FALSE with "errno" set otherwise.
592 _adddgrptabrec(
593 char *dgrp, /* Devgrp to add to the table */
594 char **members) /* Members for that devgrp */
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 */
607 /* Make a structure describing the new information */
608 if ((new = mkdgrptabent(dgrp, members)) == NULL)
609 return (FALSE);
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.
616 if (!lkdgrptab("a+", F_WRLCK)) {
617 _freedgrptabent(new);
618 return (FALSE);
622 * If the device-group is already in the table, add
623 * the specified members
626 noerr = TRUE;
627 olderrno = errno;
628 if (ent = _getdgrprec(dgrp)) {
630 /* Any members to add? If not, do nothing. */
631 if (new->membership) {
633 /* Any existing members? */
634 if ((pm = ent->membership) != NULL) {
636 /* Find the end of the existing membership list */
637 while (pm->next) pm = pm->next;
639 /* Append the new members to the membership list */
640 pm->next = new->membership;
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;
653 } else ent->membership = new->membership;
655 /* No members in the new list any more */
656 new->membership = NULL;
659 * Make a new device-group table, replacing the
660 * record for the specified device-group
663 _setdgrptab(); /* Rewind existing table */
665 /* Open a temp file */
666 if (fd = opennewdgrptab(&path)) {
668 /* While there's more records and no error ... */
669 while (((p = _getdgrptabent()) != NULL) && noerr) {
672 * If this isn't the record we're replacing,
673 * write it to the temporary file. Otherwise,
674 * write the updated record
677 if (ent->entryno != p->entryno)
678 noerr = _putdgrptabrec(fd, p) != EOF;
679 else noerr = _putdgrptabrec(fd, ent) != EOF;
680 _freedgrptabent(p);
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);
691 } /* if (opennewdgrptab()) */
693 } /* If there's members to add */
695 /* Free the memory associated with the updated entry */
696 _freedgrptabent(ent);
700 * Otherwise, add the device-group to the end of the table
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;
709 /* Finished */
710 (void) unlkdgrptab(); /* Unlock the file */
711 _freedgrptabent(new); /* Free the new dgrptab info struct */
712 return (noerr); /* Return with success indicator */
716 * int _rmdgrptabrec(dgrp)
717 * char *dgrp
719 * This function removes the record in the device-group table
720 * for the specified device-group.
722 * Arguments:
723 * dgrp The device-group to be removed
725 * Returns: int
726 * Success indicator: TRUE if successful, FALSE with errno set otherwise.
730 _rmdgrptabrec(char *dgrp) /* Device-group to remove */
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 */
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);
750 if (noerr) {
751 (void) fclose(fd);
752 noerr = mknewdgrptab(path);
753 } else {
754 (void) fclose(fd);
755 (void) rmnewdgrptab(path);
757 } else noerr = FALSE;
758 _freedgrptabent(ent);
759 } else noerr = FALSE;
760 (void) unlkdgrptab();
761 return (noerr);
765 * int _rmdgrpmems(dgrp, mems, notfounds)
766 * char *dgrp
767 * char **mems
768 * char ***notfounds
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>.
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
783 * Returns: int
784 * TRUE if successful, FALSE with errno set otherwise.
788 _rmdgrpmems(
789 char *dgrp, /* Device-group to modify */
790 char **mems, /* Members to remove */
791 char ***notfounds) /* Members req'd but not found */
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 */
807 noerr = TRUE;
809 /* Lock the device-group table */
810 if (!lkdgrptab("r", F_WRLCK))
811 return (FALSE);
813 /* Nothing is "not found" yet */
814 *notfounds = NULL;
816 /* Get the entry we're to modify */
817 if (ent = _getdgrprec(dgrp)) {
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;
828 /* For each member to remove ... (if any) */
829 if (mems)
830 for (pp = mems; *pp; pp++) {
832 found = FALSE;
834 /* Compare against each member in the membership list */
835 pm = ent->membership;
836 prev = NULL;
837 while (pm && !found) {
839 if (strcmp(*pp, pm->name) == 0) {
841 /* Found. Remove from linked list */
842 if (prev) prev->next = pm->next;
843 else ent->membership = pm->next;
844 free(pm->name);
845 free(pm);
846 found = TRUE;
848 } else {
850 /* Bump to the next member */
851 prev = pm;
852 pm = pm->next;
856 } /* For each member in the group */
859 * If the requested member-to-remove wasn't found,
860 * add it to the list of not-found members
862 if (!found) {
863 if (*pnf = malloc(strlen(*pp)+1)) {
864 (void) strcpy(*pnf++, *pp);
865 *pnf = NULL;
866 } else noerr = FALSE;
869 } /* for (each requested member to remove */
871 _setdgrptab(); /* Rewind existing table */
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);
880 if (noerr) {
881 (void) fclose(fd);
882 noerr = mknewdgrptab(path);
883 } else {
884 (void) fclose(fd);
885 (void) rmnewdgrptab(path);
887 } else noerr = FALSE; /* if (opennewdgrptab()) */
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
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;
904 } else noerr = FALSE;
906 /* Free the description of the modified device group */
907 _freedgrptabent(ent);
909 } else noerr = FALSE; /* _getdgrprec() failed */
911 /* Unlock the original device-group table */
912 (void) unlkdgrptab();
913 return (noerr);