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 *
opennewdgrptab(char ** pname)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
rmnewdgrptab(char * tempname)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
mknewdgrptab(char * tempname)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
lkdgrptab(char * o_mode,short lktype)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
unlkdgrptab(void)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 *
mkdgrptabent(char * dgroup,char ** members)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
_putdgrptabrec(FILE * stream,struct dgrptabent * rec)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
_adddgrptabrec(char * dgrp,char ** members)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
_rmdgrptabrec(char * dgrp)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
_rmdgrpmems(char * dgrp,char ** mems,char *** notfounds)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