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
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]
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.
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
49 * Externals Referenced
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>
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"
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)
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>.
114 * pname Pointer to the char * to contain the address of the name
115 * of the temporary 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.
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 */
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)
151 if (fstat64(fd
, &sbuf
) == -1) {
157 /* Get the directory that the device-group table lives in */
158 if (p
= strrchr(oldname
, '/')) {
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
172 if (fp
= fopen(buf
, "w")) {
174 (void) fchmod(fileno(fp
), sbuf
.st_mode
& 0777);
175 (void) fchown(fileno(fp
), sbuf
.st_uid
,
182 /* Free the space containing the dgrptab's name */
186 /* Finished. Return what we've got */
191 * int rmnewdgrptab(tempname)
194 * Unlink the temp dgrptab and free the memory allocated to
195 * contain the name of that file
198 * tempname Name of the temporary file
201 * TRUE if successful, FALSE otherwise
205 rmnewdgrptab(char *tempname
)
210 /* Unlink the temporary file */
211 noerr
= (unlink(tempname
) == 0);
219 * int mknewdgrptab(tempname)
222 * Make the temporary device-group table the new system
226 * tempname Name of the temporary file
229 * TRUE if successful, FALSE otherwise
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.
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 */
255 noerr
= rmnewdgrptab(tempname
);
258 noerr
= FALSE
; /* unlink() failed */
261 /* Free the dgrptab's name */
265 noerr
= FALSE
; /* dgrptabpath() failed */
268 /* Finished. Return success indicator */
273 * int lkdgrptab(o_mode, lktype)
277 * Lock the device-group table for writing. If it isn't available, it
281 * o_mode The open() mode to use when opening the device-group table
282 * lktype The type of lock to apply
285 * TRUE if successful, FALSE with errno set otherwise
290 char *o_mode
, /* Open mode */
291 short lktype
) /* Lock type */
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) */
302 /* Open the device-group table for read/append */
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
313 /* Build the locking structure */
314 lockinfo
.l_type
= lktype
;
315 lockinfo
.l_whence
= 0;
316 lockinfo
.l_start
= 0L;
320 /* Keep on going until we lock the file or an error happens */
321 while ((fcntl(fileno(oam_dgroup
), F_SETLK
, &lockinfo
) == -1) &&
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
332 if (errno
== EACCES
) {
333 if (fcntl(fileno(oam_dgroup
), F_SETLKW
,
338 if (!_opendgrptab(o_mode
))
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();
353 noerr
= FALSE
; /* _opendgrptab() failed */
362 * Unlock the locked device-group table.
367 * Whatever fcntl() returns...
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 */
384 noerr
= (fcntl(fileno(oam_dgroup
), F_SETLK
, &lockinfo
) != -1);
392 * struct dgrptabent *mkdgrptabent(dgroup, 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>.
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()
412 static struct dgrptabent
*
414 char *dgroup
, /* Device-group being created (or modified) */
415 char **members
) /* Members to add to that entry */
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) */
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 */
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
;
459 } else noerr
= FALSE
;
461 } /* End membership processing loop */
463 } else noerr
= FALSE
; /* malloc() failed */
466 * If there was a problem, clean up the mess we've made
471 _freedgrptabent(ent
);
476 } else noerr
= FALSE
; /* if (malloc(dgrptabent space)) */
483 * int _putdgrptabrec(stream, rec)
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>.
492 * stream The stream to write to
493 * rec The structure containing the information to write
496 * The number of characters written or EOF if there was some error.
501 FILE *stream
, /* Stream to write to */
502 struct dgrptabent
*rec
) /* Record to write */
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? */
515 count
= fputs(rec
->dataspace
, stream
);
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
)
526 /* "membername " or "membername\n" */
527 size
+= (int)strlen(mem
->name
) + 1;
528 } while ((mem
= mem
->next
) != NULL
); /* Next attr/val */
530 size
++; /* Count trailing '\n' if empty grp */
533 /* Alloc space for the record */
534 if (buf
= malloc((size_t) size
+1)) {
536 /* Initializations */
539 /* Write the device-group name */
541 while (*q
) *p
++ = *q
++;
544 /* Write the membership list */
545 if ((mem
= rec
->membership
) != NULL
) do {
547 while (*q
) *p
++ = *q
++;
548 if ((mem
= mem
->next
) != NULL
) *p
++ = ',';
551 /* Terminate the record */
555 /* Write the record */
556 count
= fputs(buf
, stream
);
559 count
= EOF
; /* malloc() failed */
567 * int _adddgrptabrec(dgrp, 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
577 * If <dgrp> already exists in the table, the function adds the
578 * members in the <members> list to the group's membership.
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).
588 * TRUE if successful, FALSE with "errno" set otherwise.
593 char *dgrp
, /* Devgrp to add to the table */
594 char **members
) /* Members for that devgrp */
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
)
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);
622 * If the device-group is already in the table, add
623 * the specified members
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
) {
645 while ((rm
= qm
->next
) != NULL
) {
646 if (strcmp(pm
->name
, rm
->name
) == 0) {
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
;
686 noerr
= mknewdgrptab(path
);
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
) {
705 if (fseek(oam_dgroup
, 0, SEEK_END
) == 0)
706 noerr
= (_putdgrptabrec(oam_dgroup
, new) != EOF
);
707 } else noerr
= FALSE
;
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)
719 * This function removes the record in the device-group table
720 * for the specified device-group.
723 * dgrp The device-group to be removed
726 * Success indicator: TRUE if successful, FALSE with errno set otherwise.
730 _rmdgrptabrec(char *dgrp
) /* Device-group to remove */
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 */
740 if (!lkdgrptab("r", F_WRLCK
))
742 if (ent
= _getdgrprec(dgrp
)) {
744 if (fd
= opennewdgrptab(&path
)) {
745 while (((p
= _getdgrptabent()) != NULL
) && noerr
) {
746 if (ent
->entryno
!= p
->entryno
)
747 noerr
= _putdgrptabrec(fd
, p
) != EOF
;
752 noerr
= mknewdgrptab(path
);
755 (void) rmnewdgrptab(path
);
757 } else noerr
= FALSE
;
758 _freedgrptabent(ent
);
759 } else noerr
= FALSE
;
760 (void) unlkdgrptab();
765 * int _rmdgrpmems(dgrp, mems, 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>.
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
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
784 * TRUE if successful, FALSE with errno set otherwise.
789 char *dgrp
, /* Device-group to modify */
790 char **mems
, /* Members to remove */
791 char ***notfounds
) /* Members req'd but not found */
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 */
809 /* Lock the device-group table */
810 if (!lkdgrptab("r", F_WRLCK
))
813 /* Nothing is "not found" yet */
816 /* Get the entry we're to modify */
817 if (ent
= _getdgrprec(dgrp
)) {
819 /* Allocate space for the not-found list */
822 for (pp
= mems
; *pp
; pp
++)
824 if (nflst
= malloc(i
*sizeof (char *))) {
828 /* For each member to remove ... (if any) */
830 for (pp
= mems
; *pp
; pp
++) {
834 /* Compare against each member in the membership list */
835 pm
= ent
->membership
;
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 if (pm
->name
) free(pm
->name
);
850 /* Bump to the next member */
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
863 if (*pnf
= malloc(strlen(*pp
)+1)) {
864 (void) strcpy(*pnf
++, *pp
);
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
;
882 noerr
= mknewdgrptab(path
);
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
)) {
900 for (pnf
= nflst
; *pnf
; pnf
++) free(*pnf
);
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();