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