summaryrefslogtreecommitdiff
path: root/usr/src/lib/libadm
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/lib/libadm
downloadillumos-gate-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/lib/libadm')
-rw-r--r--usr/src/lib/libadm/Makefile52
-rw-r--r--usr/src/lib/libadm/Makefile.com60
-rw-r--r--usr/src/lib/libadm/amd64/Makefile32
-rw-r--r--usr/src/lib/libadm/common/ckdate.c451
-rw-r--r--usr/src/lib/libadm/common/ckgid.c196
-rw-r--r--usr/src/lib/libadm/common/ckint.c129
-rw-r--r--usr/src/lib/libadm/common/ckitem.c597
-rw-r--r--usr/src/lib/libadm/common/ckkeywd.c118
-rw-r--r--usr/src/lib/libadm/common/ckpath.c321
-rw-r--r--usr/src/lib/libadm/common/ckrange.c151
-rw-r--r--usr/src/lib/libadm/common/ckstr.c187
-rw-r--r--usr/src/lib/libadm/common/cktime.c388
-rw-r--r--usr/src/lib/libadm/common/ckuid.c196
-rw-r--r--usr/src/lib/libadm/common/ckyorn.c116
-rw-r--r--usr/src/lib/libadm/common/data.c51
-rw-r--r--usr/src/lib/libadm/common/devattr.c181
-rw-r--r--usr/src/lib/libadm/common/devreserv.c1162
-rw-r--r--usr/src/lib/libadm/common/devtab.c1057
-rw-r--r--usr/src/lib/libadm/common/dgrpent.c661
-rw-r--r--usr/src/lib/libadm/common/fulldevnm.c489
-rw-r--r--usr/src/lib/libadm/common/getdev.c1095
-rw-r--r--usr/src/lib/libadm/common/getdgrp.c494
-rw-r--r--usr/src/lib/libadm/common/getinput.c65
-rw-r--r--usr/src/lib/libadm/common/getvol.c476
-rw-r--r--usr/src/lib/libadm/common/listdev.c213
-rw-r--r--usr/src/lib/libadm/common/listdgrp.c169
-rw-r--r--usr/src/lib/libadm/common/llib-ladm35
-rw-r--r--usr/src/lib/libadm/common/pkginfo.c600
-rw-r--r--usr/src/lib/libadm/common/pkgnmchk.c169
-rw-r--r--usr/src/lib/libadm/common/pkgparam.c451
-rw-r--r--usr/src/lib/libadm/common/putdev.c1324
-rw-r--r--usr/src/lib/libadm/common/putdgrp.c901
-rw-r--r--usr/src/lib/libadm/common/puterror.c91
-rw-r--r--usr/src/lib/libadm/common/puthelp.c75
-rw-r--r--usr/src/lib/libadm/common/putprmpt.c71
-rw-r--r--usr/src/lib/libadm/common/puttext.c307
-rw-r--r--usr/src/lib/libadm/common/rdwr_vtoc.c162
-rw-r--r--usr/src/lib/libadm/common/regexp.c66
-rw-r--r--usr/src/lib/libadm/common/space.c36
-rw-r--r--usr/src/lib/libadm/i386/Makefile33
-rw-r--r--usr/src/lib/libadm/inc/devtab.h243
-rw-r--r--usr/src/lib/libadm/inc/libadm.h128
-rw-r--r--usr/src/lib/libadm/sparc/Makefile33
-rw-r--r--usr/src/lib/libadm/sparcv9/Makefile34
-rw-r--r--usr/src/lib/libadm/spec/Makefile29
-rw-r--r--usr/src/lib/libadm/spec/Makefile.targ34
-rw-r--r--usr/src/lib/libadm/spec/adm.spec746
-rw-r--r--usr/src/lib/libadm/spec/amd64/Makefile44
-rw-r--r--usr/src/lib/libadm/spec/i386/Makefile44
-rw-r--r--usr/src/lib/libadm/spec/sparc/Makefile44
-rw-r--r--usr/src/lib/libadm/spec/sparcv9/Makefile45
-rw-r--r--usr/src/lib/libadm/spec/versions52
52 files changed, 14904 insertions, 0 deletions
diff --git a/usr/src/lib/libadm/Makefile b/usr/src/lib/libadm/Makefile
new file mode 100644
index 0000000000..e0c1013481
--- /dev/null
+++ b/usr/src/lib/libadm/Makefile
@@ -0,0 +1,52 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 1990,1998-1999,2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#pragma ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libadm/Makefile
+
+include ../Makefile.lib
+
+SUBDIRS= $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET= all
+clean := TARGET= clean
+clobber := TARGET= clobber
+install := TARGET= install
+lint := TARGET= lint
+
+.KEEP_STATE:
+
+all clean clobber install: spec .WAIT $(SUBDIRS)
+
+lint: $(SUBDIRS)
+
+$(SUBDIRS) spec: FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include ../Makefile.targ
diff --git a/usr/src/lib/libadm/Makefile.com b/usr/src/lib/libadm/Makefile.com
new file mode 100644
index 0000000000..3795d0898f
--- /dev/null
+++ b/usr/src/lib/libadm/Makefile.com
@@ -0,0 +1,60 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+LIBRARY= libadm.a
+VERS= .1
+
+OBJECTS= \
+ckdate.o ckgid.o ckint.o ckitem.o ckkeywd.o ckpath.o \
+ckrange.o ckstr.o cktime.o ckuid.o ckyorn.o data.o \
+devattr.o devreserv.o devtab.o dgrpent.o getdev.o getdgrp.o \
+getinput.o getvol.o listdev.o listdgrp.o pkginfo.o \
+pkgnmchk.o pkgparam.o putdev.o putdgrp.o puterror.o puthelp.o \
+putprmpt.o puttext.o rdwr_vtoc.o regexp.o space.o fulldevnm.o
+
+include ../../Makefile.lib
+
+# install this library in the root filesystem
+include ../../Makefile.rootfs
+
+LIBS= $(DYNLIB) $(LINTLIB)
+SRCDIR= ../common
+MAPDIR= ../spec/$(TRANSMACH)
+SPECMAPFILE= $(MAPDIR)/mapfile
+CPPFLAGS += -I ../inc
+
+$(LINTLIB) := SRCS=$(SRCDIR)/$(LINTSRC)
+LDLIBS += -lc
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: lintcheck
+
+include ../../Makefile.targ
diff --git a/usr/src/lib/libadm/amd64/Makefile b/usr/src/lib/libadm/amd64/Makefile
new file mode 100644
index 0000000000..cb39a2beff
--- /dev/null
+++ b/usr/src/lib/libadm/amd64/Makefile
@@ -0,0 +1,32 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
diff --git a/usr/src/lib/libadm/common/ckdate.c b/usr/src/lib/libadm/common/ckdate.c
new file mode 100644
index 0000000000..e2b987990e
--- /dev/null
+++ b/usr/src/lib/libadm/common/ckdate.c
@@ -0,0 +1,451 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright (c) 1997,1998 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+/*LINTLIBRARY*/
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <limits.h>
+#include "libadm.h"
+
+static int fmtcheck(char *);
+
+#define MSGSIZ 64
+#define PROMPT "Enter the date"
+#define MESG "Please enter a date"
+#define DEFAULT "%m/%d/%y"
+
+static char *p_ndigit(char *, int *, int);
+static char *p_date(char *, int, int, int);
+static char *p_eday(char *, int, int);
+static char *p_dlm(char *, char);
+
+#define MLIM 9
+#define STDIG 2
+#define LD2 10
+#define LD 01
+#define UD 31
+#define LM 01
+#define UM 12
+/*
+ * All digits are valid for a YY year format
+ * 70-99 refer to the 20th Century
+ * 00-69 refer to the 21st Century
+ */
+#define LY 00
+#define UY 99
+#define LCY 1970
+#define UCY 9999
+#define CCYY 4
+#define DELIM1 '/'
+#define DELIM2 '-'
+#define BLANK ' '
+#define TAB ' '
+
+static void
+setmsg(char *msg, char *fmt)
+{
+ if ((fmt == NULL) || strcmp(fmt, "%D") == 0)
+ fmt = "%m/%d/%y";
+ (void) sprintf(msg, "%s. Format is <%s>.", MESG, fmt);
+}
+
+static char *
+p_ndigit(char *string, int *value, int n)
+{
+ char *ptr;
+ int accum = 0;
+
+ if (!string)
+ return (NULL);
+ for (ptr = string; *ptr && n > 0; n--, ptr++) {
+ if (! isdigit((unsigned char)*ptr))
+ return (NULL);
+ accum = (10 * accum) + (*ptr - '0');
+ }
+ if (n)
+ return (NULL);
+ *value = accum;
+ return (ptr);
+}
+
+static char *
+p_date(char *string, int llim, int ulim, int ndig)
+{
+ char *ptr;
+ int begin = -1;
+
+ if (!(ptr = p_ndigit(string, &begin, ndig)))
+ return (NULL);
+ if (begin >= llim && begin <= ulim)
+ return (ptr);
+ else
+ return (NULL);
+}
+
+static char *
+p_eday(char *string, int llim, int ulim)
+{
+ char *ptr, *copy;
+ char daynum[3];
+ int begin = -1;
+ int iday = 0;
+ int idaymax = 2;
+
+ daynum[0] = '\0';
+ if (*string == BLANK) {
+ string++;
+ idaymax--;
+ }
+ copy = string;
+ while (isdigit((unsigned char)*copy) && (iday < idaymax)) {
+ daynum[iday] = *copy++;
+ iday++;
+ }
+ daynum[iday] = '\0';
+ if (iday == 1) {
+ llim = 1;
+ ulim = 9;
+ } else if (iday == 2) {
+ llim = 10;
+ ulim = 31;
+ }
+ if (iday == 0)
+ return (NULL);
+
+ if (!(ptr = p_ndigit(string, &begin, iday)))
+ return (NULL);
+
+ if (begin >= llim && begin <= ulim)
+ return (ptr);
+ else
+ return (NULL);
+}
+
+/* p_month will parse the string for the month - abbr. form i.e. JAN - DEC */
+
+static char *
+p_month(char *string, char mnabr)
+{
+ static char *fmonth[] = {
+ "JANUARY", "FEBRUARY", "MARCH", "APRIL",
+ "MAY", "JUNE", "JULY", "AUGUST",
+ "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER"
+ };
+ static char *amonth[] = {
+ "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
+ "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"
+ };
+ int ichng, icnt;
+ char *mnth[12];
+ char *copy;
+ char mletter[MLIM];
+ int mlen;
+ int imnth = 0;
+ int legit = 0;
+ int n = 0;
+
+ if (mnabr == 'a') {
+ mlen = 3;
+ for (icnt = 0; icnt < 12; icnt++)
+ mnth[icnt] = amonth[icnt];
+ } else {
+ mlen = 9;
+ for (icnt = 0; icnt < 12; icnt++)
+ mnth[icnt] = fmonth[icnt];
+ }
+
+ copy = string;
+
+ while (((islower((unsigned char)*copy)) ||
+ (isupper((unsigned char)*copy))) && (imnth < mlen)) {
+ mletter[imnth] = toupper((unsigned char)*copy++);
+ imnth++;
+ }
+ mletter[imnth] = '\0';
+ while (!(legit) && (n < 12)) {
+ if (strncmp(mletter, mnth[n],
+ (imnth = (int)strlen(mnth[n]))) == 0)
+ legit = 1; /* found legitimate string */
+ n++;
+ }
+ if (legit) {
+ for (ichng = 0; ichng < imnth; ichng++) {
+ *string = toupper((unsigned char)*string);
+ string++;
+ }
+
+ return (string);
+ /*
+ * I know this causes side effects, but it's less
+ * code than adding in a copy for string and using that
+ */
+ } else
+ return (NULL);
+}
+
+static char *
+p_dlm(char *string, char dchoice)
+{
+ char dlm;
+
+
+ if (! string)
+ return (NULL);
+ (void) sscanf(string, "%1c", &dlm);
+ if (dchoice == '/')
+ return (((dlm == DELIM1) || (dlm == DELIM2)) ? string+1 : NULL);
+ else
+ return ((dlm == dchoice) ? string + 1 : NULL);
+}
+
+int
+ckdate_err(char *fmt, char *error)
+{
+ char defmesg[MSGSIZ];
+
+ if ((fmt != NULL) && (fmtcheck(fmt) == 1))
+ return (4);
+ setmsg(defmesg, fmt);
+ puterror(stdout, defmesg, error);
+ return (0);
+}
+
+int
+ckdate_hlp(char *fmt, char *help)
+{
+ char defmesg[MSGSIZ];
+
+ if ((fmt != NULL) && (fmtcheck(fmt) == 1))
+ return (4);
+ setmsg(defmesg, fmt);
+ puthelp(stdout, defmesg, help);
+ return (0);
+}
+
+/*
+ * A little state machine that checks out the format to
+ * make sure it is acceptable.
+ * return value 1: NG
+ * return value 0: OK
+ */
+static int
+fmtcheck(char *fmt)
+{
+ int percent = 0;
+
+ while (*fmt) {
+ switch (*fmt++) {
+ case '%': /* previous state must be start or letter */
+ if (percent == 0)
+ percent = 1;
+ else
+ return (1);
+ break;
+ case 'd': /* previous state must be "%" */
+ case 'e':
+ case 'm':
+ case 'y':
+ case 'Y':
+ case 'D':
+ case 'h':
+ case 'b':
+ case 'B':
+ if (percent == 1)
+ percent = 0;
+ else
+ return (1);
+ break;
+ case TAB: /* previous state must be start or letter */
+ case BLANK:
+ case DELIM1:
+ case DELIM2:
+ if (percent == 1)
+ return (1);
+ break;
+ default:
+ return (1);
+ }
+ }
+ return (percent);
+}
+
+int
+ckdate_val(char *fmt, char *input)
+{
+ char ltrl, dfl;
+ int valid = 1; /* time of day string is valid for format */
+
+ if ((fmt != NULL) && (fmtcheck(fmt) == 1))
+ return (4);
+
+ if (fmt == NULL)
+ fmt = DEFAULT;
+ ltrl = '\0';
+ while (*fmt && valid) {
+ if ((*fmt) == '%') {
+ fmt++;
+ switch (*fmt) {
+ case 'd':
+ input = p_date(input, LD, UD, STDIG);
+ if (!input)
+ valid = 0;
+ break;
+
+ case 'e':
+ input = p_eday(input, LD2, UD);
+ if (!input)
+ valid = 0;
+ break;
+
+ case 'm':
+ input = p_date(input, LM, UM, STDIG);
+ if (!input)
+ valid = 0;
+ break;
+
+ case 'y':
+ input = p_date(input, LY, UY, STDIG);
+ if (!input)
+ valid = 0;
+ break;
+
+ case 'Y':
+ input = p_date(input, LCY, UCY, CCYY);
+ if (!input)
+ valid = 0;
+ break;
+
+ case 'D':
+ input = p_date(input, LM, UM, STDIG);
+ if (!input) {
+ valid = 0;
+ break;
+ }
+ input = p_dlm(input, DELIM1);
+ if (!input) {
+ valid = 0;
+ break;
+ }
+ input = p_date(input, LD, UD, STDIG);
+ if (!input) {
+ valid = 0;
+ break;
+ }
+ input = p_dlm(input, DELIM1);
+ if (!input) {
+ valid = 0;
+ break;
+ }
+ input = p_date(input, LY, UY, STDIG);
+ if (!input)
+ valid = 0;
+ break;
+
+ case 'h':
+ case 'b':
+ input = p_month(input, 'a');
+ if (!input)
+ valid = 0;
+ break;
+
+ case 'B':
+ input = p_month(input, 'f');
+ if (!input)
+ valid = 0;
+ break;
+
+ default:
+ (void) sscanf(input, "%1c", &ltrl);
+ input++;
+ }
+ } else {
+ dfl = '\0';
+ (void) sscanf(input, "%1c", &dfl);
+ input++;
+ }
+ fmt++;
+ } /* end of while fmt and valid */
+
+ if ((*fmt == NULL) && ((input != NULL) && *input != 0)) {
+ if (*input != NULL)
+ valid = 0;
+ }
+ return ((valid == 0));
+}
+
+int
+ckdate(char *date, char *fmt, char *defstr, char *error, char *help,
+ char *prompt)
+{
+ char defmesg[MSGSIZ];
+ char input[MAX_INPUT];
+ char *ept, end[128];
+
+ ept = end;
+ *ept = '\0';
+
+ if ((fmt != NULL) && (fmtcheck(fmt) == 1))
+ return (4);
+
+ setmsg(defmesg, fmt);
+ (void) sprintf(ept, "[?,q]");
+
+ if (!prompt)
+ prompt = PROMPT;
+
+start:
+ putprmpt(stderr, prompt, NULL, defstr);
+ if (getinput(input))
+ return (1);
+
+ if (!strlen(input)) {
+ if (defstr) {
+ (void) strcpy(date, defstr);
+ return (0);
+ }
+ puterror(stderr, defmesg, error);
+ goto start;
+ } else if (strcmp(input, "?") == 0) {
+ puthelp(stderr, defmesg, help);
+ goto start;
+ } else if (ckquit && strcmp(input, "q") == 0) {
+ return (3);
+ } else if (ckdate_val(fmt, input)) {
+ puterror(stderr, defmesg, error);
+ goto start;
+ }
+ (void) strcpy(date, input);
+ return (0);
+}
diff --git a/usr/src/lib/libadm/common/ckgid.c b/usr/src/lib/libadm/common/ckgid.c
new file mode 100644
index 0000000000..ee27038bb8
--- /dev/null
+++ b/usr/src/lib/libadm/common/ckgid.c
@@ -0,0 +1,196 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright (c) 1997, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+/*LINTLIBRARY*/
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.2 */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <grp.h>
+#include <sys/types.h>
+#include "libadm.h"
+#include <stdlib.h>
+#include <limits.h>
+
+#define PROMPT "Enter the name of an existing group"
+#define MESG "Please enter the name of an existing group."
+#define ALTMESG "Please enter one of the following group names:\\n\\t"
+#define MALSIZ 64
+
+#define DELIM1 '/'
+#define BLANK ' '
+
+static char *
+setmsg(int disp)
+{
+ struct group
+ *grpptr;
+ int count;
+ size_t n, m;
+ char *msg;
+
+ if (disp == 0)
+ return (MESG);
+
+ m = MALSIZ;
+ n = sizeof (ALTMESG);
+ msg = calloc(m, sizeof (char));
+ (void) strcpy(msg, ALTMESG);
+
+ setgrent();
+ count = 0;
+ while ((grpptr = getgrent()) != NULL) {
+ n += strlen(grpptr->gr_name) + 2;
+ while (n >= m) {
+ m += MALSIZ;
+ msg = realloc(msg, m*sizeof (char));
+ }
+ if (count++)
+ (void) strcat(msg, ", ");
+ (void) strcat(msg, grpptr->gr_name);
+ }
+ endgrent();
+ return (msg);
+}
+
+int
+ckgid_dsp(void)
+{
+ struct group *grpptr;
+
+ /* if display flag is set, then list out group file */
+ if (ckgrpfile() == 1)
+ return (1);
+ setgrent();
+ while (grpptr = getgrent())
+ (void) printf("%s\n", grpptr->gr_name);
+ endgrent();
+ return (0);
+}
+
+int
+ckgid_val(char *grpnm)
+{
+ int valid;
+
+ setgrent();
+ valid = (getgrnam(grpnm) ? 0 : 1);
+ endgrent();
+ return (valid);
+}
+
+int
+ckgrpfile(void) /* check to see if group file there */
+{
+ struct group *grpptr;
+
+ setgrent();
+ grpptr = getgrent();
+ if (!grpptr) {
+ endgrent();
+ return (1);
+ }
+ endgrent();
+ return (0);
+}
+
+void
+ckgid_err(int disp, char *error)
+{
+ char *msg;
+
+ msg = setmsg(disp);
+ puterror(stdout, msg, error);
+ if (disp)
+ free(msg);
+}
+
+void
+ckgid_hlp(int disp, char *help)
+{
+ char *msg;
+
+ msg = setmsg(disp);
+ puthelp(stdout, msg, help);
+ if (disp)
+ free(msg);
+}
+
+int
+ckgid(char *gid, short disp, char *defstr, char *error, char *help,
+ char *prompt)
+{
+ char *defmesg,
+ input[MAX_INPUT];
+
+ defmesg = NULL;
+ if (!prompt)
+ prompt = PROMPT;
+
+start:
+ putprmpt(stderr, prompt, NULL, defstr);
+ if (getinput(input)) {
+ if (disp && defmesg)
+ free(defmesg);
+ return (1);
+ }
+
+ if (!strlen(input)) {
+ if (defstr) {
+ if (disp && defmesg)
+ free(defmesg);
+ (void) strcpy(gid, defstr);
+ return (0);
+ }
+ if (!defmesg)
+ defmesg = setmsg(disp);
+ puterror(stderr, defmesg, error);
+ goto start;
+ } else if (strcmp(input, "?") == 0) {
+ if (!defmesg)
+ defmesg = setmsg(disp);
+ puthelp(stderr, defmesg, help);
+ goto start;
+ } else if (ckquit && (strcmp(input, "q") == 0)) {
+ if (disp && defmesg)
+ free(defmesg);
+ return (3);
+ } else if (ckgid_val(input)) {
+ if (!defmesg)
+ defmesg = setmsg(disp);
+ puterror(stderr, defmesg, error);
+ goto start;
+ }
+ (void) strcpy(gid, input);
+ if (disp && defmesg)
+ free(defmesg);
+ return (0);
+}
diff --git a/usr/src/lib/libadm/common/ckint.c b/usr/src/lib/libadm/common/ckint.c
new file mode 100644
index 0000000000..e7121b3b02
--- /dev/null
+++ b/usr/src/lib/libadm/common/ckint.c
@@ -0,0 +1,129 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright (c) 1997, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+/*LINTLIBRARY*/
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.3 */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <sys/types.h>
+#include "libadm.h"
+
+static void
+setmsg(char *msg, short base)
+{
+ if ((base == 0) || (base == 10))
+ (void) sprintf(msg, "Please enter an integer.");
+ else
+ (void) sprintf(msg, "Please enter a base %d integer.", base);
+}
+
+static void
+setprmpt(char *prmpt, short base)
+{
+ if ((base == 0) || (base == 10))
+ (void) sprintf(prmpt, "Enter an integer.");
+ else
+ (void) sprintf(prmpt, "Enter a base %d integer.", base);
+}
+
+int
+ckint_val(char *value, short base)
+{
+ char *ptr;
+
+ (void) strtol(value, &ptr, (int)base);
+ if (*ptr == '\0')
+ return (0);
+ return (1);
+}
+
+void
+ckint_err(short base, char *error)
+{
+ char defmesg[64];
+
+ setmsg(defmesg, base);
+ puterror(stdout, defmesg, error);
+}
+
+void
+ckint_hlp(short base, char *help)
+{
+ char defmesg[64];
+
+ setmsg(defmesg, base);
+ puthelp(stdout, defmesg, help);
+}
+
+int
+ckint(long *intval, short base, char *defstr, char *error, char *help,
+ char *prompt)
+{
+ long value;
+ char *ptr,
+ input[MAX_INPUT],
+ defmesg[64],
+ temp[64];
+
+ if (!prompt) {
+ setprmpt(temp, base);
+ prompt = temp;
+ }
+ setmsg(defmesg, base);
+
+start:
+ putprmpt(stderr, prompt, NULL, defstr);
+ if (getinput(input))
+ return (1);
+
+ if (strlen(input) == 0) {
+ if (defstr) {
+ *intval = strtol(defstr, NULL, (int)base);
+ return (0);
+ }
+ puterror(stderr, defmesg, error);
+ goto start;
+ } else if (strcmp(input, "?") == 0) {
+ puthelp(stderr, defmesg, help);
+ goto start;
+ } else if (ckquit && (strcmp(input, "q") == 0))
+ return (3);
+
+ value = strtol(input, &ptr, (int)base);
+ if (*ptr != '\0') {
+ puterror(stderr, defmesg, error);
+ goto start;
+ }
+ *intval = value;
+ return (0);
+}
diff --git a/usr/src/lib/libadm/common/ckitem.c b/usr/src/lib/libadm/common/ckitem.c
new file mode 100644
index 0000000000..8835f6b23b
--- /dev/null
+++ b/usr/src/lib/libadm/common/ckitem.c
@@ -0,0 +1,597 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.4 */
+/*LINTLIBRARY*/
+
+#include <stdio.h>
+#include <ctype.h>
+#include <limits.h>
+#include "valtools.h"
+#include <sys/types.h>
+#include <stdlib.h>
+#include <strings.h>
+#include "libadm.h"
+
+static int insert(struct _choice_ *, CKMENU *);
+static char *strtoki(char *, char *);
+static char **match(CKMENU *, char *, int);
+static int getstr(char *, char *, char *, char *, char *);
+static int getnum(char *, int, int *, int *);
+static struct _choice_ *next(struct _choice_ *);
+
+static char *deferr;
+static char *errmsg;
+static char *defhlp;
+
+#define PROMPT "Enter selection"
+#define MESG0 "Entry does not match available menu selection. "
+#define MESG1 "the number of the menu item you wish to select, or "
+#define MESG2 "the token which is associated with the menu item,\
+ or a partial string which uniquely identifies the \
+ token for the menu item. Enter ?? to reprint the menu."
+
+#define TOOMANY "Too many items selected from menu"
+#define NOTUNIQ "The entered text does not uniquely identify a menu choice."
+#define BADNUM "Bad numeric choice specification"
+
+static char *
+setmsg(CKMENU *menup, short flag)
+{
+ int n;
+ char *msg;
+
+ n = (int)(6 + sizeof (MESG2));
+ if (flag)
+ n += (int)(sizeof (MESG0));
+
+ if (menup->attr & CKUNNUM) {
+ msg = calloc((size_t)n, sizeof (char));
+ if (flag)
+ (void) strcpy(msg, MESG0);
+ else
+ msg[0] = '\0';
+ (void) strcat(msg, "Enter ");
+ (void) strcat(msg, MESG2);
+ } else {
+ msg = calloc(n+sizeof (MESG1), sizeof (char));
+ if (flag)
+ (void) strcpy(msg, MESG0);
+ else
+ msg[0] = '\0';
+ (void) strcat(msg, "Enter ");
+ (void) strcat(msg, MESG1);
+ (void) strcat(msg, MESG2);
+ }
+ return (msg);
+}
+
+CKMENU *
+allocmenu(char *label, int attr)
+{
+ CKMENU *pt;
+
+ if (pt = calloc(1, sizeof (CKMENU))) {
+ pt->attr = attr;
+ pt->label = label;
+ }
+ return (pt);
+}
+
+void
+ckitem_err(CKMENU *menup, char *error)
+{
+ deferr = setmsg(menup, 1);
+ puterror(stdout, deferr, error);
+ free(deferr);
+}
+
+void
+ckitem_hlp(CKMENU *menup, char *help)
+{
+ defhlp = setmsg(menup, 0);
+ puthelp(stdout, defhlp, help);
+ free(defhlp);
+}
+
+int
+ckitem(CKMENU *menup, char *item[], short max, char *defstr, char *error,
+ char *help, char *prompt)
+{
+ int n, i;
+ char strval[MAX_INPUT];
+ char **list;
+
+ if ((menup->nchoices <= 0) && !menup->invis)
+ return (4); /* nothing to choose from */
+
+ if (menup->attr & CKONEFLAG) {
+ if (((n = menup->nchoices) <= 1) && menup->invis) {
+ for (i = 0; menup->invis[i]; ++i)
+ n++;
+ }
+ if (n <= 1) {
+ if (menup->choice)
+ item[0] = menup->choice->token;
+ else if (menup->invis)
+ item[0] = menup->invis[0];
+ item[1] = NULL;
+ return (0);
+ }
+ }
+
+ if (max < 1)
+ max = menup->nchoices;
+
+ if (!prompt)
+ prompt = PROMPT;
+ defhlp = setmsg(menup, 0);
+ deferr = setmsg(menup, 1);
+
+reprint:
+ printmenu(menup);
+
+start:
+ if (n = getstr(strval, defstr, error, help, prompt)) {
+ free(defhlp);
+ free(deferr);
+ return (n);
+ }
+ if (strcmp(strval, "??") == 0) {
+ goto reprint;
+ }
+ if ((defstr) && (strcmp(strval, defstr) == 0)) {
+ item[0] = defstr;
+ item[1] = NULL;
+ } else {
+ list = match(menup, strval, (int)max);
+ if (!list) {
+ puterror(stderr, deferr, (errmsg ? errmsg : error));
+ goto start;
+ }
+ for (i = 0; (i < max); i++)
+ item[i] = list[i];
+ free(list);
+ }
+ free(defhlp);
+ free(deferr);
+ return (0);
+}
+
+static int
+getnum(char *strval, int max, int *begin, int *end)
+{
+ int n;
+ char *pt;
+
+ *begin = *end = 0;
+ pt = strval;
+ for (;;) {
+ if (*pt == '$') {
+ n = max;
+ pt++;
+ } else {
+ n = (int)strtol(pt, &pt, 10);
+ if ((n <= 0) || (n > max))
+ return (1);
+ }
+ while (isspace((unsigned char)*pt))
+ pt++;
+
+ if (!*begin && (*pt == '-')) {
+ *begin = n;
+ pt++;
+ while (isspace((unsigned char)*pt))
+ pt++;
+ continue;
+ } else if (*pt) {
+ return (1); /* wasn't a number, or an invalid one */
+ } else if (*begin) {
+ *end = n;
+ break;
+ } else {
+ *begin = n;
+ break;
+ }
+ }
+ if (!*end)
+ *end = *begin;
+ return ((*begin <= *end) ? 0 : 1);
+}
+
+static char **
+match(CKMENU *menup, char *strval, int max)
+{
+ struct _choice_ *chp;
+ char **choice;
+ int begin, end;
+ char *pt, *found;
+ int i, len, nchoice;
+
+ nchoice = 0;
+ choice = calloc((size_t)max, sizeof (char *));
+
+ do {
+ if (pt = strpbrk(strval, " \t,")) {
+ do {
+ *pt++ = '\0';
+ } while (strchr(" \t,", *pt));
+ }
+
+ if (nchoice >= max) {
+ errmsg = TOOMANY;
+ return (NULL);
+ }
+ if (!(menup->attr & CKUNNUM) &&
+ isdigit((unsigned char)*strval)) {
+ if (getnum(strval, (int)menup->nchoices, &begin,
+ &end)) {
+ errmsg = BADNUM;
+ return (NULL);
+ }
+ chp = menup->choice;
+ for (i = 1; chp; i++) {
+ if ((i >= begin) && (i <= end)) {
+ if (nchoice >= max) {
+ errmsg = TOOMANY;
+ return (NULL);
+ }
+ choice[nchoice++] = chp->token;
+ }
+ chp = chp->next;
+ }
+ continue;
+ }
+
+ found = NULL;
+ chp = menup->choice;
+ for (i = 0; chp; i++) {
+ len = (int)strlen(strval);
+ if (strncmp(chp->token, strval, (size_t)len) == 0) {
+ if (chp->token[len] == '\0') {
+ found = chp->token;
+ break;
+ } else if (found) {
+ errmsg = NOTUNIQ;
+ return (NULL); /* not unique */
+ }
+ found = chp->token;
+ }
+ chp = chp->next;
+ }
+
+ if (menup->invis) {
+ for (i = 0; menup->invis[i]; ++i) {
+ len = (int)strlen(strval);
+ if (strncmp(menup->invis[i], strval,
+ (size_t)len) == 0) {
+#if _3b2
+ if (chp->token[len] == '\0') {
+#else
+ if (menup->invis[i][len] == '\0') {
+#endif
+ found = menup->invis[i];
+ break;
+ } else if (found) {
+ errmsg = NOTUNIQ;
+ return (NULL);
+ }
+ found = menup->invis[i];
+ }
+ }
+ }
+ if (found) {
+ choice[nchoice++] = found;
+ continue;
+ }
+ errmsg = NULL;
+ return (NULL);
+ } while (((strval = pt) != NULL) && *pt);
+ return (choice);
+}
+
+int
+setitem(CKMENU *menup, char *choice)
+{
+ struct _choice_ *chp;
+ int n;
+ char *pt;
+
+ if (choice == NULL) {
+ /* request to clear memory usage */
+ chp = menup->choice;
+ while (chp) {
+ struct _choice_ *_chp = chp;
+
+ chp = chp->next;
+ menup->longest = menup->nchoices = 0;
+
+ (void) free(_chp->token); /* free token and text */
+ (void) free(_chp);
+ }
+ return (1);
+ }
+
+ if ((chp = calloc(1, sizeof (struct _choice_))) == NULL)
+ return (1);
+
+ if ((pt = strdup(choice)) == NULL) {
+ free(chp);
+ return (1);
+ }
+ if (!*pt || isspace((unsigned char)*pt)) {
+ free(chp);
+ return (2);
+ }
+
+ chp->token = strtoki(pt, " \t\n");
+ chp->text = strtoki(NULL, "");
+
+ if (chp->text) {
+ while (isspace((unsigned char)*chp->text))
+ chp->text++;
+ }
+ n = (int)strlen(chp->token);
+ if (n > menup->longest)
+ menup->longest = (short)n;
+
+ if (insert(chp, menup))
+ menup->nchoices++;
+ else
+ free(chp); /* duplicate entry */
+ return (0);
+}
+
+int
+setinvis(CKMENU *menup, char *choice)
+{
+ int index;
+
+ index = 0;
+ if (choice == NULL) {
+ if (menup->invis == NULL)
+ return (0);
+ while (menup->invis[index])
+ free(menup->invis[index]);
+ free(menup->invis);
+ return (0);
+ }
+
+ if (menup->invis == NULL)
+ menup->invis = calloc(2, sizeof (char *));
+ else {
+ while (menup->invis[index])
+ index++; /* count invisible choices */
+ menup->invis = realloc(menup->invis,
+ (index+2)* sizeof (char *));
+ menup->invis[index+1] = NULL;
+ }
+ if (!menup->invis)
+ return (-1);
+ menup->invis[index] = strdup(choice);
+ return (0);
+}
+
+static int
+insert(struct _choice_ *chp, CKMENU *menup)
+{
+ struct _choice_ *last, *base;
+ int n;
+
+ base = menup->choice;
+ last = NULL;
+
+ if (!(menup->attr & CKALPHA)) {
+ while (base) {
+ if (strcmp(base->token, chp->token) == 0)
+ return (0);
+ last = base;
+ base = base->next;
+ }
+ if (last)
+ last->next = chp;
+ else
+ menup->choice = chp;
+ return (1);
+ }
+
+ while (base) {
+ if ((n = strcmp(base->token, chp->token)) == 0)
+ return (0);
+ if (n > 0) {
+ /* should come before this one */
+ break;
+ }
+ last = base;
+ base = base->next;
+ }
+ if (last) {
+ chp->next = last->next;
+ last->next = chp;
+ } else {
+ chp->next = menup->choice;
+ menup->choice = chp;
+ }
+ return (1);
+}
+
+void
+printmenu(CKMENU *menup)
+{
+ int i;
+ struct _choice_ *chp;
+ char *pt;
+ char format[16];
+ int c;
+
+ (void) fputc('\n', stderr);
+ if (menup->label) {
+ (void) puttext(stderr, menup->label, 0, 0);
+ (void) fputc('\n', stderr);
+ }
+ (void) sprintf(format, "%%-%ds", menup->longest+5);
+
+ (void) next(NULL);
+ chp = ((menup->attr & CKALPHA) ? next(menup->choice) : menup->choice);
+ for (i = 1; chp; ++i) {
+ if (!(menup->attr & CKUNNUM))
+ (void) fprintf(stderr, "%3d ", i);
+ (void) fprintf(stderr, format, chp->token);
+ if (chp->text) {
+ /* there is text associated with the token */
+ pt = chp->text;
+ while (*pt) {
+ (void) fputc(*pt, stderr);
+ if (*pt++ == '\n') {
+ if (!(menup->attr & CKUNNUM))
+ (void) fprintf(stderr,
+ "%5s", "");
+ (void) fprintf(stderr, format, "");
+ while (isspace((unsigned char)*pt))
+ ++pt;
+ }
+ }
+ }
+ (void) fputc('\n', stderr);
+ chp = ((menup->attr & CKALPHA) ?
+ next(menup->choice) : chp->next);
+ if (chp && ((i % 10) == 0)) {
+ /* page the choices */
+ (void) fprintf(stderr,
+ "\n... %d more menu choices to follow;",
+ menup->nchoices - i);
+ (void) fprintf(stderr,
+ /* CSTYLED */
+ "\n<RETURN> for more choices, <CTRL-D> to stop \
+display:");
+ /* ignore other chars */
+ while (((c = getc(stdin)) != EOF) && (c != '\n'))
+ ;
+ (void) fputc('\n', stderr);
+ if (c == EOF)
+ break; /* stop printing menu */
+ }
+ }
+}
+
+static int
+getstr(char *strval, char *defstr, char *error, char *help, char *prompt)
+{
+ char input[MAX_INPUT];
+ char *ept, end[MAX_INPUT];
+
+ *(ept = end) = '\0';
+ if (defstr) {
+ (void) sprintf(ept, "(default: %s) ", defstr);
+ ept += strlen(ept);
+ }
+ if (ckquit) {
+ (void) strcat(ept, "[?,??,q]");
+ } else {
+ (void) strcat(ept, "[?,??]");
+ }
+
+start:
+ (void) fputc('\n', stderr);
+ (void) puttext(stderr, prompt, 0, 0);
+ (void) fprintf(stderr, " %s: ", end);
+
+ if (getinput(input))
+ return (1);
+
+ if (strlen(input) == 0) {
+ if (defstr) {
+ (void) strcpy(strval, defstr);
+ return (0);
+ }
+ puterror(stderr, deferr, (errmsg ? errmsg : error));
+ goto start;
+ } else if (strcmp(input, "?") == 0) {
+ puthelp(stderr, defhlp, help);
+ goto start;
+ } else if (ckquit && (strcmp(input, "q") == 0)) {
+ /* (void) strcpy(strval, input); */
+ return (3);
+ }
+ (void) strcpy(strval, input);
+ return (0);
+}
+
+static struct _choice_ *
+next(struct _choice_ *chp)
+{
+ static char *last;
+ static char *first;
+ struct _choice_ *found;
+
+ if (!chp) {
+ last = NULL;
+ return (NULL);
+ }
+
+ found = NULL;
+ for (first = NULL; chp; chp = chp->next) {
+ if (last && strcmp(last, chp->token) >= 0)
+ continue; /* lower than the last one we found */
+
+ if (!first || strcmp(first, chp->token) > 0) {
+ first = chp->token;
+ found = chp;
+ }
+ }
+ last = first;
+ return (found);
+}
+
+static char *
+strtoki(char *string, char *sepset)
+{
+ char *p, *q, *r;
+ static char *savept;
+
+ /* first or subsequent call */
+ p = (string == NULL)? savept: string;
+
+ if (p == NULL) /* return if no tokens remaining */
+ return (NULL);
+
+ q = p + strspn(p, sepset); /* skip leading separators */
+
+ if (*q == '\0') /* return if no tokens remaining */
+ return (NULL);
+
+ if ((r = strpbrk(q, sepset)) == NULL) /* move past token */
+ savept = 0; /* indicate this is last token */
+ else {
+ *r = '\0';
+ savept = ++r;
+ }
+ return (q);
+}
diff --git a/usr/src/lib/libadm/common/ckkeywd.c b/usr/src/lib/libadm/common/ckkeywd.c
new file mode 100644
index 0000000000..093562788f
--- /dev/null
+++ b/usr/src/lib/libadm/common/ckkeywd.c
@@ -0,0 +1,118 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright (c) 1997, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+/*LINTLIBRARY*/
+
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <sys/types.h>
+#include "libadm.h"
+
+static int
+match(char *strval, char *set[])
+{
+ char *found;
+ int i, len;
+
+ len = (int)strlen(strval);
+
+ found = NULL;
+ for (i = 0; set[i]; i++) {
+ if (strncmp(set[i], strval, len) == 0) {
+ if (found)
+ return (-1); /* not unique */
+ found = set[i];
+ }
+ }
+
+ if (found) {
+ (void) strcpy(strval, found);
+ return (0);
+ }
+ return (1);
+}
+
+int
+ckkeywd(char *strval, char *keyword[], char *defstr, char *error, char *help,
+ char *prompt)
+{
+ int valid, i, n;
+ char input[MAX_INPUT];
+ char defmesg[512];
+ char *ept;
+
+ (void) sprintf(defmesg, "Please enter one of the following keywords: ");
+ ept = defmesg + strlen(defmesg);
+ for (i = 0; keyword[i]; ) {
+ if (i)
+ (void) strcat(ept, ", ");
+ (void) strcat(ept, keyword[i++]);
+ }
+ (void) strcat(ept, ckquit ? ", q." : ".");
+
+ if (!prompt)
+ prompt = "Enter appropriate value";
+
+start:
+ putprmpt(stderr, prompt, keyword, defstr);
+ if (getinput(input))
+ return (1);
+
+ n = (int)strlen(input);
+ if (n == 0) {
+ if (defstr) {
+ (void) strcpy(strval, defstr);
+ return (0);
+ }
+ puterror(stderr, defmesg, error);
+ goto start;
+ }
+ if (strcmp(input, "?") == 0) {
+ puthelp(stderr, defmesg, help);
+ goto start;
+ }
+ if (ckquit && (strcmp(input, "q") == 0)) {
+ (void) strcpy(strval, input);
+ return (3);
+ }
+
+ valid = 1;
+ if (keyword)
+ valid = !match(input, keyword);
+
+ if (!valid) {
+ puterror(stderr, defmesg, error);
+ goto start;
+ }
+ (void) strcpy(strval, input);
+ return (0);
+}
diff --git a/usr/src/lib/libadm/common/ckpath.c b/usr/src/lib/libadm/common/ckpath.c
new file mode 100644
index 0000000000..c5ce5b9f15
--- /dev/null
+++ b/usr/src/lib/libadm/common/ckpath.c
@@ -0,0 +1,321 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright (c) 1996-1998, 2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.3 */
+/*LINTLIBRARY*/
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "valtools.h"
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include "libadm.h"
+
+#define E_SYNTAX "does not meet suggested filename syntax standard"
+#define E_READ "is not readable"
+#define E_WRITE "is not writable"
+#define E_EXEC "is not executable"
+#define E_CREAT "cannot be created"
+#define E_ABSOLUTE "must begin with a slash (/)"
+#define E_RELATIVE "must not begin with a slash (/)"
+#define E_EXIST "does not exist"
+#define E_NEXIST "must not already exist"
+#define E_BLK "must specify a block special device"
+#define E_CHR "must specify a character special device"
+#define E_DIR "must specify a directory"
+#define E_REG "must be a regular file"
+#define E_NONZERO "must be a file of non-zero length"
+
+#define H_READ "must be readable"
+#define H_WRITE "must be writable"
+#define H_EXEC "must be executable"
+#define H_CREAT "will be created if it does not exist"
+#define H_ABSOLUTE E_ABSOLUTE
+#define H_RELATIVE E_RELATIVE
+#define H_EXIST "must already exist"
+#define H_NEXIST "must not already exist"
+#define H_BLK E_BLK
+#define H_CHR E_CHR
+#define H_DIR E_DIR
+#define H_REG E_REG
+#define H_NONZERO E_NONZERO
+
+#define MSGSIZ 1024
+#define STDHELP \
+ "A pathname is a filename, optionally preceded by parent directories."
+
+static char *errstr;
+static char *badset = "*?[]{}()<> \t'`\"\\|^";
+
+static void
+addhlp(char *msg, char *text)
+{
+ static int count;
+
+ if (text == NULL) {
+ count = 0;
+ return;
+ }
+ if (!count++)
+ (void) strcat(msg, " The pathname you enter:");
+ (void) strcat(msg, "\\n\\t-\\ ");
+ (void) strcat(msg, text);
+}
+
+static char *
+sethlp(int pflags)
+{
+ char *msg;
+
+ msg = calloc(MSGSIZ, sizeof (char));
+ addhlp(msg, NULL); /* initialize count */
+ (void) strcpy(msg, STDHELP);
+
+ if (pflags & P_EXIST)
+ addhlp(msg, H_EXIST);
+ else if (pflags & P_NEXIST)
+ addhlp(msg, H_NEXIST);
+
+ if (pflags & P_ABSOLUTE)
+ addhlp(msg, H_ABSOLUTE);
+ else if (pflags & P_RELATIVE)
+ addhlp(msg, H_RELATIVE);
+
+ if (pflags & P_READ)
+ addhlp(msg, H_READ);
+ if (pflags & P_WRITE)
+ addhlp(msg, H_WRITE);
+ if (pflags & P_EXEC)
+ addhlp(msg, H_EXEC);
+ if (pflags & P_CREAT)
+ addhlp(msg, H_CREAT);
+
+ if (pflags & P_BLK)
+ addhlp(msg, H_BLK);
+ else if (pflags & P_CHR)
+ addhlp(msg, H_CHR);
+ else if (pflags & P_DIR)
+ addhlp(msg, H_DIR);
+ else if (pflags & P_REG)
+ addhlp(msg, H_REG);
+
+ if (pflags & P_NONZERO)
+ addhlp(msg, H_NONZERO);
+
+ return (msg);
+}
+
+int
+ckpath_stx(int pflags)
+{
+ if (((pflags & P_ABSOLUTE) && (pflags & P_RELATIVE)) ||
+ ((pflags & P_NEXIST) && (pflags &
+ (P_EXIST|P_NONZERO|P_READ|P_WRITE|P_EXEC))) ||
+ ((pflags & P_CREAT) && (pflags & (P_EXIST|P_NEXIST|P_BLK|P_CHR))) ||
+ ((pflags & P_BLK) && (pflags & (P_CHR|P_REG|P_DIR|P_NONZERO))) ||
+ ((pflags & P_CHR) && (pflags & (P_REG|P_DIR|P_NONZERO))) ||
+ ((pflags & P_DIR) && (pflags & P_REG))) {
+ return (1);
+ }
+ return (0);
+}
+
+int
+ckpath_val(char *path, int pflags)
+{
+ struct stat64 status;
+ int fd;
+ char *pt;
+
+ if ((pflags & P_RELATIVE) && (*path == '/')) {
+ errstr = E_RELATIVE;
+ return (1);
+ }
+ if ((pflags & P_ABSOLUTE) && (*path != '/')) {
+ errstr = E_ABSOLUTE;
+ return (1);
+ }
+ if (stat64(path, &status)) {
+ if (pflags & P_EXIST) {
+ errstr = E_EXIST;
+ return (1);
+ }
+ for (pt = path; *pt; pt++) {
+ if (!isprint((unsigned char)*pt) ||
+ strchr(badset, *pt)) {
+ errstr = E_SYNTAX;
+ return (1);
+ }
+ }
+ if (pflags & P_CREAT) {
+ if (pflags & P_DIR) {
+ if ((mkdir(path, 0755)) != 0) {
+ errstr = E_CREAT;
+ return (1);
+ }
+ } else {
+ if ((fd = creat(path, 0644)) < 0) {
+ errstr = E_CREAT;
+ return (1);
+ }
+ (void) close(fd);
+ }
+ }
+ return (0);
+ } else if (pflags & P_NEXIST) {
+ errstr = E_NEXIST;
+ return (1);
+ }
+ if ((status.st_mode & S_IFMT) == S_IFREG) {
+ /* check non zero status */
+ if ((pflags & P_NONZERO) && (status.st_size < 1)) {
+ errstr = E_NONZERO;
+ return (1);
+ }
+ }
+ if ((pflags & P_CHR) && ((status.st_mode & S_IFMT) != S_IFCHR)) {
+ errstr = E_CHR;
+ return (1);
+ }
+ if ((pflags & P_BLK) && ((status.st_mode & S_IFMT) != S_IFBLK)) {
+ errstr = E_BLK;
+ return (1);
+ }
+ if ((pflags & P_DIR) && ((status.st_mode & S_IFMT) != S_IFDIR)) {
+ errstr = E_DIR;
+ return (1);
+ }
+ if ((pflags & P_REG) && ((status.st_mode & S_IFMT) != S_IFREG)) {
+ errstr = E_REG;
+ return (1);
+ }
+ if ((pflags & P_READ) && !(status.st_mode & S_IREAD)) {
+ errstr = E_READ;
+ return (1);
+ }
+ if ((pflags & P_WRITE) && !(status.st_mode & S_IWRITE)) {
+ errstr = E_WRITE;
+ return (1);
+ }
+ if ((pflags & P_EXEC) && !(status.st_mode & S_IEXEC)) {
+ errstr = E_EXEC;
+ return (1);
+ }
+ return (0);
+}
+
+void
+ckpath_err(int pflags, char *error, char *input)
+{
+ char buffer[2048];
+ char *defhlp;
+
+ if (input) {
+ if (ckpath_val(input, pflags)) {
+ (void) sprintf(buffer, "Pathname %s.", errstr);
+ puterror(stdout, buffer, error);
+ return;
+ }
+ }
+ defhlp = sethlp(pflags);
+ puterror(stdout, defhlp, error);
+ free(defhlp);
+}
+
+void
+ckpath_hlp(int pflags, char *help)
+{
+ char *defhlp;
+
+ defhlp = sethlp(pflags);
+ puthelp(stdout, defhlp, help);
+ free(defhlp);
+}
+
+int
+ckpath(char *pathval, int pflags, char *defstr, char *error, char *help,
+ char *prompt)
+{
+ char *defhlp,
+ input[MAX_INPUT],
+ buffer[256];
+
+ if ((pathval == NULL) || ckpath_stx(pflags))
+ return (2); /* usage error */
+
+ if (!prompt) {
+ if (pflags & P_ABSOLUTE)
+ prompt = "Enter an absolute pathname";
+ else if (pflags & P_RELATIVE)
+ prompt = "Enter a relative pathname";
+ else
+ prompt = "Enter a pathname";
+ }
+ defhlp = sethlp(pflags);
+
+start:
+ putprmpt(stderr, prompt, NULL, defstr);
+ if (getinput(input)) {
+ free(defhlp);
+ return (1);
+ }
+
+ if (strlen(input) == 0) {
+ if (defstr) {
+ (void) strcpy(pathval, defstr);
+ free(defhlp);
+ return (0);
+ }
+ puterror(stderr, NULL, "Input is required.");
+ goto start;
+ }
+ if (strcmp(input, "?") == 0) {
+ puthelp(stderr, defhlp, help);
+ goto start;
+ }
+ if (ckquit && (strcmp(input, "q") == 0)) {
+ free(defhlp);
+ return (3);
+ }
+
+ if (ckpath_val(input, pflags)) {
+ (void) sprintf(buffer, "Pathname %s.", errstr);
+ puterror(stderr, buffer, error);
+ goto start;
+ }
+ (void) strcpy(pathval, input);
+ free(defhlp);
+ return (0);
+}
diff --git a/usr/src/lib/libadm/common/ckrange.c b/usr/src/lib/libadm/common/ckrange.c
new file mode 100644
index 0000000000..bf3710c7a6
--- /dev/null
+++ b/usr/src/lib/libadm/common/ckrange.c
@@ -0,0 +1,151 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright (c) 1997, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.3 */
+/*LINTLIBRARY*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <sys/types.h>
+#include "libadm.h"
+
+#define MSGSIZ 256
+#define PROMPT10 "Enter an integer between %ld and %ld"
+#define PROMPT "Enter a base %d integer between %ld and %ld"
+#define MESG10 "Please enter an integer between %ld and %ld."
+#define MESG "Please enter a base %d integer between %ld and %ld."
+
+static void
+setmsg(char *msg, long lower, long upper, int base)
+{
+ if ((base == 10) || (base == 0))
+ (void) sprintf(msg, MESG10, lower, upper);
+ else
+ (void) sprintf(msg, MESG, base, lower, upper);
+}
+
+void
+ckrange_err(long lower, long upper, int base, char *error)
+{
+ char defmesg[MSGSIZ];
+
+ setmsg(defmesg, lower, upper, base);
+ puterror(stdout, defmesg, error);
+}
+
+void
+ckrange_hlp(long lower, long upper, int base, char *help)
+{
+ char defmesg[MSGSIZ];
+
+ setmsg(defmesg, lower, upper, base);
+ puthelp(stdout, defmesg, help);
+}
+
+int
+ckrange_val(long lower, long upper, int base, char *input)
+{
+ char *ptr;
+ long value;
+
+ value = strtol(input, &ptr, base);
+ if ((*ptr != '\0') || (value < lower) || (value > upper))
+ return (1);
+ return (0);
+}
+
+int
+ckrange(long *rngval, long lower, long upper, short base, char *defstr,
+ char *error, char *help, char *prompt)
+{
+ int valid, n;
+ long value;
+ char *ptr;
+ char input[MAX_INPUT];
+ char defmesg[MSGSIZ];
+ char defpmpt[128];
+ char buffer[64];
+ char *choices[2];
+
+ if (lower >= upper)
+ return (2);
+
+ (void) sprintf(buffer, "%ld-%ld", lower, upper);
+
+ if (base == 0)
+ base = 10;
+
+ if (!prompt) {
+ if (base == 10)
+ (void) sprintf(defpmpt, PROMPT10, lower, upper);
+ else
+ (void) sprintf(defpmpt, PROMPT, base, lower, upper);
+ prompt = defpmpt;
+ }
+
+ setmsg(defmesg, lower, upper, base);
+ choices[0] = buffer;
+ choices[1] = NULL;
+
+start:
+ putprmpt(stderr, prompt, choices, defstr);
+ if (getinput(input))
+ return (1);
+
+ n = (int)strlen(input);
+ if (n == 0) {
+ if (defstr) {
+ *rngval = strtol(defstr, NULL, base);
+ return (0);
+ }
+ puterror(stderr, defmesg, error);
+ goto start;
+ }
+ if (strcmp(input, "?") == 0) {
+ puthelp(stderr, defmesg, help);
+ goto start;
+ }
+ if (ckquit && (strcmp(input, "q") == 0))
+ return (3);
+
+ value = strtol(input, &ptr, base);
+ if (*ptr == '\0')
+ valid = ((value >= lower) && (value <= upper));
+ else
+ valid = 0;
+ if (!valid) {
+ puterror(stderr, defmesg, error);
+ goto start;
+ }
+ *rngval = value;
+ return (0);
+}
diff --git a/usr/src/lib/libadm/common/ckstr.c b/usr/src/lib/libadm/common/ckstr.c
new file mode 100644
index 0000000000..e01717f233
--- /dev/null
+++ b/usr/src/lib/libadm/common/ckstr.c
@@ -0,0 +1,187 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <sys/types.h>
+#include "libadm.h"
+
+/*
+ * This file is the only one anywhere to need these functions,
+ * so we declare them here, not in libadm.h
+ */
+extern char *__compile(char *, char *, const char *, int);
+extern int __step(const char *, const char *);
+
+#define ESIZE 1024
+
+#define ERRMSG0 "Input is required."
+#define ERRMSG1 "Please enter a string containing no more than %d characters."
+#define ERRMSG2 \
+ "Pattern matching has failed."
+#define ERRMSG3 \
+ "Please enter a string which contains no imbedded, \
+ leading or trailing spaces or tabs."
+
+#define HLPMSG0 "Please enter a string"
+#define HLPMSG1 "Please enter a string containing no more than %d characters"
+#define HLPMSG2 "matches one of the following patterns:"
+#define HLPMSG3 "matches the following pattern:"
+#define HLPMSG4 "contains no imbedded, leading or trailing spaces or tabs."
+
+static char *errstr;
+
+static char *
+sethlp(char *msg, char *regexp[], int length)
+{
+ int i;
+
+ if (length)
+ (void) sprintf(msg, HLPMSG1, length);
+ else
+ (void) strcpy(msg, HLPMSG0);
+
+ (void) strcat(msg, length ? " and " : " which ");
+
+ if (regexp && regexp[0]) {
+ (void) strcat(msg, regexp[1] ? HLPMSG2 : HLPMSG3);
+ for (i = 0; regexp[i]; i++) {
+ (void) strcat(msg, "\\n\\t");
+ (void) strcat(msg, regexp[i]);
+ }
+ } else
+ (void) strcat(msg, HLPMSG4);
+ return (msg);
+}
+
+int
+ckstr_val(char *regexp[], int length, char *input)
+{
+ char expbuf[ESIZE];
+ int i, valid;
+
+ valid = 1;
+ if (length && (strlen(input) > (size_t)length)) {
+ errstr = ERRMSG1;
+ return (1);
+ }
+ if (regexp && regexp[0]) {
+ valid = 0;
+ for (i = 0; !valid && regexp[i]; ++i) {
+ if (!__compile(regexp[i], expbuf, &expbuf[ESIZE], '\0'))
+ return (2);
+ valid = __step(input, expbuf);
+ }
+ if (!valid)
+ errstr = ERRMSG2;
+ } else if (strpbrk(input, " \t")) {
+ errstr = ERRMSG3;
+ valid = 0;
+ }
+ return (valid == 0);
+}
+
+void
+ckstr_err(char *regexp[], int length, char *error, char *input)
+{
+ char *defhlp;
+ char temp[1024];
+
+ if (input) {
+ if (ckstr_val(regexp, length, input)) {
+ (void) sprintf(temp, errstr, length);
+ puterror(stdout, temp, error);
+ return;
+ }
+ }
+
+ defhlp = sethlp(temp, regexp, length);
+ puterror(stdout, defhlp, error);
+}
+
+void
+ckstr_hlp(char *regexp[], int length, char *help)
+{
+ char *defhlp;
+ char hlpbuf[1024];
+
+ defhlp = sethlp(hlpbuf, regexp, length);
+ puthelp(stdout, defhlp, help);
+}
+
+int
+ckstr(char *strval, char *regexp[], int length, char *defstr, char *error,
+ char *help, char *prompt)
+{
+ int n;
+ char *defhlp;
+ char input[MAX_INPUT],
+ hlpbuf[1024],
+ errbuf[1024];
+
+ defhlp = NULL;
+ if (!prompt)
+ prompt = "Enter an appropriate value";
+
+start:
+ putprmpt(stderr, prompt, NULL, defstr);
+ if (getinput(input))
+ return (1);
+
+ n = (int)strlen(input);
+ if (n == 0) {
+ if (defstr) {
+ (void) strcpy(strval, defstr);
+ return (0);
+ }
+ puterror(stderr, ERRMSG0, error);
+ goto start;
+ }
+ if (strcmp(input, "?") == 0) {
+ if (defhlp == NULL)
+ defhlp = sethlp(hlpbuf, regexp, length);
+ puthelp(stderr, defhlp, help);
+ goto start;
+ }
+ if (ckquit && (strcmp(input, "q") == 0)) {
+ (void) strcpy(strval, input);
+ return (3);
+ }
+ if (ckstr_val(regexp, length, input)) {
+ (void) sprintf(errbuf, errstr, length);
+ puterror(stderr, errbuf, error);
+ goto start;
+ }
+ (void) strcpy(strval, input);
+ return (0);
+}
diff --git a/usr/src/lib/libadm/common/cktime.c b/usr/src/lib/libadm/common/cktime.c
new file mode 100644
index 0000000000..71a5580600
--- /dev/null
+++ b/usr/src/lib/libadm/common/cktime.c
@@ -0,0 +1,388 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright (c) 1997,1998 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+/*LINTLIBRARY*/
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include "libadm.h"
+
+static int fmtcheck(char *);
+
+#define PROMPT "Enter the time of day"
+#define ERRMSG "Please enter the time of day. Format is"
+#define DEFAULT "%H:%M"
+
+#define TLEN 3
+#define LH 00
+#define UH 23
+#define USH 12
+#define LM 00
+#define UM 59
+#define LS 00
+#define US 59
+#define DELIM1 ':'
+#define BLANK ' '
+#define TAB ' '
+
+static void
+setmsg(char *msg, char *fmt)
+{
+ if (fmt == NULL)
+ fmt = DEFAULT;
+ (void) sprintf(msg, "%s <%s>.", ERRMSG, fmt);
+}
+
+static char *
+p_ndig(char *string, int *value)
+{
+ char *ptr;
+ int accum = 0;
+ int n = 2;
+
+ if (!string)
+ return (0);
+ for (ptr = string; *ptr && n > 0; n--, ptr++) {
+ if (! isdigit((unsigned char)*ptr))
+ return (NULL);
+ accum = (10 * accum) + (*ptr - '0');
+ }
+ if (n)
+ return (NULL);
+ *value = accum;
+ return (ptr);
+}
+
+static char *
+p_time(char *string, int llim, int ulim)
+{
+ char *ptr;
+ int begin = -1;
+ if (!(ptr = p_ndig(string, &begin)))
+ return (NULL);
+ if (begin >= llim && begin <= ulim)
+ return (ptr);
+ else return (NULL);
+}
+
+/* p_meridian will parse the string for the meridian - AM/PM or am/pm */
+
+static char *
+p_meridian(char *string)
+{
+ static char *middle[] = { "AM", "PM", "am", "pm" };
+ int legit, n;
+ char mid[TLEN];
+
+ legit = 0;
+ n = 0;
+ mid[2] = '\0';
+ (void) sscanf(string, "%2s", mid);
+ while (!(legit) && (n < 4)) {
+ if ((strncmp(mid, middle[n], 2)) == 0)
+ legit = 1; /* found legitimate string */
+ n++;
+ }
+ if (legit)
+ return (string+2);
+ return (NULL);
+}
+
+static char *
+p_delim(char *string, char dchoice)
+{
+ char dlm;
+
+ if (! string)
+ return (NULL);
+ (void) sscanf(string, "%1c", &dlm);
+ return ((dlm == dchoice) ? string + 1 : NULL);
+}
+
+int
+cktime_val(char *fmt, char *input)
+{
+ char ltrl, dfl;
+ int valid = 1; /* time of day string is valid for format */
+
+ if ((fmt != NULL) && (fmtcheck(fmt) == 1))
+ return (4);
+
+ if (fmt == NULL)
+ fmt = DEFAULT;
+ ltrl = '\0';
+ while (*fmt && valid) {
+ if ((*fmt) == '%') {
+ switch (*++fmt) {
+ case 'H':
+ input = p_time(input, LH, UH);
+ if (!input)
+ valid = 0;
+ break;
+
+ case 'M':
+ input = p_time(input, LM, UM);
+ if (!input)
+ valid = 0;
+ break;
+
+ case 'S':
+ input = p_time(input, LS, US);
+ if (!input)
+ valid = 0;
+ break;
+
+ case 'T':
+ input = p_time(input, LH, UH);
+ if (!input) {
+ valid = 0;
+ break;
+ }
+
+ input = p_delim(input, DELIM1);
+ if (!input) {
+ valid = 0;
+ break;
+ }
+ input = p_time(input, LM, UM);
+ if (!input) {
+ valid = 0;
+ break;
+ }
+ input = p_delim(input, DELIM1);
+ if (!input) {
+ valid = 0;
+ break;
+ }
+ input = p_time(input, LS, US);
+ if (!input)
+ valid = 0;
+ break;
+
+ case 'R':
+ input = p_time(input, LH, UH);
+ if (!input) {
+ valid = 0;
+ break;
+ }
+ input = p_delim(input, DELIM1);
+ if (!input) {
+ valid = 0;
+ break;
+ }
+ input = p_time(input, LM, UM);
+ if (!input) {
+ valid = 0;
+ break;
+ }
+ break;
+
+ case 'r':
+ input = p_time(input, LH, USH);
+ if (!input) {
+ valid = 0;
+ break;
+ }
+ input = p_delim(input, DELIM1);
+ if (!input) {
+ valid = 0;
+ break;
+ }
+ input = p_time(input, LM, UM);
+ if (!input) {
+ valid = 0;
+ break;
+ }
+ input = p_delim(input, DELIM1);
+ if (!input) {
+ valid = 0;
+ break;
+ }
+ input = p_time(input, LS, US);
+ if (!input) {
+ valid = 0;
+ break;
+ }
+ input = p_delim(input, BLANK);
+ if (!input) {
+ valid = 0;
+ break;
+ }
+ input = p_meridian(input);
+ if (!input)
+ valid = 0;
+ break;
+
+ case 'I':
+ input = p_time(input, LH, USH);
+ if (!input)
+ valid = 0;
+ break;
+
+ case 'p':
+ input = p_meridian(input);
+ if (!input)
+ valid = 0;
+ break;
+
+ default:
+ (void) sscanf(input++, "%1c", &ltrl);
+ }
+ } else {
+ dfl = '\0';
+ (void) sscanf(input, "%1c", &dfl);
+ input++;
+ }
+ fmt++;
+ }
+
+ if (!(*fmt) && (input) && (*input))
+ valid = 0;
+
+ return ((valid == 0));
+}
+
+int
+cktime_err(char *fmt, char *error)
+{
+ char defmesg[128];
+
+ if ((fmt != NULL) && (fmtcheck(fmt) == 1))
+ return (4);
+ setmsg(defmesg, fmt);
+ puterror(stdout, defmesg, error);
+ return (0);
+}
+
+int
+cktime_hlp(char *fmt, char *help)
+{
+ char defmesg[128];
+
+ if ((fmt != NULL) && (fmtcheck(fmt) == 1))
+ return (4);
+ setmsg(defmesg, fmt);
+ puthelp(stdout, defmesg, help);
+ return (0);
+}
+
+/*
+ * A little state machine that checks out the format to
+ * make sure it is acceptable.
+ * return value 1: NG
+ * return value 0: OK
+ */
+int
+fmtcheck(char *fmt)
+{
+ int percent = 0;
+
+ while (*fmt) {
+ switch (*fmt++) {
+ case '%': /* previous state must be start or letter */
+ if (percent == 0)
+ percent = 1;
+ else
+ return (1);
+ break;
+ case 'H': /* previous state must be "%" */
+ case 'M':
+ case 'S':
+ case 'T':
+ case 'R':
+ case 'r':
+ case 'I':
+ case 'p':
+ if (percent == 1)
+ percent = 0;
+ else
+ return (1);
+ break;
+ case TAB: /* previous state must be start or letter */
+ case BLANK:
+ case DELIM1:
+ if (percent == 1)
+ return (1);
+ break;
+ default:
+ return (1);
+ }
+ }
+ return (percent);
+}
+
+int
+cktime(char *tod, char *fmt, char *defstr, char *error, char *help,
+ char *prompt)
+{
+ char input[MAX_INPUT],
+ defmesg[128];
+
+ if ((fmt != NULL) && (fmtcheck(fmt) == 1))
+ return (4);
+
+ if (fmt == NULL)
+ fmt = DEFAULT;
+ setmsg(defmesg, fmt);
+ if (!prompt)
+ prompt = "Enter a time of day";
+
+start:
+ putprmpt(stderr, prompt, NULL, defstr);
+ if (getinput(input))
+ return (1);
+
+ if (!strlen(input)) {
+ if (defstr) {
+ (void) strcpy(tod, defstr);
+ return (0);
+ }
+ puterror(stderr, defmesg, error);
+ goto start;
+ }
+ if (strcmp(input, "?") == 0) {
+ puthelp(stderr, defmesg, help);
+ goto start;
+ }
+ if (ckquit && (strcmp(input, "q") == 0))
+ return (3);
+
+ if (cktime_val(fmt, input)) {
+ puterror(stderr, defmesg, error);
+ goto start;
+ }
+ (void) strcpy(tod, input);
+ return (0);
+}
diff --git a/usr/src/lib/libadm/common/ckuid.c b/usr/src/lib/libadm/common/ckuid.c
new file mode 100644
index 0000000000..a185a19193
--- /dev/null
+++ b/usr/src/lib/libadm/common/ckuid.c
@@ -0,0 +1,196 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright (c) 1997, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.2 */
+/*LINTLIBRARY*/
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <limits.h>
+#include "libadm.h"
+
+#define PROMPT "Enter the login name of an existing user"
+#define MESG "Please enter the login name of an existing user."
+#define ALTMESG "Please enter one of the following login names:\\n\\t"
+#define MALSIZ 64
+
+#define DELIM1 '/'
+#define BLANK ' '
+
+static char *
+setmsg(int disp)
+{
+ struct passwd
+ *pwdptr;
+ int count;
+ size_t n, m;
+ char *msg;
+
+ if (disp == 0)
+ return (MESG);
+
+ m = MALSIZ;
+ n = sizeof (ALTMESG);
+ msg = (char *) calloc(m, sizeof (char));
+ (void) strcpy(msg, ALTMESG);
+
+ setpwent();
+ count = 0;
+ while (pwdptr = getpwent()) {
+ n += strlen(pwdptr->pw_name) + 2;
+ while (n >= m) {
+ m += MALSIZ;
+ msg = (char *) realloc(msg, m*sizeof (char));
+ }
+ if (count++)
+ (void) strcat(msg, ", ");
+ (void) strcat(msg, pwdptr->pw_name);
+ }
+ endpwent();
+ return (msg);
+}
+
+int
+ckuid_dsp(void)
+{
+ struct passwd *pwdptr;
+
+ /* if display flag is set, then list out passwd file */
+ if (ckpwdfile() == 1)
+ return (1);
+ setpwent();
+ while (pwdptr = getpwent())
+ (void) printf("%s\n", pwdptr->pw_name);
+ endpwent();
+ return (0);
+}
+
+int
+ckuid_val(char *usrnm)
+{
+ int valid;
+
+ setpwent();
+ valid = (getpwnam(usrnm) ? 0 : 1);
+ endpwent();
+ return (valid);
+}
+
+int
+ckpwdfile(void) /* check to see if passwd file there */
+{
+ struct passwd *pwdptr;
+
+ setpwent();
+ pwdptr = getpwent();
+ if (!pwdptr) {
+ endpwent();
+ return (1);
+ }
+ endpwent();
+ return (0);
+}
+
+void
+ckuid_err(short disp, char *error)
+{
+ char *msg;
+
+ msg = setmsg(disp);
+ puterror(stdout, msg, error);
+ if (disp)
+ free(msg);
+}
+
+void
+ckuid_hlp(int disp, char *help)
+{
+ char *msg;
+
+ msg = setmsg(disp);
+ puthelp(stdout, msg, help);
+ if (disp)
+ free(msg);
+}
+
+int
+ckuid(char *uid, short disp, char *defstr, char *error, char *help,
+ char *prompt)
+{
+ char *defmesg,
+ input[MAX_INPUT];
+
+ defmesg = NULL;
+ if (!prompt)
+ prompt = PROMPT;
+
+start:
+ putprmpt(stderr, prompt, NULL, defstr);
+ if (getinput(input)) {
+ if (disp && defmesg)
+ free(defmesg);
+ return (1);
+ }
+
+ if (!strlen(input)) {
+ if (defstr) {
+ if (disp && defmesg)
+ free(defmesg);
+ (void) strcpy(uid, defstr);
+ return (0);
+ }
+ if (!defmesg)
+ defmesg = setmsg(disp);
+ puterror(stderr, defmesg, error);
+ goto start;
+ } else if (strcmp(input, "?") == 0) {
+ if (!defmesg)
+ defmesg = setmsg(disp);
+ puthelp(stderr, defmesg, help);
+ goto start;
+ } else if (ckquit && (strcmp(input, "q") == 0)) {
+ if (disp && defmesg)
+ free(defmesg);
+ return (3);
+ } else if (ckuid_val(input)) {
+ if (!defmesg)
+ defmesg = setmsg(disp);
+ puterror(stderr, defmesg, error);
+ goto start;
+ }
+ (void) strcpy(uid, input);
+ if (disp && defmesg)
+ free(defmesg);
+ return (0);
+}
diff --git a/usr/src/lib/libadm/common/ckyorn.c b/usr/src/lib/libadm/common/ckyorn.c
new file mode 100644
index 0000000000..942e0ebaf0
--- /dev/null
+++ b/usr/src/lib/libadm/common/ckyorn.c
@@ -0,0 +1,116 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+/*LINTLIBRARY*/
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <limits.h>
+#include <sys/types.h>
+#include "libadm.h"
+
+static char *choices[] = { "y", "n", NULL };
+static char *vchoices[] = { "y", "n", "yes", "no", NULL };
+
+#define TMPSIZ 7
+#define REQMSG "Input is required."
+#define ERRMSG "Please enter yes or no."
+#define HLPMSG \
+ "To respond in the affirmative, enter y, yes, Y, or YES. \
+ To respond in the negative, enter n, no, N, or NO."
+
+int
+ckyorn_val(char *str)
+{
+ int i;
+ char *pt,
+ temp[TMPSIZ+1];
+
+ for (pt = temp, i = 0; *str && i < TMPSIZ; i++) {
+ *pt++ = tolower((unsigned char)*str++);
+ }
+ *pt = '\0';
+ for (i = 0; vchoices[i]; ) {
+ if (strcmp(temp, vchoices[i++]) == 0)
+ return (0);
+ }
+ return (-1);
+}
+
+void
+ckyorn_err(char *error)
+{
+ puterror(stdout, ERRMSG, error);
+}
+
+void
+ckyorn_hlp(char *help)
+{
+ puthelp(stdout, HLPMSG, help);
+}
+
+int
+ckyorn(char *yorn, char *defstr, char *error, char *help, char *prompt)
+{
+ int n;
+ char input[MAX_INPUT];
+
+ if (!prompt)
+ prompt = "Yes or No";
+start:
+ putprmpt(stderr, prompt, choices, defstr);
+ if (getinput(input))
+ return (1);
+
+ n = (int)strlen(input);
+ if (n == 0) {
+ if (defstr) {
+ (void) strcpy(yorn, defstr);
+ return (0);
+ }
+ puterror(stderr, REQMSG, error);
+ goto start;
+ }
+ if (strcmp(input, "?") == 0) {
+ puthelp(stderr, HLPMSG, help);
+ goto start;
+ }
+ if (ckquit && (strcmp(input, "q") == 0))
+ return (3);
+
+ if (ckyorn_val(input)) {
+ puterror(stderr, ERRMSG, error);
+ goto start;
+ }
+ (void) strcpy(yorn, input);
+ return (0);
+}
diff --git a/usr/src/lib/libadm/common/data.c b/usr/src/lib/libadm/common/data.c
new file mode 100644
index 0000000000..570b436d2c
--- /dev/null
+++ b/usr/src/lib/libadm/common/data.c
@@ -0,0 +1,51 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+/* LINTLIBRARY */
+
+/*
+ * data.c
+ *
+ * This file contains global data for the library "liboam".
+ *
+ * FILE *oam_devtab The open file descriptor for the current
+ * device table.
+ * FILE *oam_dgroup The open file descriptor for the current
+ * device-group table.
+ */
+
+
+/*
+ * Header files needed:
+ * <stdio.h> Standard I/O definitions
+ */
+
+#include <stdio.h>
+
+
+
+FILE *oam_devtab = (FILE *) NULL;
+FILE *oam_dgroup = (FILE *) NULL;
diff --git a/usr/src/lib/libadm/common/devattr.c b/usr/src/lib/libadm/common/devattr.c
new file mode 100644
index 0000000000..c64a589ea9
--- /dev/null
+++ b/usr/src/lib/libadm/common/devattr.c
@@ -0,0 +1,181 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright (c) 1997, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.2 */
+
+/*LINTLIBRARY*/
+
+/*
+ * devattr.c
+ *
+ * Contents:
+ * devattr() Get the value of a attribute for a specific device
+ */
+
+/*
+ * Header files needed
+ * <sys/types.h> System Data Types
+ * <stdio.h> Standard I/O Definitions
+ * <errno.h> Error-value definitions
+ * <string.h> String function and constant definitions
+ * <devmgmt.h> Device table definitions available to the world
+ * "devtab.h" Local device table definitions
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <devmgmt.h>
+#include "devtab.h"
+
+/*
+ * Local constant definitions
+ */
+
+
+/*
+ * Local static data
+ */
+
+/*
+ * char *devattr(device, attr)
+ *
+ * This function searches the device table, looking for the device
+ * specified by <device>. If it finds a record corresponding to that
+ * device (see below for a definition of that correspondence), it
+ * extracts the value of the field <attr> from that record, if any.
+ * It returns a pointer to that value, or (char *) NULL if none.
+ *
+ * Arguments:
+ * device Pointer to the character-string that describes the
+ * device whose record is to be looked for
+ * attr The device's attribute to be looked for
+ *
+ * Returns: char *
+ * A pointer to the character-string containing the value of the
+ * attribute <attr> for the device <device>, or (char *) NULL if none
+ * was found. If the function returns (char *) NULL and the error was
+ * detected by this function, it sets "errno" to indicate the problem.
+ *
+ * "errno" Values:
+ * EPERM Permissions deny reading access of the device-table
+ * file
+ * ENOENT The specified device-table file could not be found
+ * ENODEV Device not found in the device table
+ * EINVAL The device does not have that attribute defined
+ * ENOMEM No memory available
+ */
+
+char *
+devattr(
+ char *device, /* The device ) we're to look for */
+ char *attribute) /* The attribute to extract */
+{
+ /* Automatic data */
+ struct devtabent *record; /* Retrieved record */
+ struct attrval *p; /* attr/val records */
+ char *val; /* Extracted value */
+ char *rtnval; /* Value to return */
+ int found; /* TRUE if attribute found */
+
+
+ /* Get the record for the specified device */
+ if (!(record = _getdevrec(device))) {
+ _enddevtab();
+ return (NULL);
+ }
+
+ /* Search the record for the specified attribute */
+ found = FALSE;
+
+ /* Did they ask for the device alias? */
+ if (strcmp(attribute, DTAB_ALIAS) == 0) {
+ val = (record->alias != NULL) ? record->alias : "";
+ found = TRUE;
+ }
+
+ /* Did they ask for the character-special device? */
+ else if (strcmp(attribute, DTAB_CDEVICE) == 0) {
+ val = (record->cdevice != NULL) ? record->cdevice : "";
+ found = TRUE;
+ }
+
+ /* Did they ask for the block-special device? */
+ else if (strcmp(attribute, DTAB_BDEVICE) == 0) {
+ val = (record->bdevice != NULL) ? record->bdevice : "";
+ found = TRUE;
+ }
+
+ /* Did they ask for the pathname? */
+ else if (strcmp(attribute, DTAB_PATHNAME) == 0) {
+ val = (record->pathname != NULL) ? record->pathname : "";
+ found = TRUE;
+ }
+
+ else {
+
+ /*
+ * Didn't ask for one of the easy ones, search the attr/val
+ * structure
+ */
+
+ p = record->attrlist;
+ while (!found && (p)) {
+ if (strcmp(p->attr, attribute) == 0) {
+ val = p->val;
+ found = TRUE;
+ } else p = p->next;
+ }
+ }
+
+ /*
+ * If the attribute was found, copy it into malloc()ed space.
+ * If not, set errno appropriately; we'll return NULL
+ */
+
+ if (found) {
+ if (rtnval = malloc(strlen(val)+1))
+ (void) strcpy(rtnval, val);
+ else errno = ENOMEM;
+ } else {
+ rtnval = NULL;
+ errno = EINVAL;
+ }
+
+ /* Free the space allocated to the struct devtabent structure */
+ _freedevtabent(record);
+
+ _enddevtab();
+
+ /* Fini */
+ return (rtnval);
+}
diff --git a/usr/src/lib/libadm/common/devreserv.c b/usr/src/lib/libadm/common/devreserv.c
new file mode 100644
index 0000000000..ed9c5735d1
--- /dev/null
+++ b/usr/src/lib/libadm/common/devreserv.c
@@ -0,0 +1,1162 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright (c) 1997, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+/*LINTLIBRARY*/
+
+/*
+ * Globals defined:
+ *
+ * devreserv() Reserve a set of OA&M devices
+ * devfree() Free a reserved device
+ * reservdev() Get a list of reserved devices
+ * _openlkfile() Opens the lock file
+ * _rsvtabpath() Get the pathname of the lock table file
+ * _closelkfile() Closes the lock file
+ */
+
+/*
+ * Headers referenced:
+ * <sys/types.h> System data types
+ * <errno.h> Error definitions (including "errno")
+ * <string.h> String handling definitions
+ * <fcntl.h> File control definitions
+ * <unistd.h> Unix standard value definitions
+ * <devmgmt.h> Global Device Management definitions
+ * "devtab.h" Local Device Management definitions
+ */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <devmgmt.h>
+#include "devtab.h"
+
+/*
+ * Local Definitions:
+ */
+
+
+/*
+ * Local data types:
+ * struct devlks Structure that defines locking information (key
+ * with alias name (may be '\0' terminated)
+ */
+
+struct devlks {
+ int lk_key;
+ char lk_alias[((DTAB_MXALIASLN+2)/2)*2];
+};
+
+
+/*
+ * Local Functions:
+ * isanullstr() Is a character string a null string ("")?
+ * getlkcnt() Get the number of devices locked
+ * locklkfile() Lock the OA&M Device locking file
+ * getlocks() Get the device locks from the device-lock file
+ * islocked() Determines if a device is locked
+ * putlocks() Close the device locks w/ update
+ * freelkfile() Close the device locks w/o updating
+ * compresslks() Compresses the table containing lock info
+ */
+
+#define isanullstr(s) (s[0] == '\0')
+
+static int locklkfile(short); /* Lock the lock file */
+static int getlkcnt(void); /* Get the number of locked devices */
+static int getlocks(void); /* Get the lock information */
+static int putlocks(char **, int); /* Update lock information */
+static int freelkfile(void); /* Free lock information (no update) */
+static char *islocked(char *); /* Determines if a device is locked */
+
+
+/*
+ * Static data
+ */
+
+static struct flock lkinfo = {0, 0, 0, 0, 0};
+static struct devlks *locklist;
+static int lockcount;
+static int lkfilefd = -1;
+
+/*
+ * char *_rsvtabpath()
+ *
+ * Determines the pathname of the device reservation table file
+ *
+ * Uses the following sequential steps:
+ * 1) If OAM_DEVLKFILE is defined and is not null, use that as
+ * the pathname to the file
+ * 2) Otherwise, use the devault name found in DVLK_PATH (defined
+ * in the header file <devtab.h>
+ *
+ * Arguments: None
+ *
+ * Returns: char *
+ * A pointer to the filename in malloc()ed memory or (char *) NULL if
+ * it fails. "errno" will indicate the error if it fails.
+ */
+
+char *
+_rsvtabpath(void)
+{
+ /* Automatics */
+ char *lockname; /* Name of the lockfile */
+#ifdef DEBUG
+ char *p; /* Temporary pointer */
+#endif
+
+#ifdef DEBUG
+ p = getenv(OAM_DEVLKTAB);
+ if ((p != NULL) && (*p != '\0')) {
+ if (lockname = malloc(strlen(p)+1))
+ (void) strcpy(lockname, p);
+ } else {
+#endif
+ if (lockname = malloc(strlen(DVLK_PATH)+1))
+ (void) strcpy(lockname, DVLK_PATH);
+
+#ifdef DEBUG
+ }
+#endif
+
+ /* Fini -- return a pointer to the lockfile pathname */
+ return (lockname);
+}
+
+/*
+ * int _openlkfile()
+ *
+ * The _openlkfile() function opens a device-reservation table file
+ * for read/write access.
+ *
+ * Arguments: None
+ *
+ * Returns: int
+ * TRUE if successful, FALSE otherwise.
+ *
+ * Statics Used:
+ * lkfilefd Lock file file descriptor
+ */
+
+int
+_openlkfile(void)
+{
+ /*
+ * Automatic data
+ */
+
+ char *lockname; /* Name of the lock file */
+
+
+ /* Close the lockfile -- it might be open */
+ (void) _closelkfile();
+
+ /* If we can get the name of the lock file ... */
+ if (lockname = _rsvtabpath()) {
+
+ /* Open it */
+ lkfilefd = open(lockname, O_RDWR|O_CREAT, 0600);
+ free(lockname);
+
+ }
+
+ /* Finis */
+ return ((lkfilefd != -1) ? TRUE : FALSE);
+}
+
+/*
+ * int _closelkfile()
+ *
+ * Function closes the device-reservation table file and sets the
+ * necessary external variables to indicate such.
+ *
+ * Arguments: None
+ *
+ * Returns: int
+ * Same as close()
+ *
+ * Statics referenced:
+ * lkfilefd The device reservation table file's file descriptor
+ */
+
+int
+_closelkfile(void)
+{
+ /* Automatics */
+ int rtnval; /* Value to return */
+
+ /* Close the lock file if it's open */
+ if (lkfilefd != -1) rtnval = close(lkfilefd);
+ else rtnval = 0;
+
+ /* Indicate that the lock-file is closed */
+ lkfilefd = -1;
+
+ /* Finis */
+ return (rtnval);
+}
+
+/*
+ * int locklkfile(lkflag)
+ * short lkflag
+ *
+ * This function locks the device lock file. If the request cannot
+ * be serviced, it keeps on trying until it manages to lock the file
+ * or it encounters an error.
+ *
+ * Arguments:
+ * lkflag Flag (from FCNTL(BA_OS)) indicating which type
+ * of lock is being requested. Values that make
+ * sense:
+ * F_RDLCK: Read lock.
+ * F_WRLCK: Write lock.
+ *
+ * Returns: int
+ * TRUE (non-zero) if the function managed to lock the file, FALSE
+ * otherwise ("errno" will indicate the problem).
+ *
+ * Statics used:
+ * int lkfilefd File descriptor of the open lock file
+ * struct flock lkinfo Structure used by fcntl() to lock a file
+ */
+
+static int
+locklkfile(short lkflag)
+{
+ /* Automatic data */
+ int noerror; /* TRUE if no error yet */
+ int locked; /* TRUE if the file is locked */
+ int olderrno; /* Value of errno on call */
+
+
+ /* Set up the locking structure */
+ lkinfo.l_type = lkflag;
+
+ /* Try to lock the file. If it's locked, wait and try again */
+ noerror = TRUE;
+ locked = FALSE;
+ olderrno = errno;
+ while (noerror && !locked) {
+ if (fcntl(lkfilefd, F_SETLK, &lkinfo) != -1) locked = TRUE;
+ else {
+ if ((errno == EACCES) || (errno == EAGAIN)) {
+ errno = olderrno;
+ if (sleep(2)) noerror = FALSE;
+ } else noerror = FALSE;
+ }
+ }
+
+ /* Return a success flag */
+ return (locked);
+}
+
+/*
+ * int getlkcnt()
+ *
+ * This function extracts the number of currently-locked devices
+ * from the lock file.
+ *
+ * Arguments: None
+ *
+ * Returns: int
+ * The number of devices locked or -1 if an error occurred.
+ *
+ * Statics used:
+ * lkfilefd File descriptor of the open lockfile
+ *
+ * Assumptions:
+ * - The file is positioned to the beginning-of-file
+ */
+
+static int
+getlkcnt(void)
+{
+ /* Automatics */
+ int cntread; /* Number of bytes read */
+ int lkcnt; /* Number of current locks */
+
+ /* Get the lock count from the file */
+ cntread = (int)read(lkfilefd, &lkcnt, sizeof (int));
+
+ /* If there wasn't one, set to 0. If error, set to -1 */
+ if (cntread != (int)sizeof (int))
+ lkcnt = (cntread < 0) ? -1 : 0;
+
+ /* Return the lock count */
+ return (lkcnt);
+}
+
+/*
+ * int readlocks()
+ *
+ * The readlocks() function reads the reserved-device list from
+ * the reserved-device file (which has already been opened)
+ *
+ * Arguments: None
+ *
+ * Returns: int
+ * TRUE if all went well, FALSE otherwise.
+ *
+ * Statics Used:
+ * lockcount Sets this to the number of locks in the lock list
+ * locklist Sets this to the malloc()ed space containing the
+ * list of reserved devices.
+ * lkfilefd Reads data from this file
+ */
+
+static int
+readlocks(void)
+{
+ /* Automatics */
+ struct devlks *alloc; /* Ptr to alloc'ed space */
+ int noerror; /* TRUE if all is well */
+ size_t bufsiz; /* # bytes needed for lock data */
+
+
+ /* Initializations */
+ noerror = TRUE;
+
+ /* Get the number of devices currently locked */
+ if ((lockcount = getlkcnt()) > 0) {
+
+ /* Allocate space for the locks */
+ bufsiz = lockcount * sizeof (struct devlks);
+ if (alloc = malloc(bufsiz)) {
+
+ /* Read the locks into the malloc()ed buffer */
+ if (read(lkfilefd, alloc, bufsiz) != (ssize_t)bufsiz)
+ noerror = FALSE;
+
+ /* If the read failed, free malloc()ed buffer */
+ if (!noerror) free(alloc);
+
+ } else noerror = FALSE; /* malloc() failed */
+
+ } else if (lockcount < 0) noerror = FALSE;
+
+ /* Finished */
+ if (noerror)
+ locklist = (lockcount > 0) ? alloc : NULL;
+ return (noerror);
+}
+
+/*
+ * int getlocks()
+ *
+ * getlocks() extracts the list of locked devices from the file
+ * containing that information. It returns the number of locked
+ * devices. If there are any locked devices, it allocates a buffer
+ * for the locked file information, saves that buffer address in
+ * the allocated buffer. Also, the device lock file is open and
+ * locked if the function is successful.
+ *
+ * Arguments: None
+ *
+ * Returns: int
+ * TRUE if successful, FALSE otherwise. "errno" will reflect the
+ * error if the function returns FALSE.
+ *
+ * Static data referenced:
+ * int lkfilefd File descriptor of the lock file
+ */
+
+static int
+getlocks(void)
+{
+ /* Automatic data */
+ int noerror; /* TRUE if all's well */
+
+
+ /* Initializations */
+ noerror = TRUE;
+
+ /* Open the lock file */
+ if (_openlkfile()) {
+
+ /* Lock the lock file */
+ if (locklkfile(F_WRLCK)) {
+
+ /* Get the number of devices currently locked */
+ if (!readlocks()) noerror = FALSE;
+
+ /* If something happened, unlock the file */
+ if (!noerror) (void) freelkfile();
+
+ } else noerror = FALSE; /* Lock failed */
+
+ /* If something happened, close the lock file */
+ if (!noerror)
+ (void) _closelkfile();
+
+ } else noerror = FALSE; /* Open failed */
+
+ /* Done */
+ return (noerror);
+}
+
+/*
+ * int writelks(tblcnt)
+ * int tblcnt
+ *
+ * writelks() writes the lock information to the lock file. Lock
+ * information includes the number of locks (to be) in the table.
+ * Note that functions may still be appending new locks after this
+ * call...
+ *
+ * Arguments:
+ * tblcnt Number of locks in the lock table
+ *
+ * Returns:
+ * TRUE if successful, FALSE otherwise with "errno" containing an
+ * indication of the error.
+ *
+ * Statics Used:
+ * lockcount Number of locks to exist
+ * locklist Table of locks (may not include new ones)
+ * lkfilefd File descriptor of the lock file
+ *
+ * Notes:
+ * - The number of locks that are going to be in the lock file
+ * is in the static variable "lockcount". <tblcnt> indicates
+ * the number of entries in the lock table.
+ */
+
+static int
+writelks(int tblcnt)
+{
+ /* Automatic data */
+ int noerr; /* FLAG, TRUE if all's well */
+ size_t tblsz; /* Size of the table to write */
+
+ /* Initializations */
+ noerr = TRUE;
+
+ /* Rewind the OA&M Device Lock File */
+ if (lseek(lkfilefd, 0L, 0) >= 0L)
+
+ /* Write the number of locks that will (eventually) exist */
+ if (write(lkfilefd, &lockcount, sizeof (int)) == sizeof (int)) {
+
+ /* Write the table as we currently know it */
+ tblsz = tblcnt * sizeof (struct devlks);
+ if (tblsz)
+ if (!write(lkfilefd, locklist, tblsz) == (ssize_t)tblsz)
+ noerr = FALSE; /* Write of locks failed */
+
+ } else noerr = FALSE; /* write() of count failed */
+
+ else noerr = FALSE; /* Rewind failed */
+
+ /* Return an indicator of our success */
+ return (noerr);
+}
+
+/*
+ * int appendlk(key, alias)
+ * int key
+ * char *alias
+ *
+ * Write device locking information to the device locking file.
+ *
+ * Arguments:
+ * key Key the device is being locked on
+ * alias The device alias being locked
+ *
+ * Returns: int
+ * TRUE if we successfully appended a lock to the lock file,
+ * FALSE with "errno" set otherwise.
+ *
+ * Static data used:
+ * lkfilefd The open file descriptor for the open device
+ * locking file
+ */
+
+static int
+appendlk(
+ int key, /* Lock key */
+ char *alias) /* Alias to lock */
+{
+ /* Automatic data */
+ struct devlks lk; /* Structure for writing a lock */
+
+ /* Set up the data to write */
+ lk.lk_key = key;
+ (void) strcpy(lk.lk_alias, alias);
+
+ /* Write the data, returning an indicator of our success */
+ return (write(lkfilefd, &lk,
+ sizeof (struct devlks)) == sizeof (struct devlks));
+}
+
+/*
+ * int compresslks()
+ *
+ * This function compresses the lock table, squeezing out the empty
+ * lock entries.
+ *
+ * Arguments: none
+ *
+ * Returns: int
+ * The number of non-empty entries in the table. They will be the
+ * first 'n' entries in the table after compression.
+ *
+ * Statics Used
+ * lockcount Number of locks in the device lock list
+ * locklist The device lock list
+ */
+
+static int
+compresslks(void)
+{
+ /* Automatics */
+ struct devlks *avail; /* Pointer to empty slot */
+ struct devlks *p; /* Running pointer to locks */
+ int nlocks; /* Number of locks (up to date) */
+ int i; /* Temporary counter */
+
+ /* Initializations */
+ p = locklist;
+ nlocks = lockcount;
+ avail = NULL;
+
+ /* Loop through the lock list squeezing out unused slots */
+ for (i = 0; i < lockcount; i++) {
+
+ /* If we've found an empty slot ... */
+ if (isanullstr(p->lk_alias)) {
+
+ /*
+ * If we've an empty slot to move to, just decrement
+ * count of used slots. Otherwise, make it the next
+ * available slot
+ */
+
+ nlocks--;
+ if (!avail) avail = p;
+ }
+
+ else if (avail) {
+
+ /*
+ * If we found a slot in use and there's an
+ * available slot, move this one there
+ */
+
+ (void) strcpy(avail->lk_alias, p->lk_alias);
+ avail->lk_key = p->lk_key;
+ avail++;
+ }
+
+ /* Next, please */
+ p++;
+ }
+
+ return (nlocks);
+}
+
+/*
+ * int freelkfile()
+ *
+ * This function unlocks the OA&M device locking file.
+ *
+ * Arguments: None
+ *
+ * Returns: int
+ * TRUE if it successfully unlocked the file, FALSE otherwise
+ * with "errno" set to indicate the problem.
+ *
+ * Statics Used:
+ * lkinfo File-locking structure
+ * lkfilefd File-descriptor of the open lock file
+ */
+
+static int
+freelkfile(void)
+{
+ /* Automatic data */
+ int noerr; /* TRUE if all's well */
+
+ /* Set the action to "unlock" */
+ lkinfo.l_type = F_UNLCK;
+
+ /* Unlock the file */
+ noerr = (fcntl(lkfilefd, F_SETLK, &lkinfo) != -1);
+
+ /* Return an indication of our success */
+ return (noerr);
+}
+
+/*
+ * int putlocks(newlist, key)
+ * char **newlist
+ * int key
+ *
+ * This function updates the file containing OA&M device locks.
+ *
+ * Arguments:
+ * newlist The address of the list of addresses of device
+ * aliases to add to the list of locked devices
+ * key The key on which to lock the devices
+ *
+ * Returns: int
+ * TRUE if all went well, FALSE otherwise with "errno" set to an
+ * error code that indicates the problem.
+ *
+ * Statics Used:
+ * lockcount Number of locks in the locked device structure
+ * locklist Locked device structure
+ */
+
+static int
+putlocks(
+ char **newlist, /* New devices to lock */
+ int key) /* Key we're locking stuff on */
+{
+ /* Automatic data */
+ struct devlks *plk; /* Ptr into the locks list */
+ char **pp; /* Pointer into the device list */
+ char **qq; /* Another ptr into the dev list */
+ int lkndx; /* Index into locks list */
+ int noerr; /* TRUE if all's well */
+ int lksintbl; /* Number of locks in the table */
+
+
+ /*
+ * Look through the existing lock list, looking for holes we can
+ * use for the newly locked devices
+ */
+
+ plk = locklist;
+ pp = newlist;
+ lkndx = 0;
+ while (*pp && (lkndx < lockcount)) {
+ if (isanullstr(plk->lk_alias)) {
+ plk->lk_key = key;
+ (void) strcpy(plk->lk_alias, *pp++);
+ }
+ lkndx++;
+ plk++;
+ }
+
+ /*
+ * Update the locks file (algorithm depends on whether we're adding
+ * new locks or not. May be replacing old locks!)
+ */
+
+ if (*pp) {
+
+ /*
+ * Need to expand the locks file
+ * - Remember the old lock count (in existing lock buffer)
+ * - Count the number of new locks we need to add
+ * - Write out the old locks structure
+ * - Append locks for the newly added locks
+ */
+
+ lksintbl = lockcount;
+ for (qq = pp; *qq; qq++) lockcount++;
+ noerr = writelks(lksintbl);
+ while (noerr && *pp) noerr = appendlk(key, *pp++);
+ } else {
+
+ /*
+ * Don't need to expand the locks file. Compress the locks
+ * then write out the locks information
+ */
+
+ lockcount = compresslks();
+ noerr = writelks(lockcount);
+ }
+
+ /* Done. Return an indication of our success */
+ return (noerr);
+}
+
+/*
+ * char *islocked(device)
+ * char *device
+ *
+ * This function checks a device to see if it is locked. If it is
+ * not locked, it returns the device alias.
+ *
+ * A device is not locked if the device's alias does not appear in
+ * the device locks table, or the key on which the device was locked
+ * is no longer active.
+ *
+ * Argumetns:
+ * char *device The device to be reserved. This can be
+ * a pathname to the device or a device
+ * alias.
+ *
+ * Returns: char *
+ * Returns a pointer to the device alias if it's not locked, or
+ * (char *) NULL if it's locked or some error occurred.
+ *
+ * Static data used:
+ * struct devlks *locklist Pointer to the list of device locks
+ * int lockcount The number of devices that are locked
+ */
+
+static char *
+islocked(char *device)
+{
+ /* Automatic data */
+ char *alias; /* Alias of "device" */
+ struct devlks *plk; /* Ptr to locking info */
+ int locked; /* TRUE if device in locked list */
+ int i; /* Temp counter */
+
+ /* Get the device's alias */
+ if (alias = devattr(device, DTAB_ALIAS)) {
+
+ /*
+ * Look through the device locks to see if this device alias
+ * is locked
+ */
+
+ locked = FALSE;
+ plk = locklist;
+ for (i = 0; !locked && (i < lockcount); i++) {
+ if (strncmp(alias, plk->lk_alias, DTAB_MXALIASLN) == 0)
+ locked = TRUE;
+ else plk++;
+ }
+
+ if (locked) {
+ free(alias);
+ alias = NULL;
+ errno = EAGAIN;
+ }
+
+ } /* devattr() failed, no such device? */
+
+ /* Return pointer to the device */
+ return (alias);
+}
+
+/*
+ * int unreserv(key, device)
+ * int key
+ * char *device
+ *
+ * This function removes a device reservation.
+ *
+ * Arguments:
+ * int key The key on which the device was allocated
+ * char *device The device to be freed.
+ *
+ * Returns: int
+ * TRUE if successful, FALSE otherwise with "errno" set.
+ *
+ * Explicit "errno" settings:
+ * (This follows the "signal()" model which gives one the ability
+ * to determine if a device is allocated without having the
+ * permission to free it.)
+ *
+ * EINVAL The device specified was not locked
+ * EPERM The device specified was locked but not on the
+ * specified key
+ *
+ * Static data used:
+ * locklist List of locked devices
+ * lockcount Number of entries in the locked-device list
+ */
+
+int
+unreserv(int key, char *device)
+{
+ /* Automatics */
+ char *srchalias; /* Device alias to search table with */
+ char *alias; /* Device's alias (from devattr()) */
+ struct devlks *plk; /* Pointer to a device lock */
+ int locked; /* TRUE if device currently locked */
+ int noerr; /* TRUE if all's well */
+ int olderrno; /* Entry value of "errno" */
+ int i; /* Counter of locks */
+
+
+ /* Initializations */
+ noerr = TRUE;
+
+ /*
+ * Get the device alias. If none can be found, try to free
+ * whatever it is that was given to us (the possibility exists
+ * that the device has been removed from the device table since
+ * it was reserved, so the device not being in the table shouldn't
+ * pose too much of a problem with us...)
+ */
+
+ olderrno = errno;
+ if (alias = devattr(device, DTAB_ALIAS)) srchalias = alias;
+ else {
+ errno = olderrno;
+ srchalias = device;
+ }
+
+ /* Loop through the locked-device list looking for what we've got... */
+ locked = FALSE;
+ plk = locklist;
+ for (i = 0; !locked && (i < lockcount); i++) {
+ if (strcmp(srchalias, plk->lk_alias) == 0)
+ locked = TRUE;
+ else plk++;
+ }
+
+ /* Free the alias string (if any), we don't need it anymore */
+ if (alias) free(alias);
+
+ /* If the device is locked ... */
+ if (locked) {
+
+ /*
+ * If it's locked on the key we've been given, free it.
+ * Otherwise, don't free it and set errno to EPERM
+ */
+
+ if (plk->lk_key == key) {
+ plk->lk_alias[0] = '\0';
+ } else {
+ noerr = FALSE;
+ errno = EPERM;
+ }
+ } else {
+
+ /* The device isn't locked. Set errno to EINVAL */
+ noerr = FALSE;
+ errno = EINVAL;
+ }
+
+ /* Finished. Return an indication of our success */
+ return (noerr);
+}
+
+/*
+ * char **devreserv(key, rsvlst)
+ * int key
+ * char **rsvlist[]
+ *
+ * The devreserv() function reserves devices known to the OA&M Device
+ * Management family of functions. Once a device is reserved, it can't
+ * be reserved by another until it is freed or the process with the
+ * "key" is no longer active. It returns a list aliases of the devices
+ * it allocated.
+ *
+ * The function attempts to reserve a single device from each of the
+ * lists. It scans each list sequentially until it was able to
+ * reserve a requested device. If it successfully reserved a device
+ * from each of the lists, it updates the device-locked file and
+ * returns those aliases to the caller. If it fails, it allocates
+ * nothing and returns (char **) NULL to the caller. "errno"
+ * indicates the error.
+ *
+ * Arguments:
+ * int key The key on which this device is being reserved.
+ *
+ * char **rsvlist[] The address of the list of addresses of lists
+ * of pointers to the devices to allocate.
+ *
+ * Returns: char **
+ * A pointer to malloc()ed space containing pointers to the aliases
+ * of the reserved devices. The aliases are in malloc()ed space also.
+ * The list is terminated by the value (char *) NULL.
+ *
+ * Static Data Used:
+ * None directly, but functions called share hidden information
+ * that really isn't of concern to devreserv().
+ */
+
+char **
+devreserv(
+ int key, /* Key to reserve device on */
+ char **rsvlst[]) /* List of lists of devs to reserve */
+{
+ char ***ppp; /* Ptr to current list in rsvlist */
+ char **pp; /* Ptr to current item in list */
+ char **qq; /* Ptr to item in rtnlist */
+ char **rr; /* Ptr to item in aliases */
+ char **aliases; /* List of aliases allocated */
+ char **rtnlist; /* Ptr to buf to return */
+ char *alias; /* Alias of dev to reserve */
+ int noerr; /* TRUE if all's well */
+ int olderrno; /* Old value of errno */
+ int gotone; /* TRUE if unreserved dev found */
+ int foundone; /* Found a valid device in the list */
+ int ndevs; /* # of devs to reserve */
+
+ noerr = TRUE;
+ ppp = rsvlst;
+ olderrno = errno;
+ for (ndevs = 0; *ppp++; ndevs++)
+ ;
+ if (rtnlist = malloc((ndevs+1)*sizeof (char **))) {
+ if (aliases = malloc((ndevs+1)*sizeof (char **))) {
+ if (getlocks()) {
+ qq = rtnlist;
+ rr = aliases;
+
+ /* Go through the lists of devices we're to reserve */
+
+ for (ppp = rsvlst; noerr && *ppp; ppp++) {
+
+ /* Try to reserve a device from each list */
+ gotone = FALSE;
+ foundone = FALSE;
+ for (pp = *ppp; noerr && !gotone && *pp; pp++) {
+
+ /*
+ * Check the next device in the list. If islocked()
+ * returns that device's alias, it's ours to have
+ */
+
+ if (alias = islocked(*pp)) {
+ gotone = TRUE;
+ foundone = TRUE;
+ if (*qq = malloc(strlen(*pp)+1)) {
+ (void) strcpy(*qq++, *pp);
+ *rr++ = alias;
+ } else {
+ *rr = NULL;
+ noerr = FALSE;
+ }
+ } else {
+ if (errno == EAGAIN) {
+ foundone = TRUE;
+ errno = olderrno;
+ } else if (errno == ENODEV) errno = olderrno;
+ else {
+ noerr = FALSE;
+ *rr = NULL;
+ }
+ }
+ }
+
+ /*
+ * If no device from the list could be reserved,
+ * we've failed
+ */
+
+ if (noerr && !gotone) {
+ noerr = FALSE;
+ if (!foundone) errno = ENODEV;
+ else errno = EAGAIN;
+ *qq = NULL;
+ *rr = NULL;
+ }
+
+ } /* End of loop through lists loop */
+
+ /*
+ * If all went well, update lock file.
+ * Then, free locks
+ */
+
+ if (noerr) {
+ *qq = NULL;
+ *rr = NULL;
+ if (!putlocks(aliases, key)) noerr = FALSE;
+ }
+
+ /* Free resources */
+ if (!freelkfile()) noerr = FALSE;
+ if (_closelkfile() != 0) noerr = FALSE;
+ for (qq = aliases; *qq; qq++) free(*qq);
+ if (!noerr)
+ for (pp = rtnlist; *pp; pp++)
+ free(*pp);
+
+ } else noerr = FALSE; /* Error getting locks */
+
+ free(aliases);
+
+ } else noerr = FALSE; /* Malloc() for alias list failed */
+
+ if (!noerr) {
+ free(rtnlist);
+ rtnlist = NULL;
+ }
+
+ } else noerr = FALSE; /* malloc() failed */
+
+ /* Return list or an indication of an error */
+ return (noerr ? rtnlist : NULL);
+}
+
+/*
+ * int devfree(key, device)
+ * int key
+ * char *device
+ *
+ * This function unreserves (frees) the given device. It returns
+ * an indication of success with "errno" containing information about
+ * a failure.
+ *
+ * Arguments:
+ * int key The key that the device is locked on
+ * char *device The device (alias, pathname to, etc.) to be freed.
+ *
+ * Returns: int
+ * 0 if successful, -1 with "errno" set if fails.
+ */
+
+int
+devfree(
+ int key, /* Key device is locked on */
+ char *device) /* Device to free */
+{
+ /* Automatics */
+ int noerr;
+
+ /* Initializations */
+ noerr = TRUE;
+
+ /* Get the locks, locking the lock file */
+ if (getlocks()) {
+
+ /* Attempt to unreserve the device */
+ if (unreserv(key, device)) {
+
+ /*
+ * Successful. Compress the lock structure and
+ * write the new locks
+ */
+
+ lockcount = compresslks();
+ if (!writelks(lockcount)) noerr = FALSE;
+
+ } else noerr = FALSE; /* Couldn't unreserve the device */
+
+ /* Unlock and close the locks file */
+ if (!freelkfile()) noerr = FALSE;
+ if (_closelkfile() != 0) noerr = FALSE;
+
+ } else noerr = FALSE;
+
+ /* Return 0 if successful, something else otherwise */
+ return (noerr? 0 : -1);
+}
+
+/*
+ * struct reservdev **reservdev()
+ *
+ * This function returns the list of reserved devices
+ * along with the key on which those devices were locked.
+ *
+ * Arguments: None.
+ *
+ * Returns: struct reservdev **
+ * Pointer to the list of pointers to structures describing
+ * the reserved devices, or (struct reservdev **) NULL if an
+ * error occurred. The list of pointers is terminated by
+ * (struct reservdev *) NULL.
+ *
+ * Statics Used:
+ * locklist List of reserved devices
+ * lockcount Number of items in the reserved-devices list
+ */
+
+struct reservdev **
+reservdev(void)
+{
+ /* Automatics */
+ struct reservdev **rtnlist; /* Ptr to return list */
+ struct devlks *p; /* Running ptr, locklist */
+ struct reservdev **q; /* Running ptr, rtnlist */
+ char *r; /* Temp ptr to char */
+ size_t bufsiz; /* Size of buffer to alloc */
+ int noerr; /* TRUE if all's well */
+ int i; /* Lock counter */
+
+
+ /* Initializations */
+ noerr = TRUE;
+
+ /* Open the lock file ... */
+ if (_openlkfile()) {
+
+ /* Put a read-lock on the lock-file ... */
+ if (locklkfile(F_RDLCK)) {
+
+ /* Read the locks ... */
+ if (readlocks()) {
+
+ /* Alloc space for the return list */
+ bufsiz = (lockcount+1) * sizeof (struct reservdev *);
+ if (rtnlist = malloc(bufsiz)) {
+
+ /* Build the return list from the lock list */
+ p = locklist;
+ q = rtnlist;
+ for (i = 0; noerr && (i < lockcount); i++) {
+ if (*q = malloc(sizeof (struct reservdev))) {
+ if (r = malloc(strlen(p->lk_alias)+1)) {
+ (*q)->devname = strcpy(r, p->lk_alias);
+ (*q)->key = p->lk_key;
+ } else noerr = FALSE; /* malloc() error */
+ } else noerr = FALSE; /* malloc() error */
+ p++;
+ q++;
+ }
+
+ /*
+ * If no error, terminate the list. Otherwise, free
+ * the space we've allocated
+ */
+
+ if (noerr) *q = NULL;
+ else {
+ for (q = rtnlist; *q; q++) {
+ free((*q)->devname);
+ free(*q);
+ }
+ free(rtnlist);
+ }
+
+ } else noerr = FALSE; /* Couldn't malloc() list space */
+
+ } else noerr = FALSE; /* Problem reading locks */
+
+ /* Free the lock file */
+ (void) freelkfile();
+
+ } else noerr = FALSE; /* Error locking the lock file */
+
+ /* Close the lock file */
+ (void) _closelkfile();
+
+ } else noerr = FALSE; /* Error opening the lock file */
+
+ /* Return ptr to list of locks or NULL if an error has occurred */
+ return (noerr ? rtnlist : NULL);
+}
diff --git a/usr/src/lib/libadm/common/devtab.c b/usr/src/lib/libadm/common/devtab.c
new file mode 100644
index 0000000000..ae1c812e5d
--- /dev/null
+++ b/usr/src/lib/libadm/common/devtab.c
@@ -0,0 +1,1057 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1996-1998 by Sun Microsystems, Inc.
+ * All Rights reserved.
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.2 */
+/*LINTLIBRARY*/
+
+/*
+ * devtab.c
+ *
+ * Contains functions that deal with the device table and are not for
+ * consumption by the general user population.
+ *
+ * Functions defined:
+ * _opendevtab() Opens the device table for commands
+ * _setdevtab() Rewinds the open device table
+ * _enddevtab() Closes the open device table
+ * _getdevtabent() Gets the next entry in the device table
+ * _freedevtabent() Frees memory allocated to a device-table entry
+ * _getdevrec() Gets a specific record from the device table
+ * _devtabpath() Get the pathname of the device table file
+ * _validalias() Is a value a valid alias?
+ */
+
+/*
+ * Header files
+ *
+ * <sys/sysmacros.h> System macro definitions
+ * <sys/types.h> System data types
+ * <sys/mkdev.h> Device Macros
+ * <unistd.h> System Symbolic Constants
+ * <stdio.h> Standard I/O definitions
+ * <string.h> String handling definitions
+ * <ctype.h> Character types and macros
+ * <errno.h> Error codes
+ * <sys/stat.h> File status information
+ * <devmgmt.h> Global Device Management definitions
+ * "devtab.h" Local Device Management definitions
+ */
+
+#include <sys/sysmacros.h>
+#include <sys/types.h>
+#ifndef SUNOS41
+#include <sys/mkdev.h>
+#endif
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <devmgmt.h>
+#include "devtab.h"
+#include <stdlib.h>
+
+/*
+ * Static data definitions:
+ * dtabrecnum Record number of the current record (0 to n-1)
+ * leftoff Addr of char to begin next parse using
+ * getfld(), getattrval(), getquoted()
+ * recbufsz The size of the buffer used for reading records
+ * recbuf Addr of malloc() buffer for reading records
+ * xtndcnt Number of malloc()/realloc() calls on record buffer
+ */
+
+static int xtndcnt = 0;
+static char *recbuf = NULL;
+static int recbufsz = 0;
+
+static char *leftoff = NULL;
+static int dtabrecnum = 0;
+
+/*
+ * int samedev(x, y)
+ * struct stat x, y
+ *
+ * Compares pertinent information in a stat() structure
+ * to see if the two structures describe the same device.
+ * If the file modes are the same and they have the same
+ * file system and i-node (i.e. they're links) or they
+ * are block or character devices and have the same major
+ * and minor device numbers (i.e. "mknod"s for the same
+ * device), it's the same device.
+ *
+ * Returns: int
+ * TRUE if the two structures describe the same device
+ * FALSE otherwise
+ */
+
+static int
+samedev(struct stat64 x, struct stat64 y)
+{
+ int same;
+
+
+ /* If the devices are of the same type ... */
+ if ((x.st_mode & 0170000) == (y.st_mode & 0170000)) {
+
+ /*
+ * If they are described by the same inode on the same device,
+ * the two devices are the same. Otherwise, if the devices are
+ * character-special or block-special devices, try to match by
+ * device type and major and minor device numbers.
+ */
+
+ if ((x.st_dev == y.st_dev) && (x.st_ino == y.st_ino)) same = TRUE;
+ else
+ if (((x.st_mode & 0170000) == 0020000) ||
+ ((x.st_mode & 0170000) == 0060000)) {
+ if ((major(x.st_rdev) == major(y.st_rdev)) &&
+ (minor(x.st_rdev) == minor(y.st_rdev))) same = TRUE;
+ else same = FALSE;
+ } else same = FALSE;
+
+ } else same = FALSE;
+
+ return (same);
+}
+
+/*
+ * void _setdevtab()
+ *
+ * This function rewinds the open device table so that the next
+ * _getdevtabent() returns the first record in the device table.
+ *
+ * Arguments: None
+ *
+ * Returns: Void
+ */
+
+void
+_setdevtab(void)
+{
+ /* If the device table file is open, rewind the file */
+ if (oam_devtab != NULL) {
+ rewind(oam_devtab);
+ dtabrecnum = 0;
+ }
+}
+
+/*
+ * void _enddevtab()
+ *
+ * This function closes the open device table. It resets the
+ * open device table external variable to NULL.
+ *
+ * Arguments: None
+ *
+ * Returns: Void
+ */
+
+void
+_enddevtab(void)
+{
+ /* If the device table file is open, close it */
+ if (oam_devtab != NULL) {
+ (void) fclose(oam_devtab);
+ oam_devtab = NULL;
+ dtabrecnum = 0;
+ }
+}
+
+/*
+ * char *getfld(ptr, delims)
+ * char *ptr
+ * char *delims
+ *
+ * Notes:
+ * - Can't use "strtok()" because of its use of static data. The caller
+ * may be using strtok() and we'll really mess them up.
+ * - The function returns NULL if it didn't find any token -- '\0' can't
+ * be a delimiter using this algorithm.
+ */
+
+static char *
+getfld(
+ char *ptr, /* String to parse */
+ char *delims) /* List of delimiters */
+{
+ int done; /* TRUE if we're finished */
+ char *p, *q; /* Temp pointers */
+
+ /*
+ * Figure out where to start.
+ * If given a pointer, use that.
+ * Otherwise, use where we left off.
+ */
+
+ p = ptr ? ptr : leftoff;
+
+
+ /*
+ * If there's anything to parse, search the string for the first
+ * occurrence of any of the delimiters. If one is found, change it
+ * to '\0' and remember the place to start for next time. If not
+ * found, forget the restart address and prepare to return NULL.
+ * Don't terminate on "escaped" characters.
+ */
+
+ if (p) { /* Anything to do ?? */
+ q = p; /* Where to begin */
+ done = FALSE; /* We're not done yet */
+ while (*q && !done) { /* Any more chars */
+ if (*q == '\\') { /* Escaped ? */
+ if (*(++q)) q++; /* Skip escaped char */
+ } else /* Not escaped */
+ if (!strchr(delims, *q)) q++; /* Skip non-delim */
+ else done = TRUE; /* Otherwise, done */
+ }
+ if (*q) { /* Terminator found? */
+ *q++ = '\0'; /* Null-terminate token */
+ leftoff = q; /* Remember restart pt. */
+ } else
+ leftoff = p = NULL; /* Nothin found or left */
+ }
+
+ /* Finished */
+ return (p); /* Return ptr to token */
+}
+
+/*
+ * char *getquoted(ptr)
+ * char *ptr;
+ *
+ * This function extracts a quoted string from the string pointed
+ * to by <ptr>, or, if <ptr> is NULL, wherever we left off
+ * last time.
+ *
+ * Arguments:
+ * char *ptr Pointer to the character-string to parse, or
+ * (char *) NULL if we're to pick up where we
+ * [getquoted(), getfld(), and getattrval()] left off.
+ *
+ * Returns: char *
+ * The address of malloc()ed space that contains the possibly quoted
+ * string.
+ *
+ * Notes:
+ * - This code only works if it can assume that the last character in
+ * the string it's parsing is a '\n', something that is guarenteed
+ * by the getnextrec() function.
+ */
+
+static char *
+getquoted(char *ptr)
+{
+ /* Automatic data */
+ char *rtn; /* Value to return */
+ char *p, *q; /* Temps */
+
+ /* Figure out where to start off */
+ p = ptr ? ptr : leftoff;
+
+ /* If there's anything to parse and it's a quoted string ... */
+ if ((p) && (*p == '"') && (p = getfld(p+1, "\""))) {
+
+ /* Copy string for the caller */
+ if (rtn = malloc(strlen(p)+1)) { /* Malloc() space */
+ q = rtn; /* Set up temp ptr */
+ do {
+ if (*p == '\\') p++; /* Skip escape */
+ *q++ = *p; /* Copy char */
+ } while (*p++); /* While there's chars */
+ } else leftoff = rtn = NULL;
+ } else leftoff = rtn = NULL;
+
+ /* Fini */
+ return (rtn);
+}
+
+/*
+ * struct attrval *getattrval(ptr)
+ * char *ptr
+ *
+ * This function extracts the next attr=val pair from <ptr> or wherever
+ * getfld() left off...
+ *
+ * Arguments:
+ * char *ptr The string to parse, or (char *) NULL if we're to
+ * begin wherever we left off last time.
+ *
+ * Returns: struct attrval *
+ * The address of a malloc()ed structure containing the attribute and the
+ * value of the attr=val pair extracted.
+ */
+
+static struct attrval *
+getattrval(char *ptr)
+{
+ /* Automatic data */
+ struct attrval *rtn; /* Ptr to struct to return */
+ char *p, *q; /* Temp pointers */
+
+
+ /* Use what's given to us or wherever we left off */
+ p = ptr ? ptr : leftoff;
+
+ /* If there's anything to parse, extract the next attr=val pair */
+ if (p) {
+
+ /* Eat white space */
+ while (*p && isspace((unsigned char)*p)) p++;
+
+ /* Extract the attribute name, if any */
+ if (*p && getfld(p, "=")) {
+
+ /* Allocate space for the structure we're building */
+ if (rtn = malloc(sizeof (struct attrval))) {
+
+ /* Allocate space for the attribute name */
+ if (rtn->attr = malloc(strlen(p)+1)) {
+
+ /* Copy the attribute name into alloc'd space */
+ q = rtn->attr; /* Set up temp ptr */
+ do {
+ if (*p == '\\') p++; /* Skip escape */
+ *q++ = *p; /* Copy char */
+ } while (*p++); /* While more */
+
+ /* Extract the value */
+ if (!(rtn->val = getquoted(NULL))) {
+ /* Error getting value, free resources */
+ free(rtn->attr);
+ free(rtn);
+ leftoff = NULL;
+ rtn = NULL;
+ }
+ } else {
+ /* Error getting space for attribute, free resources */
+ free(rtn);
+ leftoff = NULL;
+ rtn = NULL;
+ }
+
+ } else {
+ /* No space for attr struct */
+ leftoff = NULL;
+ rtn = NULL;
+ }
+
+ } else {
+ /* No attribute name */
+ leftoff = NULL;
+ rtn = NULL;
+ }
+
+ } else {
+ /* Nothing to parse */
+ leftoff = NULL;
+ rtn = NULL;
+ }
+
+ /* Done */
+ return (rtn);
+}
+
+/*
+ * char *getnextrec()
+ *
+ * This function gets the next record from the input stream "oam_devtab"
+ * and puts it in the device-table record buffer (whose address is in
+ * "recbuf"). If the buffer is not allocated or is too small to
+ * accommodate the record, the function allocates more space to the
+ * buffer.
+ *
+ * Arguments: None
+ *
+ * Returns: char *
+ * The address of the buffer containing the record.
+ *
+ * Static Data Referenced:
+ * recbuf Address of the buffer containing records read from the
+ * device table file
+ * recbufsz Current size of the record buffer
+ * xtndcnt Number of times the record buffer has been extended
+ * oam_devtab Device table stream, expected to be open for (at
+ * least) reading
+ *
+ * Notes:
+ * - The string returned in the buffer <buf> ALWAYS end in a '\n' (newline)
+ * character followed by a '\0' (null).
+ */
+
+static char *
+getnextrec(void)
+{
+ /* Automatic data */
+ char *recp; /* Value to return */
+ char *p; /* Temp pointer */
+ int done; /* TRUE if we're finished */
+ int reclen; /* Number of chars in record */
+
+
+ /* If there's no buffer for records, try to get one */
+ if (!recbuf) {
+ if (recbuf = malloc(DTAB_BUFSIZ)) {
+ recbufsz = DTAB_BUFSIZ;
+ xtndcnt = 0;
+ } else return (NULL);
+ }
+
+
+ /* Get the next record */
+ recp = fgets(recbuf, recbufsz, oam_devtab);
+ done = FALSE;
+
+ /* While we've something to return and we're not finished ... */
+ while (recp && !done) {
+
+ /* If our return string isn't a null-string ... */
+ if ((reclen = (int)strlen(recp)) != 0) {
+
+ /* If we have a complete record, we're finished */
+ if ((*(recp+reclen-1) == '\n') &&
+ ((reclen == 1) || (*(recp+reclen-2) != '\\'))) done = TRUE;
+ else while (!done) {
+
+ /*
+ * Need to complete the record. A complete record is
+ * one which is terminated by an unescaped new-line
+ * character.
+ */
+
+ /* If the buffer is full, expand it and continue reading */
+ if (reclen == recbufsz-1) {
+
+ /* Have we reached our maximum extension count? */
+ if (xtndcnt < XTND_MAXCNT) {
+
+ /* Expand the record buffer */
+ if (p = realloc(recbuf,
+ (size_t)recbufsz+DTAB_BUFINC)) {
+
+ /* Update buffer information */
+ xtndcnt++;
+ recbuf = p;
+ recbufsz += DTAB_BUFINC;
+
+ } else {
+
+ /* Expansion failed */
+ recp = NULL;
+ done = TRUE;
+ }
+
+ } else {
+
+ /* Maximum extend count exceeded. Insane table */
+ recp = NULL;
+ done = TRUE;
+ }
+
+ }
+
+ /* Complete the record */
+ if (!done) {
+
+ /* Read stuff into the expanded space */
+ if (fgets(recbuf+reclen, recbufsz-reclen, oam_devtab)) {
+ reclen = (int)strlen(recbuf);
+ recp = recbuf;
+ if ((*(recp+reclen-1) == '\n') &&
+ ((reclen == 1) || (*(recp+reclen-2) != '\\')))
+ done = TRUE;
+ } else {
+ /* Read failed, corrupt record? */
+ recp = NULL;
+ done = TRUE;
+ }
+ }
+
+ } /* End incomplete record handling */
+
+ } else {
+
+ /* Read a null string? (corrupt table) */
+ recp = NULL;
+ done = TRUE;
+ }
+
+ } /* while (recp && !done) */
+
+ /* Return what we've got (if anything) */
+ return (recp);
+}
+
+/*
+ * char *_devtabpath()
+ *
+ * Get the pathname of the device table
+ *
+ * Arguments: None
+ *
+ * Returns: char *
+ * Returns the pathname to the device table of NULL if
+ * there was a problem getting the memory needed to contain the
+ * pathname.
+ *
+ * Algorithm:
+ * 1. If OAM_DEVTAB is defined in the environment and is not
+ * defined as "", it returns the value of that environment
+ * variable.
+ * 2. Otherwise, use the value of the environment variable DTAB_PATH.
+ */
+
+
+char *
+_devtabpath(void)
+{
+
+ /* Automatic data */
+#ifdef DEBUG
+ char *path; /* Ptr to path in environment */
+#endif
+ char *rtnval; /* Ptr to value to return */
+
+
+ /*
+ * If compiled with -DDEBUG=1,
+ * look for the pathname in the environment
+ */
+
+#ifdef DEBUG
+ if (((path = getenv(OAM_DEVTAB)) != NULL) && (*path)) {
+ if (rtnval = malloc(strlen(path)+1))
+ (void) strcpy(rtnval, path);
+ } else {
+#endif
+ /*
+ * Use the standard device table.
+ */
+
+ if (rtnval = malloc(strlen(DTAB_PATH)+1))
+ (void) strcpy(rtnval, DTAB_PATH);
+
+#ifdef DEBUG
+ }
+#endif
+
+ /* Finished */
+ return (rtnval);
+}
+
+/*
+ * int _opendevtab(mode)
+ * char *mode
+ *
+ * The _opendevtab() function opens a device table for a command.
+ *
+ * Arguments:
+ * mode The open mode to use to open the file. (i.e. "r" for
+ * reading, "w" for writing. See FOPEN(BA_OS) in SVID.)
+ *
+ * Returns: int
+ * TRUE if it successfully opens the device table file, FALSE otherwise
+ */
+
+int
+_opendevtab(char *mode)
+{
+ /*
+ * Automatic data
+ */
+
+ char *devtabname; /* Ptr to the device table name */
+ int rtnval; /* Value to return */
+
+
+ rtnval = TRUE;
+ if (devtabname = _devtabpath()) {
+ if (oam_devtab) (void) fclose(oam_devtab);
+ if (oam_devtab = fopen(devtabname, mode))
+ dtabrecnum = 0; /* :-) */
+ else rtnval = FALSE; /* :-( */
+ } else rtnval = FALSE; /* :-( */
+ return (rtnval);
+}
+
+/*
+ * int _validalias(alias)
+ * char *alias
+ *
+ * Determine if <alias> is a valid alias. Returns TRUE if it is
+ * a valid alias, FALSE otherwise.
+ *
+ * Arguments:
+ * alias Value to check out
+ *
+ * Returns: int
+ * TRUE if <alias> is a valid alias, FALSE otherwise.
+ */
+
+int
+_validalias(char *alias) /* Alias to validate */
+{
+ /* Automatic data */
+ char *p; /* Temp pointer */
+ size_t len; /* Length of <alias> */
+ int rtn; /* Value to return */
+
+
+ /* Assume the worst */
+ rtn = FALSE;
+
+ /*
+ * A valid alias contains 0 < i <= 14 characters. The first
+ * must be alphanumeric or "@$_." and the rest must be alphanumeric
+ * or "@#$_+-."
+ */
+
+ /* Check length */
+ if ((alias != NULL) && ((len = strlen(alias)) > 0) && (len <= 14)) {
+
+ /* Check the first character */
+ p = alias;
+ if (isalnum((unsigned char)*p) || strchr("@$_.", *p)) {
+
+ /* Check the rest of the characters */
+ for (p++; *p && (isalnum((unsigned char)*p) ||
+ strchr("@#$_-+.", *p)); p++)
+ ;
+ if (!(*p)) rtn = TRUE;
+ }
+ }
+
+ /* Return indicator... */
+ return (rtn);
+
+} /* int _validalias() */
+
+/*
+ * struct devtabent *_getdevtabent()
+ *
+ * This function returns the next entry in the device table.
+ * If no device table is open, it opens the standard device table
+ * and returns the first record in the table.
+ *
+ * Arguments: None.
+ *
+ * Returns: struct devtabent *
+ * Pointer to the next record in the device table, or
+ * (struct devtabent *) NULL if it was unable to open the file or there
+ * are no more records to read. "errno" reflects the situation. If
+ * errno is not changed and the function returns NULL, there are no more
+ * records to read. If errno is set, it indicates the error.
+ *
+ * Notes:
+ * - The caller should set "errno" to 0 before calling this function.
+ */
+
+struct devtabent *
+_getdevtabent(void)
+{
+ /* Automatic data */
+ struct devtabent *ent; /* Ptr to dev table entry structure */
+ struct attrval *attr; /* Ptr to struct for attr/val pair */
+ struct attrval *t; /* Tmp ptr to attr/val struct */
+ char *record; /* Ptr to the record just read */
+ char *p, *q; /* Tmp char ptrs */
+ int done; /* TRUE if we've built an entry */
+
+
+ /* Open the device table if it's not already open */
+ if (oam_devtab == NULL) {
+ if (!_opendevtab("r"))
+ return (NULL);
+ }
+
+ /* Get space for the structure we're returning */
+ if (!(ent = malloc(sizeof (struct devtabent)))) {
+ return (NULL);
+ }
+
+ done = FALSE;
+ while (!done && (record = getnextrec())) {
+
+ /* Save record number in structure */
+ ent->entryno = dtabrecnum++;
+
+ /* Comment record? If so, just save the value and we're through */
+ if (strchr("#\n", *record) || isspace((unsigned char)*record)) {
+ ent->comment = TRUE;
+ done = TRUE;
+ if (ent->attrstr = malloc(strlen(record)+1)) {
+ q = ent->attrstr;
+ p = record;
+ do {
+ if (*p == '\\') p++;
+ *q++ = *p;
+ } while (*p++);
+ } else {
+ free(ent);
+ ent = NULL;
+ }
+ }
+
+ else {
+
+ /* Record is a data record. Parse it. */
+ ent->comment = FALSE;
+ ent->attrstr = NULL; /* For now */
+
+ /* Extract the device alias */
+ if (p = getfld(record, ":")) {
+ if (*p) {
+ if (ent->alias = malloc(strlen(p)+1)) {
+ q = ent->alias;
+ do {
+ if (*p == '\\') p++;
+ *q++ = *p;
+ } while (*p++);
+ }
+ } else ent->alias = NULL;
+
+ /* Extract the character-device name */
+ if ((p = getfld(NULL, ":")) == NULL) {
+ if (ent->alias)
+ free(ent->alias);
+ } else {
+ if (*p) {
+ if (ent->cdevice = malloc(strlen(p)+1)) {
+ q = ent->cdevice;
+ do {
+ if (*p == '\\') p++;
+ *q++ = *p;
+ } while (*p++);
+ }
+ } else ent->cdevice = NULL;
+
+ /* Extract the block-device name */
+ if (!(p = getfld(NULL, ":"))) {
+ if (ent->alias) free(ent->alias);
+ if (ent->cdevice) free(ent->cdevice);
+ } else {
+ if (*p) {
+ if (ent->bdevice = malloc(strlen(p)+1)) {
+ q = ent->bdevice;
+ do {
+ if (*p == '\\') p++;
+ *q++ = *p;
+ } while (*p++);
+ }
+ } else
+ ent->bdevice = NULL;
+
+ /* Extract the pathname */
+ if ((p = getfld(NULL, ":\n")) == NULL) {
+ if (ent->alias) free(ent->alias);
+ if (ent->cdevice) free(ent->cdevice);
+ if (ent->bdevice) free(ent->bdevice);
+ } else {
+ if (*p) {
+ if (ent->pathname = malloc(strlen(p)+1)) {
+ q = ent->pathname;
+ do {
+ if (*p == '\\') p++;
+ *q++ = *p;
+ } while (*p++);
+ }
+ } else
+ ent->pathname = NULL;
+
+ /* Found a valid record */
+ done = TRUE;
+
+ /*
+ * Extract attributes, build a linked list of
+ * 'em (may be none)
+ */
+ if (attr = getattrval(NULL)) {
+ ent->attrlist = attr;
+ t = attr;
+ while (attr = getattrval(NULL)) {
+ t->next = attr;
+ t = attr;
+ }
+ t->next = NULL;
+ } else
+ ent->attrlist = NULL;
+
+ } /* pathname extracted */
+ } /* bdevice extracted */
+ } /* cdevice extracted */
+ } /* alias extracted */
+ }
+ } /* !done && record read */
+
+ /* If no entry was read, free space allocated to the structure */
+ if (!done) {
+ free(ent);
+ ent = NULL;
+ }
+
+ return (ent);
+}
+
+/*
+ * void _freedevtabent(devtabent)
+ * struct devtabent *devtabent;
+ *
+ * This function frees space allocated to a device table entry.
+ *
+ * Arguments:
+ * struct devtabent *devtabent The structure whose space is to be
+ * freed.
+ *
+ * Returns: void
+ */
+
+void
+_freedevtabent(struct devtabent *ent)
+{
+ /*
+ * Automatic data
+ */
+
+ struct attrval *p; /* Structure being freed */
+ struct attrval *q; /* Next structure to free */
+
+ if (!ent->comment) {
+
+ /*
+ * Free the attribute list. For each item in the attribute
+ * list,
+ * 1. Free the attribute name (always defined),
+ * 2. Free the value (if any -- it's not defined if we're
+ * changing an existing attribute),
+ * 3. Free the space allocated to the structure.
+ */
+
+ q = ent->attrlist;
+ if (q)
+ do {
+ p = q;
+ q = p->next;
+ free(p->attr);
+ if (p->val) free(p->val);
+ free(p);
+ } while (q);
+
+ /* Free the standard fields (alias, cdevice, bdevice, pathname) */
+ if (ent->alias) free(ent->alias);
+ if (ent->cdevice) free(ent->cdevice);
+ if (ent->bdevice) free(ent->bdevice);
+ if (ent->pathname) free(ent->pathname);
+ }
+
+ /* Free the attribute string */
+ if (ent->attrstr) free(ent->attrstr);
+
+ /* Free the space allocated to the structure */
+ free(ent);
+}
+
+/*
+ * struct devtabent *_getdevrec(device)
+ * char *device
+ *
+ * Thie _getdevrec() function returns a pointer to a structure that
+ * contains the information in the device-table entry that describes
+ * the device <device>.
+ *
+ * The device <device> can be a device alias, a pathname contained in
+ * the entry as the "cdevice", "bdevice", or "pathname" attribute,
+ * or a pathname to a device described using the "cdevice", "bdevice",
+ * or "pathname" attribute (depending on whether the pathname references
+ * a character-special file, block-special file, or something else,
+ * respectively.
+ *
+ * Arguments:
+ * char *device A character-string describing the device whose record
+ * is to be retrieved from the device table.
+ *
+ * Returns: struct devtabent *
+ * A pointer to a structure describing the device.
+ *
+ * Notes:
+ * - Someday, add a cache so that repeated requests for the same record
+ * don't require going to the filesystem. (Maybe -- this might belong
+ * in devattr()...)
+ */
+
+struct devtabent *
+_getdevrec(char *device) /* The device to search for */
+{
+ /*
+ * Automatic data
+ */
+
+ struct stat64 devstatbuf; /* Stat struct, <device> */
+ struct stat64 tblstatbuf; /* Stat struct, tbl entry */
+ struct devtabent *devrec; /* Pointer to current record */
+ int found; /* TRUE if record found */
+ int olderrno; /* Old value of errno */
+
+
+ /*
+ * Search the device table looking for the requested device
+ */
+
+ _setdevtab();
+ olderrno = errno;
+ found = FALSE;
+ if ((device != NULL) && !_validalias(device)) {
+ while (!found && (devrec = _getdevtabent())) {
+ if (!devrec->comment) {
+ if (devrec->cdevice)
+ if (strcmp(device, devrec->cdevice) == 0) found = TRUE;
+ if (devrec->bdevice)
+ if (strcmp(device, devrec->bdevice) == 0) found = TRUE;
+ if (devrec->pathname)
+ if (strcmp(device, devrec->pathname) == 0) found = TRUE;
+ } else _freedevtabent(devrec);
+ }
+
+ /*
+ * If the device <device> wasn't named explicitly in the device
+ * table, compare it against like entries by comparing file-
+ * system, major device number, and minor device number
+ */
+
+ if (!found) {
+ _setdevtab();
+
+ /* Status the file <device>. If fails, invalid device */
+ if (stat64(device, &devstatbuf) != 0) errno = ENODEV;
+ else {
+
+ /*
+ * If <device> is a block-special device. See if it is
+ * in the table by matching its file-system indicator
+ * and major/minor device numbers against the
+ * file-system and major/minor device numbers of the
+ * "bdevice" entries.
+ */
+
+ if ((devstatbuf.st_mode & 0170000) == 0020000) {
+ while (!found && (devrec = _getdevtabent())) {
+ if (!devrec->comment &&
+ (devrec->cdevice != NULL))
+ if (stat64(devrec->cdevice, &tblstatbuf) == 0) {
+ if (samedev(tblstatbuf, devstatbuf))
+ found = TRUE;
+ } else {
+ /* Ignore stat() errs */
+ errno = olderrno;
+ }
+ if (!found) _freedevtabent(devrec);
+ }
+ }
+
+ /*
+ * If <device> is a block-special device. See if it is
+ * in the table by matching its file-system indicator
+ * and major/minor device numbers against the
+ * file-system and major/minor device numbers of the
+ * "bdevice" entries.
+ */
+
+ else if ((devstatbuf.st_mode & 0170000) == 0060000) {
+ while (!found && (devrec = _getdevtabent())) {
+ if (!devrec->comment &&
+ (devrec->bdevice != NULL))
+ if (stat64(devrec->bdevice, &tblstatbuf) == 0) {
+ if (samedev(tblstatbuf, devstatbuf))
+ found = TRUE;
+ } else {
+ /* Ignore stat() errs */
+ errno = olderrno;
+ }
+ if (!found) _freedevtabent(devrec);
+ }
+ }
+
+ /*
+ * If <device> is neither a block-special or character-
+ * special device. See if it is in the table by
+ * matching its file-system indicator and major/minor
+ * device numbers against the file-system and
+ * major/minor device numbers of the "pathname" entries.
+ */
+
+ else {
+ while (!found && (devrec = _getdevtabent())) {
+ if (!devrec->comment &&
+ (devrec->pathname != NULL))
+ if (stat64(devrec->pathname,
+ &tblstatbuf) == 0) {
+ if (samedev(tblstatbuf, devstatbuf))
+ found = TRUE;
+ } else {
+ /* Ignore stat() errs */
+ errno = olderrno;
+ }
+ if (!found) _freedevtabent(devrec);
+ }
+ }
+
+ if (!found) {
+ devrec = NULL;
+ errno = ENODEV;
+ }
+
+ } /* End case where stat() on the <device> succeeded */
+
+ } /* End case handling pathname not explicitly in device table */
+
+ } /* End case handling <device> as a fully-qualified pathname */
+
+
+ /*
+ * Otherwise the device <device> is an alias.
+ * Search the table for a record that has as the "alias" attribute
+ * the value <device>.
+ */
+
+ else {
+ while (!found && (devrec = _getdevtabent())) {
+ if (!devrec->comment && (device != NULL) &&
+ strcmp(device, devrec->alias) == 0)
+ found = TRUE;
+ else _freedevtabent(devrec);
+ }
+ if (!found) {
+ devrec = NULL;
+ errno = ENODEV;
+ }
+ }
+
+ /* Fini */
+ return (devrec);
+}
diff --git a/usr/src/lib/libadm/common/dgrpent.c b/usr/src/lib/libadm/common/dgrpent.c
new file mode 100644
index 0000000000..0e48c9a1b8
--- /dev/null
+++ b/usr/src/lib/libadm/common/dgrpent.c
@@ -0,0 +1,661 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright (c) 1997,1998,2002 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+/*LINTLIBRARY*/
+
+/*
+ * dgrpent.c
+ *
+ * Contains functions that deal with the device-group table and are not for
+ * consumption by the general user population.
+ *
+ * Functions defined:
+ * _opendgrptab() Opens the device-group table for commands
+ * _setdgrptab() Rewinds the open device table
+ * _enddgrptab() Closes the open device table
+ * _getdgrptabent() Gets the next entry in the device table
+ * _freedgrptabent() Frees memory allocated to a device-table entry
+ * _getdgrprec() Gets a specific record from the device table
+ * _dgrptabpath() Gets the pathname of the device group file
+ */
+
+/*
+ * Header files
+ * <sys/types.h> System data types
+ * <unistd.h> Standard UNIX(r) definitions
+ * <stdio.h> Standard I/O Definitions
+ * <string.h> String handling definitions
+ * <ctype.h> Character types and macros
+ * <errno.h> Errorcode definitions
+ * <sys/stat.h> File status information
+ * <devmgmt.h> Global Device Management definitions
+ * "devtab.h" Local device table definitions
+ */
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <devmgmt.h>
+#include "devtab.h"
+#include <stdlib.h>
+
+/*
+ * Local definitions
+ */
+
+
+/*
+ * Static data definitions:
+ * leftoff Addr of char to begin next parse using
+ * getfld(), getattrval(), getquoted()
+ * recbufsz The size of the buffer used for reading records
+ * recbuf Addr of malloc() buffer for reading records
+ * recnum Record number of next record to read
+ * xtndcnt Number of times the buffer has been extended
+ */
+
+static char *leftoff = NULL;
+static int recbufsz = 0;
+static char *recbuf = NULL;
+static int recnum = 0;
+static int xtndcnt = 0;
+
+/*
+ * void _setdgrptab()
+ *
+ * This function rewinds the open device table so that the next
+ * _getdgrptabent() returns the first record in the device table.
+ *
+ * Arguments: None
+ *
+ * Returns: Void
+ */
+
+void
+_setdgrptab(void)
+{
+ /* If the device table file is open, rewind the file */
+ if (oam_dgroup) {
+ rewind(oam_dgroup);
+ recnum = 0;
+ }
+}
+
+/*
+ * void _enddgrptab()
+ *
+ * This function closes the open device table. It resets the
+ * open device table external variable to NULL.
+ *
+ * Arguments: None
+ *
+ * Returns: Void
+ */
+
+void
+_enddgrptab(void)
+{
+ /* If the device table file is open, close it */
+ if (oam_dgroup) {
+ (void) fclose(oam_dgroup);
+ recnum = 0;
+ oam_dgroup = NULL;
+ }
+}
+
+/*
+ * char *getfld(ptr, delims)
+ * char *ptr
+ * char *delims
+ *
+ * Notes:
+ * - Can't use "strtok()" because of its use of static data. The caller
+ * may be using strtok() and we'll really mess them up.
+ * - The function returns NULL if it didn't find any token -- '\0' can't
+ * be a delimiter using this algorithm.
+ */
+
+static char *
+getfld(
+ char *ptr, /* String to parse */
+ char *delims) /* List of delimiters */
+{
+ char *p, *q;
+
+ /*
+ * Figure out where to start.
+ * If given a pointer, use that.
+ * Otherwise, use where we left off.
+ */
+
+ p = ptr ? ptr : leftoff;
+
+
+ /*
+ * If there's anything to parse, search the string for the first
+ * occurrence of any of the delimiters. If one is found, change it
+ * to '\0' and remember the place to start for next time. If not
+ * found, forget the restart address and prepare to return NULL
+ */
+
+ if (p) {
+ while (*p && isspace((unsigned char)*p)) p++;
+ if (*p) {
+ q = p;
+ while (*q && !strchr(delims, *q)) q++;
+ if (*q) {
+ *q++ = '\0';
+ leftoff = q;
+ } else leftoff = NULL;
+ } else leftoff = p = NULL;
+ }
+
+ /* Finished */
+ return (p);
+}
+
+/*
+ * char *getnextrec()
+ *
+ * This function gets the next record from the input stream "oam_dgroup"
+ * and puts it in the device-group table record buffer (whose address is
+ * in "recbuf"). If the buffer is not allocated or is too small to
+ * accommodate the record, the function allocates more space to the
+ * buffer.
+ *
+ * Arguments: None
+ *
+ * Returns: char *
+ * The address of the buffer containing the record.
+ *
+ * Static Data Referenced:
+ * recbuf Address of the buffer containing records read from the
+ * device table file
+ * recbufsz Current size of the record buffer
+ * xtndcnt Number of times the record buffer has been extended
+ * oam_dgroup Device-group table stream, expected to be open for (at
+ * least) reading
+ *
+ * Notes:
+ * - The string returned in the buffer <buf> ALWAYS end in a '\n' (newline)
+ * character followed by a '\0' (null).
+ */
+
+static char *
+getnextrec(void)
+{
+ /* Automatic data */
+ char *recp; /* Value to return */
+ char *p; /* Temp pointer */
+ int done; /* TRUE if we're finished */
+ int reclen; /* Number of chars in record */
+
+
+ /* If there's no buffer for records, try to get one */
+ if (!recbuf) {
+ if (recbuf = malloc(DGRP_BUFSIZ)) {
+ recbufsz = DGRP_BUFSIZ;
+ xtndcnt = 0;
+ } else return (NULL);
+ }
+
+
+ /* Get the next record */
+ recp = fgets(recbuf, recbufsz, oam_dgroup);
+ done = FALSE;
+
+ /* While we've something to return and we're not finished ... */
+ while (recp && !done) {
+
+ /* If our return string isn't a null-string ... */
+ if ((reclen = (int)strlen(recp)) != 0) {
+
+ /* If we have a complete record, we're finished */
+ if (*(recp+reclen-1) == '\n') done = TRUE;
+ else while (!done) {
+
+ /*
+ * Need to complete the record. A complete record is one
+ * which is terminated by a new-line character
+ */
+
+ /* If the buffer is full, expand it and continue reading */
+ if (reclen == recbufsz-1) {
+
+ /* Have we reached our maximum extension count? */
+ if (xtndcnt < XTND_MAXCNT) {
+
+ /* Expand the record buffer */
+ if (p = realloc(recbuf,
+ (size_t)(recbufsz+DGRP_BUFINC))) {
+
+ /* Update buffer information */
+ xtndcnt++;
+ recbuf = p;
+ recbufsz += DGRP_BUFINC;
+
+ } else {
+
+ /* Expansion failed */
+ recp = NULL;
+ done = TRUE;
+ }
+
+ } else {
+
+ /* Maximum extend count exceeded. Insane table */
+ recp = NULL;
+ done = TRUE;
+ }
+
+ }
+
+ /* Complete the record */
+ if (!done) {
+
+ /* Read stuff into the expanded space */
+ if (fgets(recbuf+reclen, recbufsz-reclen, oam_dgroup)) {
+ reclen = (int)strlen(recbuf);
+ recp = recbuf;
+ if (*(recp+reclen-1) == '\n') done = TRUE;
+ } else {
+ /* Read failed, corrupt record? */
+ recp = NULL;
+ done = TRUE;
+ }
+ }
+
+ } /* End incomplete record handling */
+
+ } else {
+
+ /* Read a null string? (corrupt table) */
+ recp = NULL;
+ done = TRUE;
+ }
+
+ } /* while (recp && !done) */
+
+ /* Return what we've got (if anything) */
+ return (recp);
+}
+
+/*
+ * char *_dgrptabpath()
+ *
+ * Get the pathname of the device-group table file
+ *
+ * Arguments: None
+ *
+ * Returns: char *
+ * Returns the pathname to the device group table of (char *) NULL if
+ * there was a problem getting the memory needed to contain the
+ * pathname.
+ *
+ * Algorithm:
+ * 1. If OAM_DGRP is defined in the environment and is not
+ * defined as "", it returns the value of that environment
+ * variable.
+ * 2. Otherwise, use the devault pathname (as defined by the
+ * environment variable DGRP_PATH in <devmgmt.h>.
+ */
+
+
+char *
+_dgrptabpath(void)
+{
+
+ /* Automatic data */
+#ifdef DEBUG
+ char *path; /* Ptr to path in environment */
+#endif
+ char *rtnval; /* Ptr to value to return */
+
+
+ /*
+ * If compiled with -DDEBUG=1,
+ * look for the pathname in the environment
+ */
+
+#ifdef DEBUG
+ if (((path = getenv(OAM_DGROUP)) != NULL) && (*path)) {
+ if (rtnval = malloc(strlen(path)+1))
+ (void) strcpy(rtnval, path);
+ } else {
+#endif
+ /*
+ * Use the default name.
+ */
+
+ if (rtnval = malloc(strlen(DGRP_PATH)+1))
+ (void) strcpy(rtnval, DGRP_PATH);
+
+#ifdef DEBUG
+ }
+#endif
+
+ /* Finished */
+ return (rtnval);
+}
+
+/*
+ * int _opendgrptab(mode)
+ * char *mode
+ *
+ * The _opendgrptab() function opens a device-group table for a command.
+ *
+ * Arguments:
+ * mode The open mode to use to open the file. (i.e. "r" for
+ * reading, "w" for writing. See FOPEN(BA_OS) in SVID.)
+ *
+ * Returns: int
+ * TRUE if successful, FALSE otherwise
+ */
+
+int
+_opendgrptab(char *mode)
+{
+ /* Automatic data */
+ char *dgrptabname; /* Ptr to the device-group table name */
+ int rtnval; /* Value to return */
+
+ rtnval = TRUE;
+ if (dgrptabname = _dgrptabpath()) {
+ if (oam_dgroup) (void) fclose(oam_dgroup);
+ if (oam_dgroup = fopen(dgrptabname, mode)) {
+ xtndcnt = 0;
+ recnum = 0;
+ } else rtnval = FALSE; /* :-( */
+ } else rtnval = FALSE; /* :-( */
+ return (rtnval);
+}
+
+/*
+ * struct dgrptabent *_getdgrptabent()
+ *
+ * This function returns the next entry in the device-group table.
+ * If no device-group table is open, it opens the standard device-group
+ * table and returns the first record in the table.
+ *
+ * Arguments: None.
+ *
+ * Returns: struct dgrptabent *
+ * Pointer to the next record in the device-group table, or
+ * (struct dgrptabent *) NULL if it was unable to open the file or there
+ * are no more records to read. "errno" reflects the situation. If
+ * errno is not changed and the function returns NULL, there are no more
+ * records to read. If errno is set, it indicates the error.
+ *
+ * Notes:
+ * - The caller should set "errno" to 0 before calling this function.
+ */
+
+struct dgrptabent *
+_getdgrptabent(void)
+{
+ /* Automatic data */
+ struct dgrptabent *ent; /* Dev table entry structure */
+ struct member *q, *r; /* Tmps for member structs */
+ char *record; /* Record just read */
+ char *p; /* Tmp char ptr */
+ int done; /* TRUE if built an entry */
+
+
+ /* Open the device-group table if it's not already open */
+ if (!oam_dgroup)
+ if (!_opendgrptab("r"))
+ return (NULL);
+
+
+ /* Get space for the structure we're returning */
+ if (!(ent = malloc(sizeof (struct dgrptabent)))) {
+ return (NULL);
+ }
+
+ done = FALSE;
+ while (!done && (record = getnextrec())) {
+
+ /* Is this a comment record or a data record */
+ if (strchr("#\n", *record) ||
+ isspace((unsigned char)*record)) {
+
+ /*
+ * Record is a comment record
+ */
+ ent->comment = TRUE;
+ ent->entryno = recnum++;
+
+ /* Alloc space for the comment and save pointer in struct */
+ if (ent->dataspace = malloc(strlen(record)+1)) {
+ (void) strcpy(ent->dataspace, record);
+ } else {
+ free(ent);
+ ent = NULL;
+ }
+ done = TRUE;
+
+ } else {
+
+ /*
+ * Record is a data record
+ */
+ ent->comment = FALSE;
+
+ /* Extract the device-group name */
+ if (p = getfld(record, ":")) {
+
+ /* Record is a proper record */
+ done = TRUE;
+ ent->entryno = recnum++;
+
+ /* Copy device group name into malloc()ed space */
+ if (!(ent->name = malloc(strlen(p)+1))) {
+
+ free(ent);
+ return (NULL);
+ }
+ (void) strcpy(ent->name, p);
+
+ /*
+ * Extract the membership from the membership list
+ */
+
+ /* Get the 1st member */
+ ent->dataspace = NULL;
+ while (((p = getfld(NULL, ",\n")) != NULL) && !(*p))
+ ;
+ if (p) {
+ if (!(q = malloc(sizeof (struct member)))) {
+
+ free(ent->name);
+ free(ent);
+ return (NULL);
+ }
+ if (!(q->name = malloc(strlen(p)+1))) {
+ free(q);
+ free(ent->name);
+ free((char *)ent);
+ return (NULL);
+ }
+ (void) strcpy(q->name, p);
+ ent->membership = q;
+ q->next = NULL;
+
+ /* Get the rest of the members */
+ while (p = getfld(NULL, ",\n"))
+ if (*p) {
+ if (!(r = malloc(sizeof (struct member)))) {
+ for (q = ent->membership; q; q = r) {
+ free(q->name);
+ r = q->next;
+ free(q);
+ }
+ free(ent->name);
+ free(ent);
+ return (NULL);
+ }
+ if (!(r->name = malloc(strlen(p)+1))) {
+ free(r);
+ for (q = ent->membership; q; q = r) {
+ free(q->name);
+ r = q->next;
+ free(q);
+ }
+ free(ent->name);
+ free(ent);
+ return (NULL);
+ }
+
+ q->next = r;
+ (void) strcpy(r->name, p);
+ r->next = NULL;
+ q = r;
+ }
+
+ } else {
+ /* No members */
+ ent->membership = NULL;
+ }
+
+ } /* record contains a group name */
+
+ } /* record is a data record */
+
+ } /* while (!done && there's more records) */
+
+
+ /* An entry read? If not, free alloc'd space and return NULL */
+ if (!done) {
+ free(ent);
+ ent = NULL;
+ }
+
+ /* Finis */
+ return (ent);
+}
+
+/*
+ * void _freedgrptabent(dgrptabent)
+ * struct dgrptabent *dgrptabent;
+ *
+ * This function frees space allocated to a device table entry.
+ *
+ * Arguments:
+ * struct dgrptabent *dgrptabent The structure whose space is to be
+ * freed.
+ *
+ * Returns: void
+ */
+
+void
+_freedgrptabent(struct dgrptabent *ent) /* Structure to free */
+{
+ /*
+ * Automatic data
+ */
+
+ struct member *p; /* Structure being freed */
+ struct member *q; /* Next structure to free */
+
+ /*
+ * Free the space allocated to the membership structure.
+ */
+
+ if (!ent->comment) {
+ if ((q = ent->membership) != NULL) do {
+ p = q;
+ q = p->next;
+ if (p->name) free(p->name);
+ free(p);
+ } while (q);
+
+ /* Free the device group name */
+ if (ent->name) free(ent->name);
+ }
+
+ /* Free the membership string */
+ if (ent->dataspace) free(ent->dataspace);
+}
+
+/*
+ * struct dgrptabent *_getdgrprec(dgroup)
+ * char *dgroup
+ *
+ * Thie _getdgrprec() function returns a pointer to a structure that
+ * contains the information in the device-group table entry that describes
+ * the device-group <dgroup>.
+ *
+ * Arguments:
+ * char *dgroup A character-string describing the device-group whose
+ * record is to be retrieved from the device-group table.
+ *
+ * Returns: struct dgrptabent *
+ * A pointer to a structure describing the device group.
+ */
+
+struct dgrptabent *
+_getdgrprec(char *dgroup) /* dgroup to search for */
+{
+ /*
+ * Automatic data
+ */
+
+ struct dgrptabent *dgrprec; /* Pointer to current record */
+ int found; /* FLAG, TRUE if found */
+
+
+ /*
+ * Search the device-group table looking for the requested
+ * device group
+ */
+
+ _setdgrptab();
+ errno = 0;
+ found = FALSE;
+ while (!found && (dgrprec = _getdgrptabent())) {
+ if (!dgrprec->comment && strcmp(dgroup, dgrprec->name) == 0)
+ found = TRUE;
+ else _freedgrptabent(dgrprec);
+ }
+
+ /* Set up return codes if we've failed */
+ if (!found) {
+ if (errno == 0) errno = EINVAL;
+ dgrprec = NULL;
+ }
+
+ /* Finis */
+ return (dgrprec);
+}
diff --git a/usr/src/lib/libadm/common/fulldevnm.c b/usr/src/lib/libadm/common/fulldevnm.c
new file mode 100644
index 0000000000..f22035342e
--- /dev/null
+++ b/usr/src/lib/libadm/common/fulldevnm.c
@@ -0,0 +1,489 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+/*LINTLIBRARY*/
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include <sys/vfstab.h>
+#include <sys/lofi.h>
+#include <sys/ramdisk.h>
+#include <sys/fssnap_if.h>
+#include "libadm.h"
+
+/*
+ * Globals:
+ * getfullrawname - returns a fully-qualified raw device name
+ * getfullblkname - returns a fully-qualified block device name
+ *
+ * These two routines take a device pathname and return corresponding
+ * the raw or block device name.
+ *
+ * First the device name is fully qualified:
+ * If the device name does not start with a '/' or starts with
+ * './' then the current working directory is added to the beginning
+ * of the pathname.
+ *
+ * If the device name starts with a '../' then all but the last
+ * sub-directory of the current working directory is added to the
+ * the beginning of the pathname.
+ *
+ * Second if the fully-qualified device name given is the raw/block
+ * device that is being asked for then the fully-qualified device name is
+ * returned.
+ *
+ * Third if an entry is found in /etc/vfstab which matches the given name
+ * then the corresponding raw/block device is returned. This allows
+ * non-standard names to be converted (.i.e., block device "/dev/joe" can
+ * be converted to raw device "/dev/fred", via this mechanism).
+ *
+ * Last standard names are converted. Standard names are those
+ * with a '/dsk/' for block or '/rdsk/' for raw sub-directory components
+ * in the device name. Or, the filename component has an 'r' for raw or
+ * no 'r' for block (e.g., rsd0a <=> sd0a).
+ *
+ * Caveat:
+ * It is assumed that the block and raw devices have the
+ * same device number, and this is used to verify the conversion
+ * happened corretly. If this happens not to be true, due to mapping
+ * of minor numbers or sometheing, then entries can be put in the
+ * the '/etc/vfstab' file to over-ride this checking.
+ *
+ *
+ * Return Values:
+ * raw/block device name - (depending on which routine is used)
+ * null string - When the conversion failed
+ * null pointer - malloc problems
+ *
+ * It is up to the user of these routines to free the memory, of
+ * the device name or null string returned by these library routines,
+ * when appropriate by the application.
+ */
+#define GET_BLK 0
+#define GET_RAW 1
+
+static int test_if_blk(char *, dev_t);
+static int test_if_raw(char *, dev_t);
+static char *getblkcomplete(char *, struct stat64 *);
+static char *getrawcomplete(char *, struct stat64 *);
+
+/*
+ * getfullname() - Builds a fully qualified pathname.
+ * This handles . and .. as well.
+ * NOTE: This is different from realpath(3C) because
+ * it does not follow links.
+ */
+static char *
+getfullname(char *path)
+{
+ char cwd[MAXPATHLEN];
+ char *c;
+ char *wa;
+ size_t len;
+
+ if (*path == '/')
+ return (strdup(path));
+
+ if (getcwd(cwd, sizeof (cwd)) == NULL)
+ return (strdup(""));
+
+ /* handle . and .. */
+ if (strncmp(path, "./", 2) == 0) {
+ /* strip the ./ from the given path */
+ path += 2;
+ } else if (strncmp(path, "../", 3) == 0) {
+ /* strip the last directory component from cwd */
+ c = strrchr(cwd, '/');
+ *c = '\0';
+
+ /* strip the ../ from the given path */
+ path += 3;
+ }
+
+ /*
+ * Adding 2 takes care of slash and null terminator.
+ */
+ len = strlen(cwd) + strlen(path) + 2;
+ if ((wa = malloc(len)) == NULL)
+ return (NULL);
+
+ (void) strcpy(wa, cwd);
+ (void) strcat(wa, "/");
+ (void) strcat(wa, path);
+
+ return (wa);
+}
+
+/*
+ * test the path/fname to see if is blk special
+ */
+static int
+test_if_blk(char *new_path, dev_t raw_dev)
+{
+ struct stat64 buf;
+
+ /* check if we got a char special file */
+ if (stat64(new_path, &buf) != 0)
+ return (0);
+
+ if (!S_ISBLK(buf.st_mode))
+ return (0);
+
+ if (raw_dev != buf.st_rdev)
+ return (0);
+
+ return (1);
+}
+
+/*
+ * test the path/fname to see if is char special
+ */
+static int
+test_if_raw(char *new_path, dev_t blk_dev)
+{
+ struct stat64 buf;
+
+ /* check if we got a char special file */
+ if (stat64(new_path, &buf) != 0)
+ return (0);
+
+ if (!S_ISCHR(buf.st_mode))
+ return (0);
+
+ if (blk_dev != buf.st_rdev)
+ return (0);
+
+ return (1);
+}
+
+/*
+ * complete getblkrawname() for blk->raw to handle volmgt devices
+ */
+
+static char *
+getblkcomplete(char *cp, struct stat64 *dat)
+{
+ char *dp;
+ char *new_path;
+ char c;
+
+ /* ok, so we either have a bad device or a floppy */
+
+ /* try the rfd# form */
+ if ((dp = strstr(cp, "/rfd")) != NULL) {
+ if ((new_path = malloc(strlen(cp))) == NULL)
+ return (NULL);
+
+ c = *++dp; /* save the 'r' */
+ *dp = '\0'; /* replace it with a null */
+ (void) strcpy(new_path, cp); /* save first part of it */
+ *dp++ = c; /* give the 'r' back */
+ (void) strcat(new_path, dp); /* copy, skipping the 'r' */
+
+ if (test_if_blk(new_path, dat->st_rdev))
+ return (new_path);
+
+ free(new_path);
+ return (strdup(""));
+ }
+
+ /* try the rdiskette form */
+ if ((dp = strstr(cp, "/rdiskette")) != NULL) {
+ if ((new_path = malloc(strlen(cp))) == NULL)
+ return (NULL);
+
+ c = *++dp; /* save the 'r' */
+ *dp = '\0'; /* replace it with a null */
+ (void) strcpy(new_path, cp); /* save first part of it */
+ *dp++ = c; /* give the 'r' back */
+ (void) strcat(new_path, dp); /* copy, skipping the 'r' */
+
+ if (test_if_blk(new_path, dat->st_rdev))
+ return (new_path);
+
+ free(new_path);
+ return (strdup(""));
+ }
+
+ /* no match found */
+ return (strdup(""));
+}
+
+/*
+ * complete getfullrawname() for raw->blk to handle volmgt devices
+ */
+
+static char *
+getrawcomplete(char *cp, struct stat64 *dat)
+{
+ char *dp;
+ char *new_path;
+ char c;
+
+ /* ok, so we either have a bad device or a floppy */
+
+ /* try the fd# form */
+ if ((dp = strstr(cp, "/fd")) != NULL) {
+ /* malloc path for new_path to hold raw */
+ if ((new_path = malloc(strlen(cp)+2)) == NULL)
+ return (NULL);
+
+ c = *++dp; /* save the 'f' */
+ *dp = '\0'; /* replace it with a null */
+ (void) strcpy(new_path, cp); /* save first part of it */
+ *dp = c; /* put the 'f' back */
+ (void) strcat(new_path, "r"); /* insert an 'r' */
+ (void) strcat(new_path, dp); /* copy the rest */
+
+ if (test_if_raw(new_path, dat->st_rdev))
+ return (new_path);
+
+ free(new_path);
+ }
+
+ /* try the diskette form */
+ if ((dp = strstr(cp, "/diskette")) != NULL) {
+ /* malloc path for new_path to hold raw */
+ if ((new_path = malloc(strlen(cp)+2)) == NULL)
+ return (NULL);
+
+ c = *++dp; /* save at 'd' */
+ *dp = '\0'; /* replace it with a null */
+ (void) strcpy(new_path, cp); /* save first part */
+ *dp = c; /* put the 'd' back */
+ (void) strcat(new_path, "r"); /* insert an 'r' */
+ (void) strcat(new_path, dp); /* copy the rest */
+
+ if (test_if_raw(new_path, dat->st_rdev))
+ return (new_path);
+
+ free(new_path);
+ return (strdup(""));
+ }
+
+ /* failed to build raw name, return null string */
+ return (strdup(""));
+
+
+
+}
+
+static char *
+getvfsspecial(char *path, int raw_special)
+{
+ FILE *fp;
+ struct vfstab vp;
+ struct vfstab ref_vp;
+
+ if ((fp = fopen("/etc/vfstab", "r")) == NULL)
+ return (NULL);
+
+ (void) memset(&ref_vp, 0, sizeof (struct vfstab));
+
+ if (raw_special)
+ ref_vp.vfs_special = path;
+ else
+ ref_vp.vfs_fsckdev = path;
+
+ if (getvfsany(fp, &vp, &ref_vp)) {
+ (void) fclose(fp);
+ return (NULL);
+ }
+
+ (void) fclose(fp);
+
+ if (raw_special)
+ return (vp.vfs_fsckdev);
+
+ return (vp.vfs_special);
+}
+
+/*
+ * change the device name to a block device name
+ */
+char *
+getfullblkname(char *cp)
+{
+ struct stat64 buf;
+ char *dp;
+ char *new_path;
+ dev_t raw_dev;
+
+ if (cp == NULL)
+ return (strdup(""));
+
+ /*
+ * Create a fully qualified name.
+ */
+ if ((cp = getfullname(cp)) == NULL)
+ return (NULL);
+
+ if (*cp == '\0')
+ return (cp);
+
+ if (stat64(cp, &buf) != 0) {
+ free(cp);
+ return (strdup(""));
+ }
+
+ if (S_ISBLK(buf.st_mode))
+ return (cp);
+
+ if (!S_ISCHR(buf.st_mode)) {
+ free(cp);
+ return (strdup(""));
+ }
+
+ if ((dp = getvfsspecial(cp, GET_BLK)) != NULL) {
+ free(cp);
+ return (strdup(dp));
+ }
+
+ raw_dev = buf.st_rdev;
+
+ /*
+ * We have a raw device name, go find the block name.
+ */
+ if ((dp = strstr(cp, "/rdsk/")) == NULL &&
+ (dp = strstr(cp, "/" LOFI_CHAR_NAME "/")) == NULL &&
+ (dp = strstr(cp, "/" RD_CHAR_NAME "/")) == NULL &&
+ (dp = strstr(cp, "/" SNAP_CHAR_NAME "/")) == NULL &&
+ (dp = strrchr(cp, '/')) == NULL) {
+ /* this is not really possible */
+ free(cp);
+ return (strdup(""));
+ }
+ dp++;
+ if (*dp != 'r') {
+ dp = getblkcomplete(cp, &buf);
+ free(cp);
+ return (dp);
+ }
+ if ((new_path = malloc(strlen(cp))) == NULL) {
+ free(cp);
+ return (NULL);
+ }
+ (void) strncpy(new_path, cp, dp - cp);
+
+ /* fill in the rest of the unraw name */
+ (void) strcpy(new_path + (dp - cp), dp + 1);
+
+ if (test_if_blk(new_path, raw_dev)) {
+ free(cp);
+ /* block name was found, return it here */
+ return (new_path);
+ }
+ free(new_path);
+
+ dp = getblkcomplete(cp, &buf);
+ free(cp);
+ return (dp);
+}
+
+/*
+ * change the device name to a raw devname
+ */
+char *
+getfullrawname(char *cp)
+{
+ struct stat64 buf;
+ char *dp;
+ char *new_path;
+ dev_t blk_dev;
+
+ if (cp == NULL)
+ return (strdup(""));
+
+ /*
+ * Create a fully qualified name.
+ */
+ if ((cp = getfullname(cp)) == NULL)
+ return (NULL);
+
+ if (*cp == '\0')
+ return (cp);
+
+ if (stat64(cp, &buf) != 0) {
+ free(cp);
+ return (strdup(""));
+ }
+
+ if (S_ISCHR(buf.st_mode))
+ return (cp);
+
+ if (!S_ISBLK(buf.st_mode)) {
+ free(cp);
+ return (strdup(""));
+ }
+
+ blk_dev = buf.st_rdev;
+
+ if ((dp = getvfsspecial(cp, GET_RAW)) != NULL) {
+ free(cp);
+ return (strdup(dp));
+ }
+
+ /*
+ * We have a block device name, go find the raw name.
+ */
+ if ((dp = strstr(cp, "/dsk/")) == NULL &&
+ (dp = strstr(cp, "/" LOFI_BLOCK_NAME "/")) == NULL &&
+ (dp = strstr(cp, "/" RD_BLOCK_NAME "/")) == NULL &&
+ (dp = strstr(cp, "/" SNAP_BLOCK_NAME "/")) == NULL &&
+ (dp = strrchr(cp, '/')) == NULL) {
+ /* this is not really possible */
+ free(cp);
+ return (strdup(""));
+ }
+ dp++;
+
+ if ((new_path = malloc(strlen(cp)+2)) == NULL) {
+ free(cp);
+ return (NULL);
+ }
+ (void) strncpy(new_path, cp, dp - cp);
+ /* fill in the rest of the raw name */
+ new_path[dp - cp] = 'r';
+ (void) strcpy(new_path + (dp - cp) + 1, dp);
+
+ if (test_if_raw(new_path, blk_dev)) {
+ free(cp);
+ return (new_path);
+ }
+ free(new_path);
+
+ dp = getrawcomplete(cp, &buf);
+ free(cp);
+ return (dp);
+}
diff --git a/usr/src/lib/libadm/common/getdev.c b/usr/src/lib/libadm/common/getdev.c
new file mode 100644
index 0000000000..8e4401140f
--- /dev/null
+++ b/usr/src/lib/libadm/common/getdev.c
@@ -0,0 +1,1095 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright (c) 1997, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.4 */
+/*LINTLIBRARY*/
+
+/*
+ * getdev.c
+ *
+ * Contents:
+ * getdev() List devices that match certain criteria.
+ */
+
+/*
+ * Header files referenced:
+ * <sys/types.h> System Data Types
+ * <errno.h> Error handling
+ * <fcntl.h> File controlling
+ * <ctype.h> Character types
+ * <string.h> String handling
+ * <devmgmt.h> Global device-management def'ns
+ * "devtab.h" Local device-management dev'ns
+ */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <string.h>
+#include <devmgmt.h>
+#include "devtab.h"
+#include <stdlib.h>
+
+/*
+ * Local definitions
+ * NULL Nil address
+ * TRUE Boolean TRUE
+ * FALSE Boolean FALSE
+ */
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef TRUE
+#define TRUE ('t')
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+
+/*
+ * Comparison values. These values are placed in the struct srch
+ * structure by buildsearchlist() and are used to compare values
+ * in matches().
+ * EQUAL Attribute must equal this value
+ * NOTEQUAL Attribute must not equal this value
+ * EXISTS Attribute must exist
+ * NOEXISTS Attribute must not exist
+ * IGNORE Ignore this entry
+ * ENDLIST This entry ends the list
+ */
+
+#define EQUAL 1
+#define NOTEQUAL 2
+#define EXISTS 3
+#define NOEXISTS 4
+#define IGNORE 5
+#define ENDLIST 0
+
+
+/*
+ * Structure definitions:
+ * deviceent Defines a device that matches criteria
+ * srch Describes a criteria
+ */
+
+struct deviceent {
+ struct deviceent *next; /* Pointer to next item in the list */
+ char *name; /* Presentation name of the device */
+};
+
+struct srch {
+ char *name; /* Name of field to compare */
+ char *cmp; /* Value to compare against */
+ int fcn; /* Type of comparison (see above) */
+};
+
+
+/*
+ * Local functions referenced
+ * oktoaddtolist() Determines if device can be added to the
+ * list by examining the devices list and
+ * the options governing the search
+ * initdevicelist() Initializes the linked list of devices
+ * to be included in the list-to-return
+ * freedevicelist() Frees the resources allocated to the linked
+ * list of devices
+ * addtodevicelist() Adds an entry to the linked list of devices
+ * buildsearchlist() Builds a list of struct srch structures from
+ * the criteria strings
+ * freesearchlist() Frees the resources allocated to the list of
+ * struct srch structures
+ * buildreturnlist() Builds the list of devices to return from the
+ * linked list of devices we've accumulated
+ * makealiaslist() Builds a list of aliases from the list of
+ * devices presented by the caller
+ * freealiaslist() Frees the resources allocated to the list of
+ * devices aliases
+ * getnextmatch() Get the next device that matches the search
+ * criteria
+ * matchallcriteria() See if the device attributes match all of the
+ * search criteria
+ * matchanycriteria() See if the device attributes match any of the
+ * search criteria
+ * matches() See if the criteria and attribute match
+ */
+
+static char *oktoaddtolist(char *, char **, char **, int);
+static void initdevicelist(void);
+static void freedevicelist(void);
+static int addtodevicelist(char *);
+static struct srch *buildsearchlist(char **);
+static void freesearchlist(struct srch *);
+static char **buildreturnlist(void);
+static char **makealiaslist(char **);
+static void freealiaslist(char **);
+static char *getnextmatch(struct srch *, int);
+static int matchallcriteria(struct devtabent *, struct srch *);
+static int matchanycriteria(struct devtabent *, struct srch *);
+static int matches(char *, char *, int);
+
+
+/*
+ * Global Data
+ */
+
+/*
+ * Static Data
+ * devicelisthead The first item (dummy) in the linked list of devices
+ * we're building
+ * devicelist Structure describing the linked list of devices
+ */
+
+static struct deviceent devicelisthead;
+static struct {
+ struct deviceent *head;
+ int count;
+} devicelist = {&devicelisthead, 0};
+
+/*
+ * char **getdev(devices, criteria, options)
+ * char **devices
+ * char **criteria
+ * int options
+ *
+ * This function builds a list of devices that match criteria,
+ * governed by the device list.
+ *
+ * Arguments:
+ * devices The list of devices to select from or the list of
+ * devices to exclude, depending on the value of
+ * "options"
+ * criteria The list of criteria governing the device selection
+ * Of the form <attr><op><val>
+ * options Options controlling the device selection. May require
+ * that a device meet all of the criteria (default is
+ * any one of the criteria), or may require that the
+ * devices in the list of devices be excluded from the
+ * generated list (default is to select only those
+ * devices in the list)
+ *
+ * Returns: char **
+ * The address of the first item in the list of devices that meet
+ * the selection criteria
+ */
+
+char **
+getdev(
+ char **devices, /* List of devices to constrain */
+ char **criteria, /* List of selection criteria */
+ int options) /* Options governing the search */
+{
+ /* Automatic data */
+ char **aliases; /* List of constraining devices */
+ char **returnlist; /* List of ptrs to aliases to return */
+ struct srch *searchlist; /* Pointer to searching criteria */
+ char *entry; /* Pointer to alias in record */
+ int errflag; /* FLAG: TRUE if error */
+
+
+ /*
+ * Initializations
+ */
+
+ /* Make sure the exclude/include list is all aliases */
+ aliases = makealiaslist(devices);
+ if (devices && !aliases)
+ return (NULL);
+
+ /* Build the search list */
+ if (criteria) {
+ if (!(searchlist = buildsearchlist(criteria)))
+ return (NULL);
+ } else searchlist = NULL;
+
+ /* Initialize searching */
+ initdevicelist();
+ _setdevtab();
+
+
+ /*
+ * Keep on going until we get no more matches
+ */
+
+ errflag = FALSE;
+ while (!errflag && (entry = getnextmatch(searchlist, options))) {
+ if (entry = oktoaddtolist(entry, devices, aliases, options)) {
+ errflag = addtodevicelist(entry);
+ }
+ }
+
+
+ /*
+ * Clean up:
+ * - Free the entry space we've allocated.
+ * - Close the device table.
+ * - Build the list to return to the caller.
+ * - Free the accumulate device space (but not the strings!)
+ * - Free the alias list
+ * - Return the built list to the caller.
+ */
+
+ returnlist = buildreturnlist();
+ freedevicelist();
+ freealiaslist(aliases);
+ _enddevtab();
+ return (returnlist);
+}
+
+/*
+ * char *oktoaddtolist(devtabentry, devices, aliases, options)
+ * char *devtabentry
+ * char **devices
+ * char **aliases
+ * int options
+ *
+ * This function determines the device "devtabentry" can be
+ * added to the list of devices we're accumulating. If so,
+ * it returns the device name (not the alias).
+ *
+ * Arguments:
+ * devtabentry The device alias that may or may not belong in the
+ * list we're building.
+ * devices The devices specified by the caller
+ * aliases The aliases of the devices specified by the caller
+ * (1-1 correspondence with "devices")
+ * options Options controlling the search
+ */
+
+static char *
+oktoaddtolist(
+ char *devtabentry, /* Alias to check against list */
+ char **devices, /* List of devices to check against */
+ char **aliases, /* List of alias of those devices */
+ int options) /* Options governing search */
+{
+ /* Automatic data */
+ char *rtnval; /* Value to return */
+ int found; /* Flag: TRUE if found */
+
+ /* If there's a constraint list, is this device in it? */
+ if (devices && aliases) {
+
+ /* Set "found" to TRUE if the device is in the list */
+ found = FALSE;
+ while (!found && *aliases) {
+ if (strcmp(devtabentry, *aliases) == 0) found = TRUE;
+ else {
+ devices++;
+ aliases++;
+ }
+ }
+
+ /* Set value to return */
+ if (found)
+ rtnval = (options & DTAB_EXCLUDEFLAG) ?
+ NULL : *devices;
+ else
+ rtnval = (options & DTAB_EXCLUDEFLAG) ?
+ devtabentry : NULL;
+
+ } else rtnval = devtabentry; /* No constraint list */
+
+ return (rtnval);
+}
+
+/*
+ * void initdevicelist()
+ *
+ * This function initializes the list of accumulated devices.
+ *
+ * Arguments: None
+ *
+ * Returns: Void.
+ *
+ * Notes:
+ */
+
+static void
+initdevicelist(void)
+{
+ /* Make the list a null list */
+ (devicelist.head)->next = NULL;
+ devicelist.count = 0;
+}
+
+/*
+ * void freedevicelist()
+ *
+ * This function frees the resources allocated to the linked list of
+ * devices we've been accumulating.
+ *
+ * Arguments: none
+ *
+ * Returns: void
+ */
+
+static void
+freedevicelist(void)
+{
+ /* Automatic data */
+ struct deviceent *pdevice; /* Pointer to current entry */
+ char *freeblk; /* Pointer space to free */
+
+ /* List has a dummy head node */
+ pdevice = (devicelist.head)->next;
+ while (pdevice) {
+ freeblk = (char *) pdevice;
+ pdevice = pdevice->next;
+ free(freeblk);
+ }
+}
+
+/*
+ * int addtodevicelist(deventry)
+ * char *deventry
+ *
+ * This function adds the device <deventry> to the list of devices already
+ * accumulated. It will not add the device if that device already exists
+ * in the list. The function returns 0 if successful, -1 if not with
+ * "errno" set (by functions called) to indicate the error.
+ *
+ * Arguments:
+ * deventry char *
+ * The name of the device to add to the list of
+ * accumulated devices
+ *
+ * Returns:
+ * 0 If successful
+ * -1 If failed. "errno" will be set to a value that indicates the
+ * error.
+ *
+ * Notes:
+ * - The memory allocation scheme has the potential to fragment the memory
+ * in the malloc heap. We're allocating space for a local structure,
+ * which will be freed by getdev(), then allocating space for the device
+ * name, which will be freed (maybe) by the application using getdev().
+ * Not worrying about this at the moment.
+ */
+
+static int
+addtodevicelist(char *deventry)
+{
+ /* Automatic data */
+ struct deviceent *p; /* Pointer to current device */
+ struct deviceent *q; /* Pointer to next device */
+ struct deviceent *new; /* Pointer to the alloc'd new node */
+ char *str; /* Pointer to alloc'd space for name */
+ int rtncd; /* Value to return to the caller */
+ int cmpcd; /* strcmp() value, comparing names */
+ int done; /* Loop control, TRUE if done */
+
+
+ /* Initializations */
+ rtncd = FALSE;
+
+
+ /*
+ * Find the place in the found device list devicelist where this
+ * device is to reside
+ */
+
+ p = devicelist.head;
+ done = FALSE;
+ while (!done) {
+ q = p->next;
+ if (!q) done = TRUE;
+ else if ((cmpcd = strcmp(deventry, q->name)) <= 0) done = TRUE;
+ else p = q;
+ }
+
+ /*
+ * If the device is not already in the list, insert it in the list
+ */
+
+ if (!q || (cmpcd != 0)) {
+
+ /* Alloc space for the new node */
+ if (new = malloc(sizeof (struct deviceent))) {
+
+ /* Alloc space for the device character string */
+ if (str = malloc(strlen(deventry)+1)) {
+
+ /*
+ * Insert an entry in the found device list containing
+ * this device name
+ */
+ new->next = q;
+ p->next = new;
+ new->name = strcpy(str, deventry);
+ devicelist.count++;
+ }
+
+ /* Couldn't alloc space for the device name. Error. */
+ else rtncd = TRUE;
+ }
+
+ /* Couldn't alloc space for new node in the found list. Error. */
+ else rtncd = TRUE;
+
+ }
+
+ /* Return an value indicating success or failure */
+ return (rtncd);
+}
+
+/*
+ * struct srch *buildsearchlist(criteria)
+ * char **criteria
+ *
+ * This function builds a list of search criteria structures from the
+ * criteria strings in the list of criteria whose first argument is
+ * specified by "criteria".
+ *
+ * Arguments:
+ * criteria The address of the first item in a list of
+ * character-strings specifying search criteria
+ *
+ * Returns: struct srch *
+ * The address of the structure in the list of structures describing the
+ * search criteria.
+ *
+ * Notes:
+ * - The only "regular expression" currently supported by the
+ * kywd:exp and kywd!:exp forms is exp=*. This function assumes
+ * that kywd:exp means "if kywd exist" and that kywd!:exp means
+ * "if kywd doesn't exist".
+ */
+
+static struct srch *
+buildsearchlist(char **criteria) /* Criteria from caller */
+{
+ /* Automatic data */
+ struct srch *rtnbuf; /* Value to return */
+ struct srch *psrch; /* Running pointer */
+ char *str; /* Ptr to malloc()ed string space */
+ char *p; /* Temp pointer to char */
+ int noerror; /* TRUE if all's well */
+ int n; /* Temp counter */
+ char **pp; /* Running ptr to (char *) */
+
+
+ /* Initializations */
+ rtnbuf = NULL; /* Nothing to return yet */
+ noerror = TRUE; /* No errors (yet) */
+
+ /* If we were given any criteria ... */
+ if (criteria) {
+
+ /* Count the number of criteria in the list */
+ for (n = 1, pp = criteria; *pp++; n++)
+ ;
+
+ /* Allocate space for structures describing the criteria */
+ if (rtnbuf = malloc(n*sizeof (struct srch))) {
+
+ /* Build structures describing the criteria */
+ pp = criteria;
+ psrch = rtnbuf;
+ while (noerror && *pp) {
+
+ /* Keep list sane for cleanup if necessary */
+ psrch->fcn = ENDLIST;
+
+ /* Alloc space for strings referenced by the structure */
+ if (str = malloc(strlen(*pp)+1)) {
+
+ /* Extract field name, function, and compare string */
+ (void) strcpy(str, *pp);
+
+ /* If criteria contains an equal sign ('=') ... */
+ if (p = strchr(str+1, '=')) {
+ if (*(p-1) == '!') {
+ *(p-1) = '\0';
+ psrch->fcn = NOTEQUAL;
+ } else {
+ *p = '\0';
+ psrch->fcn = EQUAL;
+ }
+ psrch->cmp = p+1;
+ psrch->name = str;
+ psrch++;
+ }
+
+ /* If criteria contains a colon (':') ... */
+ else if (p = strchr(str+1, ':')) {
+ if (*(p-1) == '!') {
+ *(p-1) = '\0';
+ psrch->fcn = NOEXISTS;
+ } else {
+ *p = '\0';
+ psrch->fcn = EXISTS;
+ }
+ psrch->cmp = p+1;
+ psrch->name = str;
+ psrch++;
+ }
+ } else {
+ /* Unable to malloc() string space. Clean up */
+ freesearchlist(rtnbuf);
+ noerror = FALSE;
+ }
+ /* Next criteria */
+ pp++;
+ }
+ /* Terminate list */
+ if (noerror) psrch->fcn = ENDLIST;
+ }
+ }
+
+ /* Return a pointer to allocated space (if any) */
+ return (rtnbuf);
+}
+
+/*
+ * void freesearchlist(list)
+ * struct srch *list
+ *
+ * This function frees the resources allocated to the searchlist <list>.
+ *
+ * Arguments:
+ * list The list whose resources are to be released.
+ *
+ * Returns: void
+ */
+
+static void
+freesearchlist(struct srch *list)
+{
+ /* Automatic data */
+ struct srch *psrch; /* Running ptr to structs */
+
+
+ /* Free all of the string space allocated for the structure elememts */
+ for (psrch = list; psrch->fcn != ENDLIST; psrch++) {
+ free(psrch->name);
+ }
+
+ /* Free the list space */
+ free(list);
+}
+
+/*
+ * char **buildreturnlist()
+ *
+ * This function builds a list of addresses of character-strings
+ * to be returned from the linked-list of devices we've been
+ * building. It returns a pointer to the first item in that list.
+ *
+ * Arguments: none
+ *
+ * Returns: char **
+ * The address of the first item in the return list
+ */
+
+static char **
+buildreturnlist(void)
+{
+ /* Automatic data */
+ char **list;
+ char **q;
+ struct deviceent *p;
+
+
+ /*
+ * Allocate space for the return list,
+ * with space for the terminating node
+ */
+
+ if (list = malloc((devicelist.count+1)*sizeof (char *))) {
+
+ /*
+ * Walk the list of accumulated devices, putting pointers to
+ * device names in the list to return
+ */
+
+ q = list;
+ for (p = devicelist.head->next; p; p = p->next) *q++ = p->name;
+
+ /* End the list with a null-pointer */
+ *q = NULL;
+ }
+
+
+ /* Return a pointer to the list we've built */
+ return (list);
+}
+
+/*
+ * char **makealiaslist(devices)
+ * char **devices List of aliases
+ *
+ * Builds a list of aliases of the devices in the "devices"
+ * list. This list will be terminated by (char *) NULL and
+ * will have the same number of elements as "devices". If
+ * a device couldn't be found, that alias will be "". There
+ * will be a one-to-one correspondence of devices to aliases
+ * in the device list "devices" and the generated list.
+ *
+ * Arguments:
+ * devices The list of devices to derive aliases from
+ *
+ * Returns: char **
+ * The address of the list of addresses of aliases. The list
+ * and aliases will be allocated using the malloc() function.
+ */
+
+static char **
+makealiaslist(char **devices)
+{
+ /* Automatic data */
+ char **pp; /* Running ptr to (char *) */
+ char **qq; /* Running ptr to (char *) */
+ char **aliases; /* List being returned */
+ char *alias; /* Alias of current device */
+ int olderrno; /* Value of errno on entry */
+ int noerror; /* Flag, TRUE if all's well */
+ int n; /* Count of entries in "devices" */
+
+
+ noerror = TRUE;
+ olderrno = errno;
+ if (devices) {
+
+ /* Get the number of entries in the constaint list */
+ for (n = 1, pp = devices; *pp; pp++) n++;
+
+ /* Get space for the alias list */
+ if (aliases = malloc(n*sizeof (char *))) {
+
+ /* Build the alias list */
+ qq = aliases;
+ for (pp = devices; noerror && *pp; pp++) {
+
+ /* Get the device's alias and put it in the list */
+ if (alias = devattr(*pp, DTAB_ALIAS)) *qq++ = alias;
+ else {
+ errno = olderrno;
+ if (alias = malloc(strlen("")+1))
+ *qq++ = strcpy(alias, "");
+ else {
+ /* No space for a null string? Yeech... */
+ for (qq = aliases; *qq; qq++) free(*qq);
+ free(aliases);
+ aliases = NULL;
+ noerror = FALSE;
+ }
+ }
+ }
+ if (noerror)
+ *qq = NULL;
+
+ }
+
+ } else
+ aliases = NULL; /* No constraint list */
+
+ /* Return ptr to generated list or NULL if none or error */
+ return (aliases);
+}
+
+/*
+ * void freealiaslist(aliaslist)
+ * char **aliaslist;
+ *
+ * Free the space allocated to the aliaslist. It frees the space
+ * allocated to the character-strings referenced by the list then
+ * it frees the list.
+ *
+ * Arguments:
+ * aliaslist The address of the first item in the list of
+ * aliases that is to be freed
+ *
+ * Returns: void
+ */
+
+static void
+freealiaslist(char **aliaslist) /* Ptr to new device list */
+{
+ /* Automatic Data */
+ char **pp; /* Running pointer */
+
+ /* If there's a list ... */
+ if (aliaslist) {
+
+ /* For each entry in the old list, free the entry */
+ for (pp = aliaslist; *pp; pp++) free(*pp);
+
+ /* Free the list */
+ free(aliaslist);
+ }
+}
+
+/*
+ * char *getnextmatch(criteria, options)
+ * struct srch *criteria
+ * int options
+ *
+ * Gets the next device in the device table that matches the criteria.
+ * Returns the alias of that device.
+ *
+ * Arguments:
+ * criteria The linked list of criteria to use to match a device
+ * options Options modifying the criteria (only one that's really
+ * important is the DTAB_ANDCRITERIA flag)
+ *
+ * Returns: char *
+ * A pointer to a malloc()ed string containing the alias of the next
+ * device that matches the criteria, or (char *) NULL if none.
+ */
+
+static char *
+getnextmatch(struct srch *criteria, int options)
+{
+ /* Automatic data */
+ struct devtabent *devtabent; /* Ptr to current record */
+ char *alias; /* Alias of device found */
+ int notdone; /* Flag, done yet? */
+ int noerror; /* Flag, had an error yet? */
+
+
+ /*
+ * Initializations:
+ * - No alias yet
+ * - Not finished yet
+ * - Make sure there are criteria we're to use
+ */
+
+ alias = NULL;
+ notdone = TRUE;
+ noerror = TRUE;
+
+ /* If we're to "and" the criteria... */
+ if (options & DTAB_ANDCRITERIA) {
+
+ /*
+ * Search the device table until we've got a record that matches
+ * all of the criteria or we run out of records
+ */
+
+ while (notdone && (devtabent = _getdevtabent())) {
+ if (!devtabent->comment) {
+ if (!criteria || matchallcriteria(devtabent, criteria)) {
+ if (alias = malloc(strlen(devtabent->alias)+1))
+ (void) strcpy(alias, devtabent->alias);
+ else noerror = FALSE;
+ notdone = FALSE;
+ }
+ }
+ _freedevtabent(devtabent);
+ }
+ } else {
+
+ /*
+ * Search the device table until we've got a record that matches
+ * any of the criteria or we run out of records
+ */
+
+ while (notdone && (devtabent = _getdevtabent())) {
+ if (!devtabent->comment) {
+ if (!criteria || matchanycriteria(devtabent, criteria)) {
+ if (alias = malloc(strlen(devtabent->alias)+1))
+ (void) strcpy(alias, devtabent->alias);
+ else noerror = FALSE;
+ notdone = FALSE;
+ }
+ }
+ _freedevtabent(devtabent);
+ }
+ }
+
+
+ /* Return pointer to extracted alias (or NULL if none) */
+ if ((alias == NULL) && noerror) errno = ENOENT;
+ return (alias);
+}
+
+/*
+ * int matchallcriteria(devtabent, criteria)
+ *
+ * This function examines the record contained in "devtabent" and
+ * determines if that record meets all of the criteria specified by
+ * "criteria".
+ *
+ * Arguments:
+ * struct devtabent *devtabent The device table entry to examine.
+ * struct srch *criteria The criteria to match.
+ *
+ * Returns: int
+ * Returns TRUE if the record matches criteria, FALSE otherwise.
+ */
+
+static int
+matchallcriteria(
+ struct devtabent *ent, /* Entry to check */
+ struct srch *criteria) /* Criteria governing match */
+{
+ /* Automatic data */
+ struct srch *p; /* Pointer to current criteria */
+ struct attrval *q; /* Pointer to current attr/val pair */
+ int notfound; /* TRUE if attr found in list */
+ int failed; /* TRUE if record failed to match */
+
+
+ /* Test only if there's criteria to test against */
+ if (criteria && (criteria->fcn != ENDLIST)) {
+
+ failed = FALSE;
+ for (p = criteria; !failed && (p->fcn != ENDLIST); p++) {
+
+ /*
+ * Don't compare against this criteria if it's function is
+ * "IGNORE"
+ */
+ if (p->fcn != IGNORE) {
+ if (p->fcn != NOEXISTS) {
+
+ /* Alias? */
+ if (strcmp(p->name, DTAB_ALIAS) == 0)
+ failed = !matches(ent->alias, p->cmp, p->fcn);
+
+ /* Char special device? */
+ else if (strcmp(p->name, DTAB_CDEVICE) == 0)
+ failed = !matches(ent->cdevice, p->cmp, p->fcn);
+
+ /* Block special device? */
+ else if (strcmp(p->name, DTAB_BDEVICE) == 0)
+ failed = !matches(ent->bdevice, p->cmp, p->fcn);
+
+ /* Pathname? */
+ else if (strcmp(p->name, DTAB_PATHNAME) == 0)
+ failed = !matches(ent->pathname, p->cmp, p->fcn);
+
+ /* Check other attributes... */
+ else {
+ notfound = TRUE;
+ q = ent->attrlist;
+ while (notfound && q) {
+ if (strcmp(p->name, q->attr) == 0) {
+ notfound = FALSE;
+ if (!matches(q->val, p->cmp, p->fcn))
+ failed = TRUE;
+ } else q = q->next;
+ }
+ if (notfound) failed = TRUE;
+ }
+ } else {
+ if (strcmp(p->name, DTAB_ALIAS) == 0) failed = TRUE;
+ else if (strcmp(p->name, DTAB_CDEVICE) == 0)
+ failed = FALSE;
+ else if (strcmp(p->name, DTAB_BDEVICE) == 0)
+ failed = FALSE;
+ else if (strcmp(p->name, DTAB_PATHNAME) == 0)
+ failed = FALSE;
+ else {
+ q = ent->attrlist;
+ while (!failed && q) {
+ if (strcmp(p->name, q->attr) == 0)
+ failed = TRUE;
+ else q = q->next;
+ }
+ }
+ }
+
+ } /* Search function is not "IGNORE" */
+
+ } /* for loop, checking each criteria */
+
+ } /* if (criteria) */
+
+ else failed = FALSE; /* No criteria specified, it's a match */
+
+
+ /* Return a value indicating if the record matches all criteria */
+ return (!failed);
+}
+
+/*
+ * int matchanycriteria(devtabent, criteria)
+ *
+ * This function examines the record contained in "devtabent" and
+ * determines if that record meets any of the criteria specified by
+ * "criteria".
+ *
+ * Arguments:
+ * struct devtabent *devtabent The device table entry to examine.
+ * struct srch *criteria The criteria to match.
+ *
+ * Returns: int
+ * Returns TRUE if the record matches criteria, FALSE otherwise.
+ */
+
+static int
+matchanycriteria(
+ struct devtabent *ent, /* Entry to check */
+ struct srch *criteria) /* Criteria governing match */
+{
+ /* Automatic data */
+ struct srch *p; /* Pointer to current criteria */
+ struct attrval *q; /* Pointer to current attr/val pair */
+ int matched; /* FLAG: TRUE if record matched */
+ int found; /* FLAG: TRUE if attribute found */
+
+
+ /* Test only if there's criteria to test against */
+ if (criteria && (criteria->fcn != ENDLIST)) {
+
+ matched = FALSE;
+ for (p = criteria; !matched && (p->fcn != ENDLIST); p++) {
+
+ /*
+ * Don't compare against this criteria if it's function is
+ * "IGNORE"
+ */
+ if (p->fcn != IGNORE) {
+ if (p->fcn != NOEXISTS) {
+
+ /* Alias? */
+ if (strcmp(p->name, DTAB_ALIAS) == 0)
+ matched = matches(ent->alias, p->cmp, p->fcn);
+
+ /* Char special device? */
+ else if (strcmp(p->name, DTAB_CDEVICE) == 0)
+ matched = matches(ent->cdevice, p->cmp, p->fcn);
+
+ /* Block special device? */
+ else if (strcmp(p->name, DTAB_BDEVICE) == 0)
+ matched = matches(ent->bdevice, p->cmp, p->fcn);
+
+ /* Pathname? */
+ else if (strcmp(p->name, DTAB_PATHNAME) == 0)
+ matched = matches(ent->pathname, p->cmp, p->fcn);
+
+ /* Check other attributes... */
+ else {
+ q = ent->attrlist;
+ found = FALSE;
+ while (!found && q)
+ if (strcmp(p->name, q->attr) == 0) {
+ matched = matches(q->val, p->cmp, p->fcn);
+ found = TRUE;
+ } else q = q->next;
+ }
+ } else {
+ if (strcmp(p->name, DTAB_ALIAS) == 0) matched = FALSE;
+ else if (strcmp(p->name, DTAB_CDEVICE) == 0)
+ matched = FALSE;
+ else if (strcmp(p->name, DTAB_BDEVICE) == 0)
+ matched = FALSE;
+ else if (strcmp(p->name, DTAB_PATHNAME) == 0)
+ matched = FALSE;
+ else {
+ q = ent->attrlist;
+ matched = TRUE;
+ while (matched && q) {
+ if (strcmp(p->name, q->attr) == 0)
+ matched = FALSE;
+ else q = q->next;
+ }
+ }
+ }
+ } /* Search function is not "IGNORE" */
+
+ } /* for loop, checking each criteria */
+
+ } /* if (criteria) */
+
+ else matched = TRUE; /* No criteria specified, it's a match */
+
+
+ /* Return a value indicating if the record matches all criteria */
+ return (matched);
+}
+
+/*
+ * int matches(value, compare, function)
+ * char *value
+ * char *compare
+ * int function
+ *
+ * This function sees if the operation <function> is satisfied by
+ * comparing the value <value> with <compare>. It returns TRUE
+ * if so, FALSE otherwise.
+ *
+ * Arguments:
+ * value Value to compare
+ * compare Value to compare against
+ * function Function to be satisfied
+ *
+ * Returns: int
+ * TRUE if the function is satisfied, FALSE otherwise
+ */
+
+static int
+matches(char *value, char *compare, int function)
+{
+ /* Automatic data */
+ int rtn; /* Value to return */
+
+
+ if (value == NULL)
+ value = "";
+
+ /* Do case depending on the function */
+ switch (function) {
+
+ /* attr=val */
+ case EQUAL:
+ rtn = (strcmp(value, compare) == 0);
+ break;
+
+ /* attr!=val */
+ case NOTEQUAL:
+ rtn = (strcmp(value, compare) != 0);
+ break;
+
+ /* attr:* */
+ case EXISTS:
+ rtn = TRUE;
+ break;
+
+ /* attr!:* */
+ case NOEXISTS:
+ rtn = FALSE;
+ break;
+
+ /* Shouldn't get here... */
+ default:
+ rtn = FALSE;
+ break;
+ }
+
+ /* Return a value indicating if the match was made */
+ return (rtn);
+}
diff --git a/usr/src/lib/libadm/common/getdgrp.c b/usr/src/lib/libadm/common/getdgrp.c
new file mode 100644
index 0000000000..3b5eb89da0
--- /dev/null
+++ b/usr/src/lib/libadm/common/getdgrp.c
@@ -0,0 +1,494 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright (c) 1997, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*LINTLIBRARY*/
+
+/*
+ * getdgrp.c
+ *
+ * Contains the following global functions:
+ * getdgrp() Get the device groups that meet certain criteria.
+ */
+
+/*
+ * Header Files Referenced
+ * <sys/types.h> Data Types
+ * <stdio.h> Standard I/O definitions
+ * <string.h> Character-string definitions
+ * <devmgmt.h> Definitions for accessing device table files
+ * "devtab.h" Local definitions for device tables
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <devmgmt.h>
+#include "devtab.h"
+
+/*
+ * Local definitions
+ * struct dgrplist Structure that makes up the internal device
+ * group list
+ * Members:
+ * name Name of the device group
+ * next Pointer to the next in the list
+ */
+
+struct dgrplist {
+ char *name;
+ struct dgrplist *next;
+};
+
+
+/*
+ * Local functions
+ * initdgrplist Initialize the internal device group list
+ * addtodgrplist Add a device group to the device group list
+ * isindevlist Does the device group contain a device?
+ * isincallerslist Is a device group in the caller's list?
+ * buildreturnlist Build list of device groups to return
+ * freedgrplist Free the internal device group list
+ */
+
+static void initdgrplist(void);
+static int addtodgrplist(struct dgrptabent *);
+static int isindevlist(struct dgrptabent *, char **);
+static int isincallerslist(struct dgrptabent *, char **);
+static char **buildreturnlist(void);
+static void freedgrplist(void);
+
+
+/*
+ * Local data
+ * dgrplistfirst First (dummy) node in the device group list
+ * dgrplistcount Number of items in the device group list
+ */
+
+static struct dgrplist dgrplistfirst;
+static int dgrplistcount;
+
+/*
+ * char **getdgrp(dgroups, criteria, options)
+ * char **dgroups
+ * char **criteria
+ * int options
+ *
+ * This function compiles a list of device groups containing devices
+ * that meet certain criteria and returns a pointer to the first
+ * item in that list.
+ *
+ * Arguments:
+ * dgroups The list of device groups to choose from or the list
+ * of device groups to exclude from the list (depends on
+ * "options"
+ * criteria The criteria that a device must meet
+ * options Indicates 1) whether to "and" the criteria or to "or"
+ * the criteria, 2) indicates whether to limit the
+ * generated list to "dgroups" or to exclude those
+ * device-groups from the list, 3) to list all device
+ * groups even if they don't contain valid devices.
+ *
+ * Returns: char **
+ * A pointer to the first address in the list of addresses of generated
+ * device groups
+ */
+
+char **
+getdgrp(
+ char **dgroups, /* List of device groups */
+ char **criteria, /* List of criteria to meet */
+ int options) /* Options governing the search */
+{
+ /* Automatic data */
+ char **devlist; /* Devices that meet criteria */
+ char **plist; /* Device groups to return */
+ struct dgrptabent *dgrp; /* Dgrp information struct */
+ int errorflag; /* TRUE if error occurred */
+ int listallflag; /* TRUE if DTAB_LISTALL && (!criteria || !*criteria) */
+
+
+ /*
+ * Open the device-group table if needed
+ */
+
+ if (!oam_dgroup && !_opendgrptab("r"))
+ return (NULL);
+
+
+ /*
+ * Get the list of devices that meet the criteria specified
+ * This step can be skipped if DTAB_LISTALL is requested and
+ * there is no criteria list.
+ */
+
+ if (((options & DTAB_LISTALL) == 0) || (criteria && *criteria)) {
+ devlist = getdev(NULL, criteria, (options & DTAB_ANDCRITERIA));
+ listallflag = FALSE;
+ } else {
+ devlist = NULL;
+ listallflag = TRUE;
+ }
+
+
+ /*
+ * Initialize the device group list (contains the device groups
+ * we're accumulating)
+ */
+
+ errorflag = FALSE;
+ initdgrplist();
+
+
+ /*
+ * If no device groups were specified by the caller, accumulate all
+ * device groups
+ */
+
+ _setdgrptab();
+ if (!dgroups || !(*dgroups)) {
+ while (!errorflag && (dgrp = _getdgrptabent())) {
+ if (!dgrp->comment && (listallflag ||
+ isindevlist(dgrp, devlist)))
+ errorflag = !addtodgrplist(dgrp);
+ _freedgrptabent(dgrp);
+ }
+ }
+
+ else {
+
+ /*
+ * If the exclusion flag is not set, build a list of device
+ * groups that is a subset of those specified by the caller
+ */
+
+ if ((options & DTAB_EXCLUDEFLAG) == 0) {
+ while (!errorflag && (dgrp = _getdgrptabent())) {
+ if (!dgrp->comment && isincallerslist(dgrp, dgroups) &&
+ (listallflag || isindevlist(dgrp, devlist))) {
+ errorflag = !addtodgrplist(dgrp);
+ }
+ _freedgrptabent(dgrp);
+ }
+ }
+
+ /*
+ * If the exclusion flag is set, build a list of device groups
+ * that meet the criteria and are not in the list of device
+ * groups specified by the caller.
+ */
+ else {
+ while (!errorflag && (dgrp = _getdgrptabent())) {
+ if (!dgrp->comment && !isincallerslist(dgrp, dgroups) &&
+ (listallflag || isindevlist(dgrp, devlist))) {
+ errorflag = !addtodgrplist(dgrp);
+ }
+ _freedgrptabent(dgrp);
+ }
+ }
+ }
+ plist = buildreturnlist();
+ freedgrplist();
+ _enddgrptab();
+ return (plist);
+}
+
+/*
+ * int initdgrplist()
+ *
+ * Initializes the internal device group linked list
+ *
+ * Arguments: None
+ *
+ * Returns: void
+ */
+
+static void
+initdgrplist(void)
+{
+ /* Automatic data */
+
+ /*
+ * Initialize the structure. Dummy node points to nothing, count to
+ * zero.
+ */
+ dgrplistcount = 0;
+ dgrplistfirst.name = "";
+ dgrplistfirst.next = NULL;
+}
+
+/*
+ * int addtodgrplist(dgrp)
+ * struct dgrptabent *dgrp
+ *
+ * Adds the device group described by the "dgrp" structure to the
+ * internal list of device-groups we're accumulating.
+ *
+ * Arguments:
+ * dgrp Describes the device-group we're adding
+ *
+ * Returns: int
+ * TRUE if successful, FALSE otherwise
+ */
+
+static int
+addtodgrplist(struct dgrptabent *dgrp)
+{
+ /* Automatic data */
+ struct dgrplist *newnode; /* Allocated node */
+ struct dgrplist *p; /* Running dgrp list ptr */
+ struct dgrplist *q; /* Another Running dgrp list ptr */
+ char *newstr; /* Space for the dgroup name */
+ int errorflag; /* TRUE if error */
+ int cmpval; /* Value from strcmp() */
+
+ /* No errors seen yet */
+ errorflag = FALSE;
+
+ /* Find where we're supposed to insert this item in the list */
+ q = &dgrplistfirst;
+ p = q->next;
+ while (p && ((cmpval = strcmp(p->name, dgrp->name)) < 0)) {
+ q = p;
+ p = p->next;
+ }
+
+ /* If the item isn't already in the list, insert it */
+ if ((p == NULL) || (cmpval != 0)) {
+
+ /* Allocate space for the structure */
+ newnode = malloc(sizeof (struct dgrplist));
+ if (newnode) {
+
+ /* Allocate space for the device group name */
+ if (newstr = malloc(strlen(dgrp->name)+1)) {
+
+ /* Link the new structure into the list */
+ newnode->name = strcpy(newstr, dgrp->name);
+ newnode->next = p;
+ q->next = newnode;
+ dgrplistcount++;
+ } else {
+ /* No space for the string. Clean up */
+ errorflag = TRUE;
+ free(newnode);
+ }
+ } else errorflag = TRUE;
+ }
+
+ /* Return a value that indicates whether we've had an error */
+ return (!errorflag);
+}
+
+/*
+ * int isindevlist(dgrp, devlist)
+ * struct dgrptabent *dgrp
+ * char **devlist
+ *
+ * This function searches the device membership list of the device
+ * group <dgrp> for any of the devices listed in the list of devices
+ * <devlist>. It returns TRUE if at least one device in <devlist> is
+ * found in <dgrp>, otherwise it returns false.
+ *
+ * Arguments:
+ * dgrp The device group to examine
+ * devlist The list of devices to search for
+ *
+ * Returns: int
+ * TRUE if one of the devices in <devlist> is a member of the device
+ * group <dgrp>, FALSE otherwise
+ */
+
+static int
+isindevlist(
+ struct dgrptabent *dgrp, /* Dgrp to search for */
+ char **devlist) /* List of devices to search against */
+{
+ /* Automatic data */
+ struct member *pmbr; /* Next member of the dgrp list */
+ char **pdev; /* Next device in the dev list */
+ char *mbralias; /* The alias of a group member */
+ int cmpval; /* strcmp() result */
+ int notfound; /* TRUE if no mbr of dgrp is in dev list */
+ int allocflag; /* TRUE if the mbralias string is malloc()ed */
+
+
+ /*
+ * For each device in the device group, search the alphabetically
+ * sorted list of devices for that device.
+ */
+
+ notfound = TRUE;
+ for (pmbr = dgrp->membership; notfound && pmbr; pmbr = pmbr->next) {
+
+ /*
+ * Get the member's alias (we've got it if the member is not a
+ * pathname)
+ */
+ allocflag = (*pmbr->name == '/');
+ if (allocflag)
+ mbralias = devattr(pmbr->name, DTAB_ALIAS);
+ else mbralias = pmbr->name;
+
+ /* If we've got a member alias, search the device list for it */
+ if (mbralias)
+ for (pdev = devlist; notfound && *pdev; pdev++)
+
+ if ((cmpval = strcmp(mbralias, *pdev)) == 0) notfound = FALSE;
+ else if (cmpval < 0)
+ break; /* Optimization: alpha sorted list */
+
+ /*
+ * Free the space allocated to the member alias
+ * (if it was allocated above by devattr())
+ */
+ if (allocflag) free(mbralias);
+
+ }
+
+
+ /*
+ * Return a value indicating that we the device group contains
+ * a member that is in the list of devices
+ */
+
+ return (!notfound);
+}
+
+/*
+ * int isincallerslist(dgrp, dgroups)
+ * struct dgrptabent *dgrp
+ * char **dgroups
+ *
+ * This function looks through the "dgroups" list for the device
+ * group described by "dgrp"
+ *
+ * Arguments:
+ * dgrp Device group to search for
+ * dgroups The address of the first item in the list of device
+ * groups to search
+ *
+ * Returns: int
+ * TRUE if found, FALSE otherwise
+ */
+
+static int
+isincallerslist(
+ struct dgrptabent *dgrp, /* Dgrp to search for */
+ char **dgroups) /* Caller's list of dgroups */
+{
+ /* Automatic data */
+ char **pdgrp;
+ int notfound;
+
+ /*
+ * Search the list of device groups for the name of the device group
+ * in the structure described by <dgrp>.
+ */
+
+ /* Initializations */
+ notfound = TRUE;
+
+ /* Search the device group list for name of this device group */
+ for (pdgrp = dgroups; notfound && *pdgrp; pdgrp++) {
+ if (strcmp(dgrp->name, *pdgrp) == 0) notfound = FALSE;
+ }
+
+ /* Return TRUE if the device group is in the list, FALSE otherwise */
+ return (!notfound);
+}
+
+/*
+ * char **buildreturnlist()
+ *
+ * This function builds the list of pointers to device groups
+ * to return to the caller from the linked list of device-groups
+ * we've been accumulating.
+ *
+ * Arguments: none
+ *
+ * Returns: char **
+ * A pointer to the first element in the malloc()ed list of pointers
+ * to malloc()ed character strings containing device groups which have
+ * member devices which match the criteria
+ */
+
+static char **
+buildreturnlist(void)
+{
+ char **list; /* List being built */
+ char **pp; /* Temp ptr within list */
+ struct dgrplist *pdgrpent; /* Ptr into list of dgrps to return */
+
+ /* Allocate space for the list of pointers to device groups */
+ list = malloc((dgrplistcount+1)*sizeof (char *));
+
+ /*
+ * For each item in the device group list, put an entry in the
+ * list of names we're building
+ */
+ if ((pp = list) != NULL) {
+ for (pdgrpent = dgrplistfirst.next; pdgrpent;
+ pdgrpent = pdgrpent->next) {
+
+ *pp++ = pdgrpent->name;
+ }
+ /* The list ends with a null pointer */
+ *pp = NULL;
+ }
+
+ /* Return a pointer to the allocated list */
+ return (list);
+}
+
+/*
+ * void freedgrplist()
+ *
+ * This function frees the resources allocated to the internal
+ * linked list of device groups
+ *
+ * Arguments: none
+ *
+ * Returns: void
+ */
+
+static void
+freedgrplist(void)
+{
+ struct dgrplist *pdgrpent; /* Dgrp to free */
+ struct dgrplist *nextnode; /* Next one to free */
+
+ for (pdgrpent = dgrplistfirst.next; pdgrpent; pdgrpent = nextnode) {
+ nextnode = pdgrpent->next;
+ free(pdgrpent);
+ }
+}
diff --git a/usr/src/lib/libadm/common/getinput.c b/usr/src/lib/libadm/common/getinput.c
new file mode 100644
index 0000000000..57375918c1
--- /dev/null
+++ b/usr/src/lib/libadm/common/getinput.c
@@ -0,0 +1,65 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright (c) 1997,1998 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+/*LINTLIBRARY*/
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <limits.h>
+#include "libadm.h"
+
+int
+getinput(char *s)
+{
+ char input[MAX_INPUT];
+ char *copy, *pt;
+
+ if (!fgets(input, MAX_INPUT, stdin))
+ return (1);
+
+ copy = s;
+ pt = input;
+
+ while (isspace((unsigned char)*pt))
+ ++pt;
+
+ while (*pt)
+ *copy++ = *pt++;
+ *copy = '\0';
+
+ if (copy != s) {
+ copy--;
+ while (isspace((unsigned char)*copy))
+ *copy-- = '\0';
+ }
+ return (0);
+}
diff --git a/usr/src/lib/libadm/common/getvol.c b/usr/src/lib/libadm/common/getvol.c
new file mode 100644
index 0000000000..f4955073ed
--- /dev/null
+++ b/usr/src/lib/libadm/common/getvol.c
@@ -0,0 +1,476 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright (c) 1997, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+/*LINTLIBRARY*/
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <devmgmt.h>
+#include "libadm.h"
+#include <stdlib.h>
+
+#define LABELSIZ 6
+#define BELL "\007"
+
+#define FORMFS_MSG ",\\n\\ \\ or [f] to format %s and place a filesystem on it"
+#define FORMAT_MSG ",\\n\\ \\ or [f] to format the %s"
+#define MAKEFS_MSG ",\\n\\ \\ or [m] to place a filesystem on %s"
+#define EJECT_MSG ",\\n\\ \\ or [e] to eject the %s"
+#define UNLOAD_MSG ",\\n\\ \\ or [u] to unload/offline the %s"
+#define WLABEL_MSG ",\\n\\ \\ or [w] to write a new label on the %s"
+#define OLABEL_MSG ",\\n\\ \\ or [o] to use the current label anyway"
+#define QUIT_MSG ",\\n\\ \\ or [q] to quit"
+
+#define ERR_ACCESS "\n%s (%s) cannot be accessed.\n"
+#define ERR_FMT "\nAttempt to format %s failed.\n"
+#define ERR_MKFS "\nAttempt to place filesystem on %s failed.\n"
+#define ERR_REMOVE "\nExecution of \"removecmd\"[%s] failed.\n"
+
+static void elabel(void);
+static void doformat(char *, char *, char *);
+static void labelerr(char *, char *);
+static int ckilabel(char *, int);
+static int insert(char *, char *, int, char *);
+
+static char *cdevice; /* character device name */
+static char *pname; /* device presentation name */
+static char *volume; /* volume name */
+static char origfsname[LABELSIZ+1];
+static char origvolname[LABELSIZ+1];
+
+/*
+ * Return:
+ * 0 - okay, label matches
+ * 1 - device not accessable
+ * 2 - unknown device (devattr failed)
+ * 3 - user selected quit
+ * 4 - label does not match
+ */
+
+/*
+ * macros from labelit to behave correctly for tape
+ * is a kludge, should use devmgmt
+ */
+#ifdef RT
+#define IFTAPE(s) ((strncmp(s, "/dev/mt", 7) == 0) || \
+(strncmp(s, "mt", 2) == 0))
+#define TAPENAMES "'/dev/mt'"
+#else
+#define IFTAPE(s) ((strncmp(s, "/dev/rmt", 8) == 0) || \
+(strncmp(s, "rmt", 3) == 0) || (strncmp(s, "/dev/rtp", 8) == 0) || \
+(strncmp(s, "rtp", 3) == 0))
+#define TAPENAMES "'/dev/rmt' or '/dev/rtp'"
+#endif
+
+int
+getvol(char *device, char *label, int options, char *prompt)
+{
+ return (_getvol(device, label, options, prompt, NULL));
+}
+
+int
+_getvol(char *device, char *label, int options, char *prompt, char *norewind)
+{
+ FILE *tmp;
+ char *advice, *pt;
+ int n, override;
+
+ cdevice = devattr(device, "cdevice");
+ if ((cdevice == NULL) || !cdevice[0]) {
+ cdevice = devattr(device, "pathname");
+ if ((cdevice == NULL) || !cdevice)
+ return (2); /* bad device */
+ }
+
+ pname = devattr(device, "desc");
+ if (pname == NULL) {
+ pname = devattr(device, "alias");
+ if (!pname)
+ pname = device;
+ }
+
+ volume = devattr(device, "volume");
+
+ if (label) {
+ (void) strncpy(origfsname, label, LABELSIZ);
+ origfsname[LABELSIZ] = '\0';
+ if (pt = strchr(origfsname, ',')) {
+ *pt = '\0';
+ }
+ if (pt = strchr(label, ',')) {
+ (void) strncpy(origvolname, pt+1, LABELSIZ);
+ origvolname[LABELSIZ] = '\0';
+ } else
+ origvolname[0] = '\0';
+ }
+
+ override = 0;
+ for (;;) {
+ if (!(options & DM_BATCH) && volume) {
+ n = insert(device, label, options, prompt);
+ if (n < 0)
+ override++;
+ else if (n)
+ return (n); /* input function failed */
+ }
+
+ if ((tmp = fopen(norewind ? norewind : cdevice, "r")) == NULL) {
+ /* device was not accessible */
+ if (options & DM_BATCH)
+ return (1);
+ (void) fprintf(stderr, ERR_ACCESS, pname, cdevice);
+ if ((options & DM_BATCH) || (volume == NULL))
+ return (1);
+ /* display advice on how to ready device */
+ if (advice = devattr(device, "advice"))
+ (void) puttext(stderr, advice, 0, 0);
+ continue;
+ }
+ (void) fclose(tmp);
+
+ /* check label on device */
+ if (label) {
+ if (options & DM_ELABEL)
+ elabel();
+ else {
+ /* check internal label using /etc/labelit */
+ if (ckilabel(label, override)) {
+ if ((options & DM_BATCH) ||
+ volume == NULL)
+ return (4);
+ continue;
+ }
+ }
+ }
+ break;
+ }
+ return (0);
+}
+
+static int
+ckilabel(char *label, int flag)
+{
+ FILE *pp;
+ char *pt, *look, buffer[512];
+ char fsname[LABELSIZ+1], volname[LABELSIZ+1];
+ char *pvolname, *pfsname;
+ int n, c;
+
+ (void) strncpy(fsname, label, LABELSIZ);
+ fsname[LABELSIZ] = '\0';
+ if (pt = strchr(fsname, ',')) {
+ *pt = '\0';
+ }
+ if (pt = strchr(label, ',')) {
+ (void) strncpy(volname, pt+1, LABELSIZ);
+ volname[LABELSIZ] = '\0';
+ } else
+ volname[0] = '\0';
+
+ (void) sprintf(buffer, "/etc/labelit %s", cdevice);
+ pp = popen(buffer, "r");
+ pt = buffer;
+ while ((c = getc(pp)) != EOF)
+ *pt++ = (char)c;
+ *pt = '\0';
+ (void) pclose(pp);
+
+ pt = buffer;
+ pfsname = pvolname = NULL;
+ look = "Current fsname: ";
+ n = (int)strlen(look);
+ while (*pt) {
+ if (strncmp(pt, look, n) == 0) {
+ *pt = '\0';
+ pt += strlen(look);
+ if (pfsname == NULL) {
+ pfsname = pt;
+ look = ", Current volname: ";
+ n = (int)strlen(look);
+ } else if (pvolname == NULL) {
+ pvolname = pt;
+ look = ", Blocks: ";
+ n = (int)strlen(look);
+ } else
+ break;
+ } else
+ pt++;
+ }
+
+ if (strcmp(fsname, pfsname) || strcmp(volname, pvolname)) {
+ /* mismatched label */
+ if (flag) {
+ (void) sprintf(label, "%s,%s", pfsname, pvolname);
+ } else {
+ labelerr(pfsname, pvolname);
+ return (1);
+ }
+ }
+ return (0);
+}
+
+static int
+wilabel(char *label)
+{
+ char buffer[512];
+ char fsname[LABELSIZ+1];
+ char volname[LABELSIZ+1];
+ int n;
+
+ if (!label || !strlen(origfsname)) {
+ if (n = ckstr(fsname, NULL, LABELSIZ, NULL, NULL, NULL,
+ "Enter text for fsname label:"))
+ return (n);
+ } else
+ (void) strcpy(fsname, origfsname);
+ if (!label || !strlen(origvolname)) {
+ if (n = ckstr(volname, NULL, LABELSIZ, NULL, NULL, NULL,
+ "Enter text for volume label:"))
+ return (n);
+ } else
+ (void) strcpy(volname, origvolname);
+
+ if (IFTAPE(cdevice)) {
+ (void) sprintf(buffer, "/etc/labelit %s \"%s\" \"%s\" -n 1>&2",
+ cdevice, fsname, volname);
+ } else {
+ (void) sprintf(buffer, "/etc/labelit %s \"%s\" \"%s\" 1>&2",
+ cdevice, fsname, volname);
+ }
+ if (system(buffer)) {
+ (void) fprintf(stderr, "\nWrite of label to %s failed.", pname);
+ return (1);
+ }
+ if (label)
+ (void) sprintf(label, "%s,%s", fsname, volname);
+ return (0);
+}
+
+static void
+elabel(void)
+{
+}
+
+static int
+insert(char *device, char *label, int options, char *prompt)
+{
+ int n;
+ char strval[16], prmpt[BUFSIZ];
+ char *pt, *keyword[10];
+ char *fmtcmd;
+ char *mkfscmd;
+ char *voltxt;
+ char *removecmd;
+ char *dev_type;
+
+ voltxt = (volume ? volume : "volume");
+
+ fmtcmd = devattr(device, "fmtcmd");
+ mkfscmd = devattr(device, "mkfscmd");
+ removecmd = devattr(device, "removecmd");
+ dev_type = devattr(device, "type");
+
+ if (prompt) {
+ (void) strcpy(prmpt, prompt);
+ for (pt = prmpt; *prompt; ) {
+ if ((*prompt == '\\') && (prompt[1] == '%'))
+ prompt++;
+ else if (*prompt == '%') {
+ switch (prompt[1]) {
+ case 'v':
+ (void) strcpy(pt, voltxt);
+ break;
+
+ case 'p':
+ (void) strcpy(pt, pname);
+ break;
+
+ default:
+ *pt = '\0';
+ break;
+ }
+ pt = pt + strlen(pt);
+ prompt += 2;
+ continue;
+ }
+ *pt++ = *prompt++;
+ }
+ *pt = '\0';
+ } else {
+ (void) sprintf(prmpt, "Insert a %s into %s.", voltxt, pname);
+ if (label && (options & DM_ELABEL)) {
+ (void) strcat(prmpt, " The following external label ");
+ (void) sprintf(prmpt+strlen(prmpt),
+ " should appear on the %s:\\n\\t%s",
+ voltxt, label);
+ }
+ if (label && !(options & DM_ELABEL)) {
+ (void) sprintf(prmpt+strlen(prmpt),
+ " The %s should be internally labeled as follows:",
+ voltxt);
+ (void) sprintf(prmpt+strlen(prmpt),
+ "\\n\\t%s\\n", label);
+ }
+ }
+
+ pt = prompt = prmpt + strlen(prmpt);
+
+ n = 0;
+ pt += sprintf(pt, "\\nType [go] when ready");
+ keyword[n++] = "go";
+
+ if (options & DM_FORMFS) {
+ if (fmtcmd && *fmtcmd && mkfscmd && *mkfscmd) {
+ pt += sprintf(pt, FORMFS_MSG, voltxt);
+ keyword[n++] = "f";
+ } else if (fmtcmd && *fmtcmd) {
+ pt += sprintf(pt, FORMAT_MSG, voltxt);
+ keyword[n++] = "f";
+ }
+ if (mkfscmd && *mkfscmd) {
+ pt += sprintf(pt, MAKEFS_MSG, voltxt);
+ keyword[n++] = "m";
+ }
+ } else if (options & DM_FORMAT) {
+ if (fmtcmd && *fmtcmd) {
+ pt += sprintf(pt, FORMAT_MSG, voltxt);
+ keyword[n++] = "f";
+ }
+ }
+ if (options & DM_WLABEL) {
+ pt += sprintf(pt, WLABEL_MSG, voltxt);
+ keyword[n++] = "w";
+ }
+ if (options & DM_OLABEL) {
+ pt += sprintf(pt, OLABEL_MSG);
+ keyword[n++] = "o";
+ }
+ if (removecmd && *removecmd && dev_type && *dev_type) {
+ if (strcmp(dev_type, "diskette") == 0) {
+ pt += sprintf(pt, EJECT_MSG, voltxt);
+ keyword[n++] = "e";
+ } else {
+ pt += sprintf(pt, UNLOAD_MSG, voltxt);
+ keyword[n++] = "u";
+ }
+ }
+ keyword[n] = NULL;
+ if (ckquit)
+ pt += sprintf(pt, QUIT_MSG);
+ *pt++ = ':';
+ *pt = '\0';
+
+ pt = prmpt;
+ (void) fprintf(stderr, BELL);
+ for (;;) {
+ if (n = ckkeywd(strval, keyword, NULL, NULL, NULL, pt))
+ return (n);
+
+ pt = prompt; /* next prompt is only partial */
+ if (*strval == 'f') {
+ if (options & DM_FORMFS)
+ doformat(voltxt, fmtcmd, mkfscmd);
+ else
+ doformat(voltxt, fmtcmd, NULL);
+ continue;
+ } else if (*strval == 'm') {
+ doformat(voltxt, NULL, mkfscmd);
+ continue;
+ } else if (*strval == 'e' || *strval == 'u') {
+ (void) doremovecmd(device, 1);
+ continue;
+ } else if (*strval == 'w') {
+ (void) wilabel(label);
+ continue;
+ } else if (*strval == 'o')
+ return (-1);
+ break;
+ }
+ return (0);
+}
+
+static void
+doformat(char *voltxt, char *fmtcmd, char *mkfscmd)
+{
+ char buffer[512];
+
+ if (fmtcmd && *fmtcmd) {
+ (void) fprintf(stderr, "\t[%s]\n", fmtcmd);
+ (void) sprintf(buffer, "(%s) 1>&2", fmtcmd);
+ if (system(buffer)) {
+ (void) fprintf(stderr, ERR_FMT, voltxt);
+ return;
+ }
+ }
+ if (mkfscmd && *mkfscmd) {
+ (void) fprintf(stderr, "\t[%s]\n", mkfscmd);
+ (void) sprintf(buffer, "(%s) 1>&2", mkfscmd);
+ if (system(buffer)) {
+ (void) fprintf(stderr, ERR_MKFS, voltxt);
+ return;
+ }
+ }
+}
+
+void
+doremovecmd(char *device, int echo)
+{
+ char *removecmd;
+ char buffer[512];
+
+ if (device && *device) {
+ removecmd = devattr(device, "removecmd");
+ if (removecmd && *removecmd) {
+ if (echo)
+ (void) fprintf(stderr, "\t[%s]\n", removecmd);
+ (void) sprintf(buffer, "(%s) 1>&2", removecmd);
+ if (system(buffer)) {
+ if (echo)
+ (void) fprintf(stderr, ERR_REMOVE,
+ removecmd);
+ return;
+ }
+ }
+ }
+}
+
+static void
+labelerr(char *fsname, char *volname)
+{
+ (void) fprintf(stderr, "\nLabel incorrect.\n");
+ if (volume)
+ (void) fprintf(stderr,
+ "The internal label on the inserted %s is\n", volume);
+ else
+ (void) fprintf(stderr, "The internal label for %s is", pname);
+ (void) fprintf(stderr, "\t%s,%s\n", fsname, volname);
+}
diff --git a/usr/src/lib/libadm/common/listdev.c b/usr/src/lib/libadm/common/listdev.c
new file mode 100644
index 0000000000..6839e7c712
--- /dev/null
+++ b/usr/src/lib/libadm/common/listdev.c
@@ -0,0 +1,213 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright (c) 1997, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.2 */
+/*LINTLIBRARY*/
+
+/*
+ * listdev.c
+ *
+ * Contains:
+ * listdev() List attributes defined for a device
+ */
+
+/*
+ * Header files needed:
+ * <sys/types.h> System Data Types
+ * <string.h> Standard string definitions
+ * <devmgmt.h> Device management definitions
+ * "devtab.h" Local device table definitions
+ */
+
+#include <sys/types.h>
+#include <string.h>
+#include <devmgmt.h>
+#include "devtab.h"
+#include <stdlib.h>
+
+/*
+ * Local Definitions:
+ */
+
+
+/*
+ * Local, Static data:
+ */
+
+/*
+ * void sortlist(list)
+ * char **list
+ *
+ * This function sorts a list of character strings
+ * so that the list is ordered alphabetically.
+ *
+ * Arguments:
+ * list The list to be sorted
+ *
+ * Returns: void
+ */
+
+static void
+sortlist(char **list) /* List to be sorted */
+{
+ char **pp; /* Pointer to item being sorted */
+ char **qq;
+ char **rr;
+ char *t; /* Temp for swapping pointers */
+
+ /* If the list isn't empty ... */
+ if (*list) {
+
+ /* Find the last item in the list */
+ for (pp = list; *pp; pp++)
+ ;
+ --pp;
+
+ /*
+ * Sort 'em by sorting larger and larger portions
+ * of the list (my CSC101 fails me, I forget what
+ * this sort is called!) [Where I come from, CS
+ * is Crop Science...]
+ */
+
+ while (pp != list) {
+ qq = pp;
+ rr = --pp;
+ while (*qq && (strcmp(*rr, *qq) > 0)) {
+ t = *rr;
+ *rr++ = *qq;
+ *qq++ = t;
+ }
+ }
+ }
+}
+
+/*
+ * char **listdev(device)
+ * char *device;
+ *
+ * Generate an alphabetized list of attribute names of the
+ * attributes defined for the device <device>.
+ *
+ * Arguments:
+ * device Device who's attributes are to be listed
+ *
+ * Returns: char **
+ * List of attribute names of the attributes defined for this
+ * device. (Never empty since all devices have the "alias"
+ * attribute defined.)
+ */
+
+char **
+listdev(char *device) /* Device to describe */
+{
+ /* Automatic data */
+
+ struct devtabent *devtabent; /* Ptr to devtab entry */
+ struct attrval *attrval; /* Ptr to attr val pair */
+ char **list; /* Ptr to alloc'd list */
+ char **rtnval; /* Value to return */
+ char **pp; /* Ptr to current val in list */
+ int noerror; /* FLAG, TRUE if :-) */
+ int n; /* Temp counter */
+
+
+ /* If the device <device> is defined ... */
+ if (devtabent = _getdevrec(device)) {
+
+ /*
+ * Count the number of attributes defined for the device
+ * being sure to count the (char *) NULL that terminates
+ * the list
+ */
+
+ n = 1;
+ if (devtabent->alias) n++; /* Alias, if defined */
+ if (devtabent->cdevice) n++; /* Char spcl, if defined */
+ if (devtabent->bdevice) n++; /* Blk spcl, if defined */
+ if (devtabent->pathname) n++; /* Pathname, if defined */
+
+ /* Other attributes, if any */
+ if ((attrval = devtabent->attrlist) != NULL) {
+ do
+ n++;
+ while ((attrval = attrval->next) != NULL);
+ }
+ noerror = TRUE;
+ if (list = malloc(n*sizeof (char *))) {
+ pp = list;
+ if (devtabent->alias) {
+ if (*pp = malloc(strlen(DTAB_ALIAS)+1))
+ (void) strcpy(*pp++, DTAB_ALIAS);
+ else noerror = FALSE;
+ }
+ if (noerror && devtabent->bdevice) {
+ if (*pp = malloc(strlen(DTAB_BDEVICE)+1))
+
+ (void) strcpy(*pp++, DTAB_BDEVICE);
+ else noerror = FALSE;
+ }
+ if (noerror && devtabent->cdevice) {
+ if (*pp = malloc(strlen(DTAB_CDEVICE)+1))
+
+ (void) strcpy(*pp++, DTAB_CDEVICE);
+ else noerror = FALSE;
+ }
+ if (noerror && devtabent->pathname) {
+ if (*pp = malloc(strlen(DTAB_PATHNAME)+1))
+
+ (void) strcpy(*pp++, DTAB_PATHNAME);
+ else noerror = FALSE;
+ }
+ if (noerror && (attrval = devtabent->attrlist)) {
+ do {
+ if (*pp = malloc(strlen(attrval->attr)+1))
+
+ (void) strcpy(*pp++, attrval->attr);
+ else noerror = FALSE;
+ } while (noerror && (attrval = attrval->next));
+ }
+ if (noerror) {
+ *pp = NULL;
+ sortlist(list);
+ rtnval = list;
+ } else {
+ for (pp = list; *pp; pp++) free(*pp);
+ free(list);
+ rtnval = NULL;
+ }
+ } else rtnval = NULL;
+ } else rtnval = NULL;
+
+ _enddevtab();
+
+ /* Fini */
+ return (rtnval);
+}
diff --git a/usr/src/lib/libadm/common/listdgrp.c b/usr/src/lib/libadm/common/listdgrp.c
new file mode 100644
index 0000000000..fd7747919e
--- /dev/null
+++ b/usr/src/lib/libadm/common/listdgrp.c
@@ -0,0 +1,169 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright (c) 1997, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+/*LINTLIBRARY*/
+
+/*
+ * listdgrp.c
+ *
+ * Contents:
+ * listdgrp() List devices that belong to a device group.
+ */
+
+/*
+ * Header files referenced:
+ * <sys/types.h> System Data Types
+ * <errno.h> UNIX and C error definitions
+ * <string.h> String handling definitions
+ * <devmgmt.h> Device management definitions
+ * "devtab.h" Local device table definitions
+ */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <devmgmt.h>
+#include "devtab.h"
+
+/*
+ * Local definitions
+ */
+
+
+/*
+ * Structure definitions:
+ */
+
+/*
+ * Local functions referenced
+ */
+
+/*
+ * Global Data
+ */
+
+/*
+ * Static Data
+ */
+
+/*
+ * char **listdgrp(dgroup)
+ * char *dgroup
+ *
+ * List the members of a device group.
+ *
+ * Arguments:
+ * char *dgroup The device group needed
+ *
+ * Returns: char **
+ * A pointer to a list of pointers to char-strings containing
+ * the members of the device group.
+ *
+ * Notes:
+ * - malloc()ed space containing addresses
+ */
+
+char **
+listdgrp(char *dgroup) /* The device group to list */
+{
+ /* Automatic data */
+ struct dgrptabent *dgrpent; /* Device group description */
+ struct member *member; /* Device group member */
+ char **listbuf; /* Buffer allocated for addrs */
+ char **rtnval; /* Value to return */
+ char **pp; /* Running ptr through addrs */
+ int noerror; /* Flag, TRUE if all's well */
+ int n; /* Counter */
+
+
+ /*
+ * Initializations
+ */
+
+ /*
+ * Get the record for this device group
+ */
+
+ if (dgrpent = _getdgrprec(dgroup)) {
+
+ /* Count the number of members in the device group */
+ n = 1;
+ for (member = dgrpent->membership; member; member = member->next)
+ n++;
+
+ /* Get space for the list to return */
+ if (listbuf = malloc(n*sizeof (char **))) {
+
+ /*
+ * For each member in the device group, add that device
+ * name to the list of devices we're building
+ */
+
+ pp = listbuf;
+ noerror = TRUE;
+ for (member = dgrpent->membership; noerror && member;
+ member = member->next) {
+
+ if (*pp = malloc(strlen(member->name)+1))
+
+ (void) strcpy(*pp++, member->name);
+ else noerror = FALSE;
+ }
+
+
+ /*
+ * If there's no error, terminate the list we've built.
+ * Otherwise, free the space allocated to the stuff we've built
+ */
+
+ if (noerror) {
+ *pp = NULL;
+ rtnval = listbuf;
+ } else {
+ /* Some error occurred. Clean up allocations */
+ for (pp = listbuf; *pp; pp++) free(*pp);
+ free(listbuf);
+ rtnval = NULL;
+ }
+
+ } /* if (malloc()) */
+
+ /* Free space alloced to the device group entry */
+ _freedgrptabent(dgrpent);
+
+ } /* if (_getdgrprec()) */
+ else rtnval = NULL;
+
+
+ /* Finished -- wasn't that simple? */
+ return (rtnval);
+}
diff --git a/usr/src/lib/libadm/common/llib-ladm b/usr/src/lib/libadm/common/llib-ladm
new file mode 100644
index 0000000000..e9f241e590
--- /dev/null
+++ b/usr/src/lib/libadm/common/llib-ladm
@@ -0,0 +1,35 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1997-2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+
+#include <sys/types.h>
+#include <sys/vtoc.h>
+#include <devmgmt.h>
+#include "devtab.h"
+#include "libadm.h"
diff --git a/usr/src/lib/libadm/common/pkginfo.c b/usr/src/lib/libadm/common/pkginfo.c
new file mode 100644
index 0000000000..f6d4e72ee4
--- /dev/null
+++ b/usr/src/lib/libadm/common/pkginfo.c
@@ -0,0 +1,600 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.2 */
+/*LINTLIBRARY*/
+
+/* 5-20-92 added newroot functions */
+
+#include <stdio.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <pkginfo.h>
+#include <pkgstrct.h>
+#include <pkglocs.h>
+#include <errno.h>
+#include "libadm.h"
+
+static void initpkg(struct pkginfo *);
+static char *svr4inst(char *);
+static int rdconfig(struct pkginfo *, char *, char *);
+static int svr4info(struct pkginfo *, char *, char *);
+static int ckinfo(char *, char *, char *);
+static int ckinst(char *, char *, char *, char *, char *);
+static int verscmp(char *, char *);
+static int archcmp(char *, char *);
+static int compver(char *, char *);
+
+/*
+ * Globals:
+ * pkgdir - specifies the directory where information about packages
+ * resides, i.e. the pkginfo file is located in a subdirectory
+ *
+ * Caveats:
+ * The structure provided via "info" will contain malloc'd information;
+ * this will be free'd upon the next call to pkginfo with this
+ * same structure. Application calls must make sure this structure
+ * is null on the first call, or else we'll free static memory areas
+ * If the "pkg" argument is a wildcard specification, the next found
+ * instance available which matches the request will be returned
+ * If the "pkg" argument is a NULL pointer, the structure pointed to
+ * via "info" will have its elements deallocated and all files
+ * associated with this routine will be closed
+ *
+ * Return codes:
+ * A non-zero exit code indicates error with "errno" appropriately set:
+ * EINVAL - invalid argument
+ * ESRCH - there are no more instances of this package around
+ * EACCESS - unable to access files which should have been there
+ */
+
+/*VARARGS*/
+int
+pkginfo(struct pkginfo *info, char *pkginst, ...)
+{
+ char *ckarch, *ckvers;
+ int check;
+ va_list ap;
+
+ va_start(ap, pkginst);
+ if (info == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if (pkginst == NULL) {
+ info->pkginst = NULL;
+ (void) fpkginfo(info, NULL);
+ (void) fpkginst(NULL);
+ return (0);
+ }
+ ckarch = va_arg(ap, char *);
+ ckvers = va_arg(ap, char *);
+ va_end(ap);
+
+ check = 0;
+ if (pkgnmchk(pkginst, "all", 1)) {
+ /* wild card specification */
+ pkginst = fpkginst(pkginst, ckarch, ckvers);
+ if (pkginst == NULL)
+ return (-1);
+ } else {
+ /* request to check indicated instance */
+ if (ckarch || ckvers)
+ check++;
+ }
+
+ info->pkginst = NULL;
+ if (fpkginfo(info, pkginst))
+ return (-1);
+
+ if (check) {
+ /*
+ * verify that the provided instance matches
+ * any arch & vers specs that were provided
+ */
+ if (ckinst(pkginst, info->arch, info->version, ckarch,
+ ckvers)) {
+ errno = ESRCH;
+ return (-1);
+ }
+ }
+ return (0);
+}
+/*ARGSUSED*/
+
+int
+fpkginfo(struct pkginfo *info, char *pkginst)
+{
+
+ if (info == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ initpkg(info);
+
+ if (pkginst == NULL)
+ return (0);
+ else if (pkgnmchk(pkginst, "all", 1)) {
+ errno = EINVAL; /* not an instance identifier */
+ return (-1);
+ }
+ if (pkgdir == NULL)
+ pkgdir = get_PKGLOC();
+
+ if (rdconfig(info, pkginst, NULL)) {
+ initpkg(info);
+ return (-1);
+ }
+ return (0);
+}
+
+static void
+initpkg(struct pkginfo *info)
+{
+ /* free previously allocated space */
+ if (info->pkginst) {
+ free(info->pkginst);
+ if (info->arch)
+ free(info->arch);
+ if (info->version)
+ free(info->version);
+ if (info->basedir)
+ free(info->basedir);
+ if (info->name)
+ free(info->name);
+ if (info->vendor)
+ free(info->vendor);
+ if (info->catg)
+ free(info->catg);
+ }
+
+ info->pkginst = NULL;
+ info->arch = info->version = NULL;
+ info->basedir = info->name = NULL;
+ info->vendor = info->catg = NULL;
+ info->status = PI_UNKNOWN;
+}
+
+static int
+rdconfig(struct pkginfo *info, char *pkginst, char *ckvers)
+{
+ FILE *fp;
+ char temp[256];
+ char *value, *pt, *copy, **memloc;
+ int count;
+
+ if ((fp = pkginfopen(pkgdir, pkginst)) == NULL) {
+ if ((errno == ENOENT) && strcmp(pkgdir, get_PKGLOC()) == 0)
+ return (svr4info(info, pkginst, ckvers));
+
+ errno = EACCES;
+ return (-1);
+ }
+
+ *temp = '\0';
+ count = 0;
+ while (value = fpkgparam(fp, temp)) {
+ if (strcmp(temp, "ARCH") == 0 ||
+ strcmp(temp, "CATEGORY") == 0) {
+ /* remove all whitespace from value */
+ pt = copy = value;
+ while (*pt) {
+ if (!isspace((unsigned char)*pt))
+ *copy++ = *pt;
+ pt++;
+ }
+ *copy = '\0';
+ }
+ count++;
+ memloc = NULL;
+ if (strcmp(temp, "NAME") == 0)
+ memloc = &info->name;
+ else if (strcmp(temp, "VERSION") == 0)
+ memloc = &info->version;
+ else if (strcmp(temp, "ARCH") == 0)
+ memloc = &info->arch;
+ else if (strcmp(temp, "VENDOR") == 0)
+ memloc = &info->vendor;
+ else if (strcmp(temp, "BASEDIR") == 0)
+ memloc = &info->basedir;
+ else if (strcmp(temp, "CATEGORY") == 0)
+ memloc = &info->catg;
+
+ temp[0] = '\0';
+ if (memloc == NULL)
+ continue; /* not a parameter we're looking for */
+
+ *memloc = strdup(value);
+ if (!*memloc) {
+ (void) fclose(fp);
+ errno = ENOMEM;
+ return (-1); /* malloc from strdup failed */
+ }
+ }
+ (void) fclose(fp);
+
+ if (!count) {
+ errno = ESRCH;
+ return (-1);
+ }
+
+ info->status = (strcmp(pkgdir, get_PKGLOC()) ? PI_SPOOLED :
+ PI_INSTALLED);
+
+ if (info->status == PI_INSTALLED) {
+ (void) sprintf(temp, "%s/%s/!I-Lock!", pkgdir, pkginst);
+ if (access(temp, 0) == 0)
+ info->status = PI_PARTIAL;
+ else {
+ (void) sprintf(temp, "%s/%s/!R-Lock!", pkgdir, pkginst);
+ if (access(temp, 0) == 0)
+ info->status = PI_PARTIAL;
+ }
+ }
+ info->pkginst = strdup(pkginst);
+ return (0);
+}
+
+static int
+svr4info(struct pkginfo *info, char *pkginst, char *ckvers)
+{
+ static DIR *pdirfp;
+ struct stat64 status;
+ FILE *fp;
+ char *pt, path[128], line[128];
+ char temp[PKGSIZ+1];
+
+ if (strcmp(pkginst, "all")) {
+ if (pdirfp) {
+ (void) closedir(pdirfp);
+ pdirfp = NULL;
+ }
+ /* determine pkginst - remove '.*' extension, if any */
+ (void) strncpy(temp, pkginst, PKGSIZ);
+ if (((pt = strchr(temp, '.')) != NULL) && strcmp(pt, ".*") == 0)
+ *pt = '\0';
+ }
+
+ /* look in /usr/options direcotry for 'name' file */
+ (void) sprintf(path, "%s/%s.name", get_PKGOLD(), temp);
+ if (lstat64(path, &status)) {
+ errno = (errno == ENOENT) ? ESRCH : EACCES;
+ return (-1);
+ }
+ if ((status.st_mode & S_IFMT) != S_IFREG) {
+ errno = ESRCH;
+ return (-1);
+ }
+ if ((fp = fopen(path, "r")) == NULL) {
+ errno = (errno == ENOENT) ? ESRCH : EACCES;
+ return (-1);
+ }
+
+ /* /usr/options/xxx.name exists */
+ (void) fgets(line, 128, fp);
+ (void) fclose(fp);
+ if (pt = strchr(line, '\n'))
+ *pt = '\0'; /* remove trailing newline */
+ if (pt = strchr(line, ':'))
+ *pt++ = '\0'; /* assumed version specification */
+
+ if (info) {
+ info->name = strdup(line);
+ info->pkginst = strdup(temp);
+ if (!info->name || !info->pkginst) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ info->status = PI_PRESVR4;
+ info->version = NULL;
+ }
+
+ if (pt) {
+ /* eat leading space off of version spec */
+ while (isspace((unsigned char)*pt))
+ pt++;
+ }
+ if (ckvers && verscmp(ckvers, pt)) {
+ errno = ESRCH;
+ return (-1);
+ }
+ if (info && *pt)
+ info->version = strdup(pt);
+ return (0);
+}
+
+static int
+ckinst(char *pkginst, char *pkgarch, char *pkgvers, char *ckarch, char *ckvers)
+{
+ if (ckarch && archcmp(ckarch, pkgarch))
+ return (-1);
+ if (ckvers) {
+ /* Check for exact version match */
+ if (verscmp(ckvers, pkgvers)) {
+ /* Check for compatable version */
+ if (compver(pkginst, ckvers))
+ return (-1);
+ }
+ }
+ return (0);
+}
+
+/*VARARGS*/
+char *
+fpkginst(char *pkg, ...)
+{
+ static char pkginst[PKGSIZ+1];
+ static DIR *pdirfp;
+ struct dirent64 *dp;
+ char *pt, *ckarch, *ckvers;
+ va_list ap;
+
+ va_start(ap, pkg);
+
+ if (pkg == NULL) {
+ /* request to close or rewind the file */
+ if (pdirfp) {
+ (void) closedir(pdirfp);
+ pdirfp = NULL;
+ }
+ (void) svr4inst(NULL); /* close any files used here */
+ return (NULL);
+ }
+
+ ckarch = va_arg(ap, char *);
+ ckvers = va_arg(ap, char *);
+ va_end(ap);
+
+ if (!pkgdir)
+ pkgdir = get_PKGLOC();
+
+ if (!pdirfp && ((pdirfp = opendir(pkgdir)) == NULL)) {
+ errno = EACCES;
+ return (NULL);
+ }
+
+ while ((dp = readdir64(pdirfp)) != NULL) {
+ if (dp->d_name[0] == '.')
+ continue;
+
+ if (pkgnmchk(dp->d_name, pkg, 0))
+ continue; /* ignore invalid SVR4 package names */
+
+ if (ckinfo(dp->d_name, ckarch, ckvers))
+ continue;
+
+ /*
+ * Leave directory open in case user requests another
+ * instance.
+ */
+ (void) strcpy(pkginst, dp->d_name);
+ return (pkginst);
+ }
+
+ /*
+ * If we are searching the directory which contains info about
+ * installed packages, check the pre-svr4 directory for an instance
+ * and be sure it matches any version specification provided to us
+ */
+ if (strcmp(pkgdir, get_PKGLOC()) == 0 && (ckarch == NULL)) {
+ /* search for pre-SVR4 instance */
+ if (pt = svr4inst(pkg))
+ return (pt);
+ }
+ errno = ESRCH;
+ /* close any file we might have open */
+ (void) closedir(pdirfp);
+ pdirfp = NULL;
+ return (NULL);
+}
+/*ARGSUSED*/
+
+static char *
+svr4inst(char *pkg)
+{
+ static char pkginst[PKGSIZ];
+ static DIR *pdirfp;
+ struct dirent64 *dp;
+ struct stat64 status; /* file status buffer */
+ char *pt;
+ char path[PATH_MAX];
+
+ if (pkg == NULL) {
+ if (pdirfp) {
+ (void) closedir(pdirfp);
+ pdirfp = NULL;
+ }
+ return (NULL);
+ }
+
+ if (!pdirfp && ((pdirfp = opendir(get_PKGOLD())) == NULL))
+ return (NULL);
+
+ while ((dp = readdir64(pdirfp)) != NULL) {
+ if (dp->d_name[0] == '.')
+ continue;
+ pt = strchr(dp->d_name, '.');
+ if (pt && strcmp(pt, ".name") == 0) {
+ /* the pkgnmchk function works on .name extensions */
+ if (pkgnmchk(dp->d_name, pkg, 1))
+ continue;
+ (void) sprintf(path, "%s/%s", get_PKGOLD(), dp->d_name);
+ if (lstat64(path, &status))
+ continue;
+ if ((status.st_mode & S_IFMT) != S_IFREG)
+ continue;
+ *pt = '\0';
+ (void) strcpy(pkginst, dp->d_name);
+ return (pkginst);
+ }
+ }
+ (void) closedir(pdirfp);
+ pdirfp = NULL;
+ return (NULL);
+}
+
+static int
+verscmp(char *request, char *actual)
+{
+ /* eat leading white space */
+ while (isspace((unsigned char)*actual))
+ actual++;
+ while (isspace((unsigned char)*request))
+ request++;
+
+ while (*request || *actual) {
+ /*
+ * Once the pointers don't match, return an error condition.
+ */
+
+ if (*request++ != *actual++)
+ return (-1);
+
+ /* eat white space if any in both the strings */
+ if (isspace((unsigned char)*request)) {
+ if (*actual && !isspace((unsigned char)*actual))
+ return (-1);
+ while (isspace((unsigned char)*request))
+ request++;
+ while (isspace((unsigned char)*actual))
+ actual++;
+ }
+ }
+
+ return (0);
+
+}
+
+static int
+compver(char *pkginst, char *version)
+{
+ FILE *fp;
+ char temp[256];
+
+ (void) sprintf(temp, "%s/%s/install/compver", get_PKGLOC(), pkginst);
+ if ((fp = fopen(temp, "r")) == NULL)
+ return (-1);
+
+ while (fgets(temp, 256, fp)) {
+ if (*temp == '#')
+ continue;
+ if (verscmp(temp, version) == 0) {
+ (void) fclose(fp);
+ return (0);
+ }
+ }
+ (void) fclose(fp);
+ return (-1);
+}
+
+static int
+archcmp(char *arch, char *archlist)
+{
+ char *pt;
+
+ if (arch == NULL)
+ return (0);
+
+ /* arch and archlist must not contain whitespace! */
+
+ while (*archlist) {
+ for (pt = arch; *pt && (*pt == *archlist); )
+ pt++, archlist++;
+ if (!*pt && (!*archlist || (*archlist == ',')))
+ return (0);
+ while (*archlist) {
+ if (*archlist++ == ',')
+ break;
+ }
+ }
+ return (-1);
+}
+
+static int
+ckinfo(char *inst, char *arch, char *vers)
+{
+ FILE *fp;
+ char temp[128];
+ char file[PATH_MAX];
+ char *pt, *copy, *value, *myarch, *myvers;
+ int errflg;
+
+ (void) sprintf(file, "%s/%s/pkginfo", pkgdir, inst);
+ if ((fp = fopen(file, "r")) == NULL)
+ return (1);
+
+ if ((arch == NULL) && (vers == NULL)) {
+ (void) fclose(fp);
+ return (0);
+ }
+ temp[0] = '\0';
+ myarch = myvers = NULL;
+ while (value = fpkgparam(fp, temp)) {
+ if (strcmp(temp, "ARCH") == 0) {
+ /* remove all whitespace from value */
+ pt = copy = value;
+ while (*pt) {
+ if (!isspace((unsigned char)*pt))
+ *copy++ = *pt;
+ pt++;
+ }
+ *copy = '\0';
+ myarch = value;
+ if (myvers)
+ break;
+ } else if (strcmp(temp, "VERSION") == 0) {
+ myvers = value;
+ if (myarch)
+ break;
+ } else
+ free(value);
+ temp[0] = '\0';
+ }
+ (void) fclose(fp);
+ errflg = 0;
+
+ if (ckinst(inst, myarch, myvers, arch, vers))
+ errflg++;
+
+ if (myarch)
+ free(myarch);
+ if (myvers)
+ free(myvers);
+
+ return (errflg);
+}
diff --git a/usr/src/lib/libadm/common/pkgnmchk.c b/usr/src/lib/libadm/common/pkgnmchk.c
new file mode 100644
index 0000000000..905285dcc7
--- /dev/null
+++ b/usr/src/lib/libadm/common/pkgnmchk.c
@@ -0,0 +1,169 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright (c) 1997-2000 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.2 */
+/*LINTLIBRARY*/
+
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include "libadm.h"
+
+static char *rsvrd[] = {
+ "all",
+ "install",
+ "new",
+ NULL
+};
+
+#define NMBRK ".*"
+#define WILD1 ".*"
+#define WILD2 "*"
+#define WILD3 ".name"
+#define ABI_NAMELNGTH 9
+#define NON_ABI_NAMELNGTH 32
+
+static int abi_namelngth = 0;
+
+static int
+valname(char *pkg, int wild, int presvr4flg)
+{
+ int count, i, n;
+ char *pt;
+
+ /* wild == 1 allow wildcard specification as a name */
+ if (wild && (strcmp(pkg, "all") == 0))
+ return (0);
+
+ /* check for reserved package names */
+ for (i = 0; rsvrd[i]; i++) {
+ n = (int)strlen(rsvrd[i]);
+ if ((strncmp(pkg, rsvrd[i], n) == 0) &&
+ (!pkg[n] || strchr(NMBRK, pkg[n])))
+ return (1);
+ }
+
+ /*
+ * check for valid extensions; we must do this
+ * first since we need to look for SVR3 ".name"
+ * before we validate the package abbreviation
+ */
+ if (pt = strpbrk(pkg, NMBRK)) {
+ if (presvr4flg && (strcmp(pt, WILD3) == 0))
+ return (0); /* SVR3 packages have no validation */
+ else if ((strcmp(pt, WILD1) == 0) || (strcmp(pt, WILD2) == 0)) {
+ /* wildcard specification */
+ if (!wild)
+ return (1);
+ } else {
+ count = 0;
+ while (*++pt) {
+ count++;
+ if (!isalpha((unsigned char)*pt) &&
+ !isdigit((unsigned char)*pt) &&
+ !strpbrk(pt, "-+"))
+ return (-1);
+ }
+ if (!count || (count > 4))
+ return (-1);
+ }
+ }
+
+ /* check for valid package name */
+ count = 0;
+ if (!isalnum((unsigned char)*pkg) ||
+ (!presvr4flg && !isalpha((unsigned char)*pkg)))
+ return (-1);
+ while (*pkg && !strchr(NMBRK, *pkg)) {
+ if (!isalnum((unsigned char)*pkg) && !strpbrk(pkg, "-+"))
+ return (-1);
+ count++, pkg++;
+ }
+
+ /* Check for ABI package name length */
+ if (get_ABI_namelngth() == 1) {
+ if (count > ABI_NAMELNGTH)
+ return (-1);
+ } else if (count > NON_ABI_NAMELNGTH)
+ return (-1);
+
+ return (0); /* pkg is valid */
+}
+
+/* presvr4flg - check for pre-svr4 package names also ? */
+int
+pkgnmchk(char *pkg, char *spec, int presvr4flg)
+{
+ /* pkg is assumed to be non-NULL upon entry */
+
+ /*
+ * this routine reacts based on the value passed in spec:
+ * NULL pkg must be valid and may be a wildcard spec
+ * "all" pkg must be valid and must be an instance
+ * "x.*" pkg must be valid and must be an instance of "x"
+ * "x*" pkg must be valid and must be an instance of "x"
+ */
+
+ if (valname(pkg, ((spec == NULL) ? 1 : 0), presvr4flg))
+ return (1); /* invalid or reserved name */
+
+ if ((spec == NULL) || (strcmp(spec, "all") == 0))
+ return (0);
+
+ while (*pkg == *spec) {
+ if ((strcmp(spec, WILD1) == 0) || (strcmp(spec, WILD2) == 0) ||
+ (strcmp(spec, WILD3) == 0))
+ break; /* wildcard spec, so stop right here */
+ else if (*pkg++ == '\0')
+ return (0); /* identical match */
+ spec++;
+ }
+
+ if ((strcmp(spec, WILD1) == 0) || (strcmp(spec, WILD2) == 0) ||
+ (strcmp(spec, WILD3) == 0)) {
+ if ((pkg[0] == '\0') || (pkg[0] == '.'))
+ return (0);
+ }
+ if ((spec[0] == '\0') && (strcmp(pkg, WILD3) == 0))
+ return (0); /* compare pkg.name to pkg */
+ return (1);
+}
+
+void
+set_ABI_namelngth(void)
+{
+ abi_namelngth = 1;
+}
+
+int
+get_ABI_namelngth(void)
+{
+ return (abi_namelngth);
+}
diff --git a/usr/src/lib/libadm/common/pkgparam.c b/usr/src/lib/libadm/common/pkgparam.c
new file mode 100644
index 0000000000..816e6a1622
--- /dev/null
+++ b/usr/src/lib/libadm/common/pkgparam.c
@@ -0,0 +1,451 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright (c) 1995-1998 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+/*LINTLIBRARY*/
+
+/* 5-20-92 newroot support added */
+
+#include <stdio.h>
+#include <limits.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <pkgstrct.h>
+#include <pkginfo.h>
+#include <pkglocs.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "libadm.h"
+
+#define VALSIZ 128
+#define NEWLINE '\n'
+#define ESCAPE '\\'
+
+static char sepset[] = ":=\n";
+static char qset[] = "'\"";
+static char *pkg_inst_root = NULL;
+
+char *pkgdir = NULL;
+char *pkgfile = NULL;
+
+static char Adm_pkgold[PATH_MAX] = { 0 }; /* added for newroot */
+static char Adm_pkgloc[PATH_MAX] = { 0 }; /* added for newroot */
+static char Adm_pkgadm[PATH_MAX] = { 0 }; /* added for newroot */
+
+/*
+ * This looks in a directory that might be the top level directory of a
+ * package. It tests a temporary install directory first and then for a
+ * standard directory. This looks a little confusing, so here's what's
+ * happening. If this pkginfo is being openned in a script during a pkgadd
+ * which is updating an existing package, the original pkginfo file is in a
+ * directory that has been renamed from <pkginst> to .save.<pkginst>. If the
+ * pkgadd fails it will be renamed back to <pkginst>. We are always interested
+ * in the OLD pkginfo data because the new pkginfo data is already in our
+ * environment. For that reason, we try to open the backup first - that has
+ * the old data. This returns the first accessible path in "path" and a "1"
+ * if an appropriate pkginfo file was found. It returns a 0 if no type of
+ * pkginfo was located.
+ */
+int
+pkginfofind(char *path, char *pkg_dir, char *pkginst)
+{
+ /* Construct the temporary pkginfo file name. */
+ (void) sprintf(path, "%s/.save.%s/pkginfo", pkg_dir, pkginst);
+ if (access(path, 0)) {
+ /*
+ * This isn't a temporary directory, so we look for a
+ * regular one.
+ */
+ (void) sprintf(path, "%s/%s/pkginfo", pkg_dir, pkginst);
+ if (access(path, 0))
+ return (0); /* doesn't appear to be a package */
+ }
+
+ return (1);
+}
+
+/*
+ * This opens the appropriate pkginfo file for a particular package.
+ */
+FILE *
+pkginfopen(char *pkg_dir, char *pkginst)
+{
+ FILE *fp = NULL;
+ char temp[PATH_MAX];
+
+ if (pkginfofind(temp, pkg_dir, pkginst))
+ fp = fopen(temp, "r");
+
+ return (fp);
+}
+
+
+char *
+fpkgparam(FILE *fp, char *param)
+{
+ char ch, buffer[VALSIZ];
+ char *mempt, *copy;
+ int c, n, escape, begline, quoted;
+
+ if (param == NULL) {
+ errno = ENOENT;
+ return (NULL);
+ }
+
+ mempt = NULL;
+
+ for (;;) { /* for each entry in the file fp */
+ copy = buffer;
+ n = 0;
+
+ /* Get the next token. */
+ while ((c = getc(fp)) != EOF) {
+ ch = (char) c;
+ if (strchr(sepset, ch))
+ break;
+ if (++n < VALSIZ)
+ *copy++ = ch;
+ }
+
+ /* If it's the end of the file, exit the for() loop */
+ if (c == EOF) {
+ errno = EINVAL;
+ return (NULL); /* no more entries left */
+
+ /* If it's end of line, look for the next parameter. */
+ } else if (c == NEWLINE)
+ continue;
+
+ /* At this point copy points to the end of a valid parameter. */
+ *copy = '\0'; /* Terminate the string. */
+ if (buffer[0] == '#') /* If it's a comment, drop thru. */
+ copy = NULL; /* Comments don't get buffered. */
+ else {
+ /* If parameter is NULL, we return whatever we got. */
+ if (param[0] == '\0') {
+ (void) strcpy(param, buffer);
+ copy = buffer;
+
+ /* If this doesn't match the parameter, drop thru. */
+ } else if (strcmp(param, buffer))
+ copy = NULL;
+
+ /* Otherwise, this is our boy. */
+ else
+ copy = buffer;
+ }
+
+ n = quoted = escape = 0;
+ begline = 1;
+
+ /* Now read the parameter value. */
+ while ((c = getc(fp)) != EOF) {
+ ch = (char) c;
+ if (begline && ((ch == ' ') || (ch == '\t')))
+ continue; /* ignore leading white space */
+
+ if (ch == NEWLINE) {
+ if (!escape)
+ break; /* end of entry */
+ if (copy) {
+ if (escape) {
+ copy--; /* eat previous esc */
+ n--;
+ }
+ *copy++ = NEWLINE;
+ }
+ escape = 0;
+ begline = 1; /* new input line */
+ } else {
+ if (!escape && strchr(qset, ch)) {
+ /* handle quotes */
+ if (begline) {
+ quoted++;
+ begline = 0;
+ continue;
+ } else if (quoted) {
+ quoted = 0;
+ continue;
+ }
+ }
+ if (ch == ESCAPE)
+ escape++;
+ else if (escape)
+ escape = 0;
+ if (copy) *copy++ = ch;
+ begline = 0;
+ }
+
+ if (copy && ((++n % VALSIZ) == 0)) {
+ if (mempt) {
+ mempt = realloc(mempt,
+ (n+VALSIZ)*sizeof (char));
+ if (!mempt)
+ return (NULL);
+ } else {
+ mempt = calloc((size_t)(2*VALSIZ),
+ sizeof (char));
+ if (!mempt)
+ return (NULL);
+ (void) strncpy(mempt, buffer, n);
+ }
+ copy = &mempt[n];
+ }
+ }
+
+ /*
+ * Don't allow trailing white space.
+ * NOTE : White space in the middle is OK, since this may
+ * be a list. At some point it would be a good idea to let
+ * this function know how to validate such a list. -- JST
+ *
+ * Now while there's a parametric value and it ends in a
+ * space and the actual remaining string length is still
+ * greater than 0, back over the space.
+ */
+ while (copy && isspace((unsigned char)*(copy - 1)) && n-- > 0)
+ copy--;
+
+ if (quoted) {
+ if (mempt)
+ (void) free(mempt);
+ errno = EFAULT; /* missing closing quote */
+ return (NULL);
+ }
+ if (copy) {
+ *copy = '\0';
+ break;
+ }
+ if (c == EOF) {
+ errno = EINVAL; /* parameter not found */
+ return (NULL);
+ }
+ }
+
+ if (!mempt)
+ mempt = strdup(buffer);
+ else
+ mempt = realloc(mempt, (strlen(mempt)+1)*sizeof (char));
+ return (mempt);
+}
+
+char *
+pkgparam(char *pkg, char *param)
+{
+ static char lastfname[PATH_MAX];
+ static FILE *fp = NULL;
+ char *pt, *copy, *value, line[PATH_MAX];
+
+ if (!pkgdir)
+ pkgdir = get_PKGLOC();
+
+ if (!pkg) {
+ /* request to close file */
+ if (fp) {
+ (void) fclose(fp);
+ fp = NULL;
+ }
+ return (NULL);
+ }
+
+ if (!param) {
+ errno = ENOENT;
+ return (NULL);
+ }
+
+ if (pkgfile)
+ (void) strcpy(line, pkgfile); /* filename was passed */
+ else
+ (void) pkginfofind(line, pkgdir, pkg);
+
+ if (fp && strcmp(line, lastfname)) {
+ /* different filename implies need for different fp */
+ (void) fclose(fp);
+ fp = NULL;
+ }
+ if (!fp) {
+ (void) strcpy(lastfname, line);
+ if ((fp = fopen(lastfname, "r")) == NULL)
+ return (NULL);
+ }
+
+ /*
+ * if parameter is a null string, then the user is requesting us
+ * to find the value of the next available parameter for this
+ * package and to copy the parameter name into the provided string;
+ * if it is not, then it is a request for a specified parameter, in
+ * which case we rewind the file to start search from beginning
+ */
+ if (param[0]) {
+ /* new parameter request, so reset file position */
+ if (fseek(fp, 0L, 0))
+ return (NULL);
+ }
+
+ if (pt = fpkgparam(fp, param)) {
+ if (strcmp(param, "ARCH") == NULL ||
+ strcmp(param, "CATEGORY") == NULL) {
+ /* remove all whitespace from value */
+ value = copy = pt;
+ while (*value) {
+ if (!isspace((unsigned char)*value))
+ *copy++ = *value;
+ value++;
+ }
+ *copy = '\0';
+ }
+ return (pt);
+ }
+ return (NULL);
+}
+/*
+ * This routine sets adm_pkgloc and adm_pkgadm which are the
+ * replacement location for PKGLOC and PKGADM.
+ */
+
+static void canonize_name(char *);
+
+void
+set_PKGpaths(char *path)
+{
+ if (path && *path) {
+ (void) sprintf(Adm_pkgloc, "%s%s", path, PKGLOC);
+ (void) sprintf(Adm_pkgold, "%s%s", path, PKGOLD);
+ (void) sprintf(Adm_pkgadm, "%s%s", path, PKGADM);
+ set_install_root(path);
+ } else {
+ (void) sprintf(Adm_pkgloc, "%s", PKGLOC);
+ (void) sprintf(Adm_pkgold, "%s", PKGOLD);
+ (void) sprintf(Adm_pkgadm, "%s", PKGADM);
+ }
+ canonize_name(Adm_pkgloc);
+ canonize_name(Adm_pkgold);
+ canonize_name(Adm_pkgadm);
+ pkgdir = Adm_pkgloc;
+}
+
+char *
+get_PKGLOC(void)
+{
+ if (Adm_pkgloc[0] == NULL)
+ return (PKGLOC);
+ else
+ return (Adm_pkgloc);
+}
+
+char *
+get_PKGOLD(void)
+{
+ if (Adm_pkgold[0] == NULL)
+ return (PKGOLD);
+ else
+ return (Adm_pkgold);
+}
+
+char *
+get_PKGADM(void)
+{
+ if (Adm_pkgadm[0] == NULL)
+ return (PKGADM);
+ else
+ return (Adm_pkgadm);
+}
+
+void
+set_PKGADM(char *newpath)
+{
+ (void) strcpy(Adm_pkgadm, newpath);
+}
+
+void
+set_PKGLOC(char *newpath)
+{
+ (void) strcpy(Adm_pkgloc, newpath);
+}
+
+#define isdot(x) ((x[0] == '.')&&(!x[1]||(x[1] == '/')))
+#define isdotdot(x) ((x[0] == '.')&&(x[1] == '.')&&(!x[2]||(x[2] == '/')))
+
+static void
+canonize_name(char *file)
+{
+ char *pt, *last;
+ int level;
+
+ /* Remove references such as "./" and "../" and "//" */
+
+ for (pt = file; *pt; ) {
+ if (isdot(pt))
+ (void) strcpy(pt, pt[1] ? pt+2 : pt+1);
+ else if (isdotdot(pt)) {
+ level = 0;
+ last = pt;
+ do {
+ level++;
+ last += 2;
+ if (*last)
+ last++;
+ } while (isdotdot(last));
+ --pt; /* point to previous '/' */
+ while (level--) {
+ if (pt <= file)
+ return;
+ while ((*--pt != '/') && (pt > file))
+ ;
+ }
+ if (*pt == '/')
+ pt++;
+ (void) strcpy(pt, last);
+ } else {
+ while (*pt && (*pt != '/'))
+ pt++;
+ if (*pt == '/') {
+ while (pt[1] == '/')
+ (void) strcpy(pt, pt+1);
+ pt++;
+ }
+ }
+ }
+ if ((--pt > file) && (*pt == '/'))
+ *pt = '\0';
+}
+
+void
+set_install_root(char *path)
+{
+ pkg_inst_root = strdup(path);
+}
+
+char *
+get_install_root()
+{
+ return (pkg_inst_root);
+}
diff --git a/usr/src/lib/libadm/common/putdev.c b/usr/src/lib/libadm/common/putdev.c
new file mode 100644
index 0000000000..5d0e7dc562
--- /dev/null
+++ b/usr/src/lib/libadm/common/putdev.c
@@ -0,0 +1,1324 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1996-1997, by Sun Microsystems, Inc.
+ * All Rights reserved.
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.2 */
+/* LINTLIBRARY */
+
+/*
+ * putdev.c
+ *
+ * Global Definitions:
+ * _adddevtabrec() Add a record to the device table
+ * _putdevtabrec() Write a record to the device table
+ * _moddevtabrec() Modify a device-table record
+ * _rmdevtabrec() Remove a device-table record
+ * _rmdevtabattrs() Remove attributes from a device-table record
+ * oam_devtab File descriptor of the open device table
+ */
+
+/*
+ * G L O B A L R E F E R E N C E S
+ *
+ * Header Files
+ * Externals Referenced
+ */
+
+/*
+ * Header Files
+ * <sys/types.h> UNIX(r) Data Types
+ * <sys/stat.h>
+ * <stdio.h> Standard I/O definitions
+ * <fcntl.h> Definitions for file control
+ * <errno.h> Error handling definitions
+ * <string.h> String Handling Definitions
+ * <devmgmt.h> Device Management Definitions
+ * <unistd.h> Get UNIX(r) Standard Definitions
+ * "devtab.h" Local Device Management Definitions
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <devmgmt.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "devtab.h"
+
+/*
+ * L O C A L D E F I N I T I O N S
+ *
+ * TDTABNM Name of the temporary device table (in the
+ * directory of the existing table)
+ * TDTABNMLN Number of characters added to the directory
+ * name -- the length of the device table temp name
+ */
+
+#define TDTABNM "%sdevtab.%6.6d"
+#define TDTABNMLN 13
+
+
+/*
+ * Static functions
+ * strcatesc Copies a character-string from one place to another
+ * escaping the appropriate characters
+ * lkdevtab Locks the device table
+ * unlkdevtab Unlocks the device table
+ * mkdevtabent Builds a device-table entry from the alias and the
+ * list of attr=val pairs given
+ * opennewdevtab Opens a new device table (as a temp file)
+ * mknewdevtab Makes the temp device table the new devtab
+ * rmnewdevtab Remove the temporary device table and free space
+ * allocated to the filename of that file.
+ */
+
+static char *strcatesc(char *, char *);
+static int lkdevtab(char *, short);
+static int unlkdevtab(void);
+static struct devtabent *mkdevtabent(char *, char **);
+static FILE *opennewdevtab(char **);
+static int mknewdevtab(char *);
+static int rmnewdevtab(char *);
+
+/*
+ * char *strcatesc(p, q)
+ * char *p
+ * char *q
+ *
+ * Write the character-string pointed to by "q" to the place
+ * pointed to by "p", escaping those characters in "q" found in the
+ * string "DTAB_ESCS" by preceding them with '\\'. Return a pointer to
+ * the byte beyond the last character written to "p".
+ *
+ * Arguments:
+ * p The place to begin writing to
+ * q The string to write
+ *
+ * Returns: char *
+ * The address of the byte beyond the last character written into "p"
+ */
+
+static char *
+strcatesc(
+ char *p, /* Place to write to */
+ char *q) /* Thing to write */
+{
+ while (*q) {
+ if (strchr(DTAB_ESCS, *q)) *p++ = '\\';
+ *p++ = *q++;
+ }
+ return (p);
+}
+
+/*
+ * FILE *opennewdevtab(pname)
+ * char **pname
+ *
+ * Generates a temporary device-table name from the existing
+ * device table name (in the same directory) and opens that
+ * file for writing. It puts a pointer to the malloc()ed space
+ * containing the temp device table's name at the place referenced
+ * by <pname>.
+ *
+ * Arguments:
+ * pname Pointer to the char * to contain the address of the name
+ * of the temporary file
+ *
+ * Returns: FILE *
+ * A pointer to the opened stream or (FILE *) NULL if an error occurred.
+ * If an error occurred, "errno" will be set to reflect the problem.
+ */
+
+static FILE *
+opennewdevtab(char **pname) /* A(ptr to temp filename's path) */
+{
+ char *oldname; /* Ptr to the device-table's name */
+ char *buf; /* Ptr to the temp file's name */
+ char *dirname; /* Directory containing devtab */
+ char *p; /* Ptr to last '/' in devtab name */
+ int fd; /* Opened file descriptor */
+ FILE *fp; /* Opened file pointer */
+ struct stat64 sbuf; /* stat buf for old devtab file */
+
+ fp = NULL;
+ if (oldname = _devtabpath()) {
+ /*
+ * It is possible for us to have sufficient permissions to create
+ * the new file without having sufficient permissions to write the
+ * original devtab file. For consistency with the operations which
+ * modify the original file by writing it directly we require write
+ * permissions for the original file in order to make a new one.
+ */
+ if ((fd = open(oldname, O_WRONLY)) == -1)
+ return (NULL);
+
+ if (fstat64(fd, &sbuf) == -1) {
+ (void) close(fd);
+ return (NULL);
+ }
+ (void) close(fd);
+
+ if (p = strrchr(oldname, '/')) {
+ *(p+1) = '\0';
+ dirname = oldname;
+ } else dirname = "./";
+ if (buf = malloc(TDTABNMLN + strlen(dirname) + 1)) {
+
+ /*
+ * Build the name of the temp device table and open the
+ * file. We must reset the owner, group and perms to those
+ * of the original devtab file.
+ */
+ (void) sprintf(buf, TDTABNM, dirname, getpid());
+ if (fp = fopen(buf, "w")) {
+ *pname = buf;
+ (void) fchmod(fileno(fp), sbuf.st_mode & 0777);
+ (void) fchown(fileno(fp), sbuf.st_uid, sbuf.st_gid);
+ } else {
+ free(buf);
+ }
+ }
+
+ /*
+ *
+ * Free the space containing the device table's name.
+ */
+ free(oldname);
+ }
+
+ /* Finished. Return what we've got */
+ return (fp);
+}
+
+/*
+ * int rmnewdevtab(tempname)
+ * char *tempname
+ *
+ * Unlink the temp device table and free the memory allocated to
+ * contain the name of that file
+ *
+ * Arguments:
+ * tempname Name of the temporary file
+ *
+ * Returns: int
+ * TRUE if successful, FALSE otherwise
+ */
+
+static int
+rmnewdevtab(char *tempname) /* Filename of new device table */
+{
+ int noerr; /* Flag, TRUE if no error, FALSE otherwise */
+
+ /* Unlink the file */
+ noerr = (unlink(tempname) == 0);
+
+ /* Free the space allocated to the filename */
+ free(tempname);
+
+ /* Return success indicator */
+ return (noerr);
+}
+
+/*
+ * int mknewdevtab(tempname)
+ * char *tempname
+ *
+ * Make the temporary device-table the new system device table
+ *
+ * Arguments:
+ * tempname Name of the temporary file
+ *
+ * Returns: int
+ * TRUE if successful, FALSE otherwise
+ *
+ * Notes:
+ * - Need to use rename() someday instead of link()/unlink()
+ * - This code is somewhat ineffecient in that asks for the name
+ * of the device-table more than once. Done so that we don't
+ * have to manage that space, but this may be somewhat lazy.
+ */
+
+static int
+mknewdevtab(char *tempname) /* Ptr to name of temp dev tab */
+{
+ char *devtabname; /* Ptr to the device table's name */
+ int noerr; /* FLAG, TRUE if all's well */
+
+ /* Get the device table's pathname */
+ if (devtabname = _devtabpath()) {
+
+ /* Unlink the existing file */
+ if (unlink(devtabname) == 0) {
+
+ /* Make the temp file the real device table */
+ noerr = (link(tempname, devtabname) == 0) ? TRUE : FALSE;
+
+ /* Remove the temp file (and resources) */
+ if (noerr) (void) rmnewdevtab(tempname);
+
+ } else noerr = FALSE; /* unlink() failed */
+
+ /* Free the device table's name */
+ free(devtabname);
+
+ } else noerr = FALSE; /* devtabpath() failed */
+
+ /* Finished. Return success indicator */
+ return (noerr);
+}
+
+/*
+ * static int lkdevtab(o_mode, lktype)
+ * char *o_mode
+ * short lktype
+ *
+ * Lock the device table for writing. If it isn't available, it waits
+ * until it is.
+ *
+ * Arguments:
+ * o_mode The open() mode to use when opening the device table
+ * lktype The type of lock to apply
+ *
+ * Returns: int
+ * TRUE if successful, FALSE with errno set otherwise
+ */
+
+static int
+lkdevtab(
+ char *o_mode, /* Open mode */
+ short lktype) /* Lock type */
+{
+ /* Automatic data */
+ struct flock lockinfo; /* File locking structure */
+ int noerr; /* FLAG, TRUE if no error */
+ int olderrno; /* Old value of "errno" */
+
+
+ /* Close the device table (if it's open) */
+ _enddevtab();
+
+ /* Open the device table for read/append */
+ noerr = TRUE;
+ if (_opendevtab(o_mode)) {
+
+ /*
+ * Lock the device table (for writing). If it's not
+ * available, wait until it is, then close and open the
+ * table (modify and delete change the table!) and try
+ * to lock it again
+ */
+
+ /* Build the locking structure */
+ lockinfo.l_type = lktype;
+ lockinfo.l_whence = 0;
+ lockinfo.l_start = 0L;
+ lockinfo.l_len = 0L;
+ olderrno = errno;
+
+ /* Keep on going until we lock the file or an error happens */
+ while ((fcntl(fileno(oam_devtab), F_SETLK, &lockinfo) == -1) &&
+ !noerr) {
+ if (errno == EACCES) {
+ if (fcntl(fileno(oam_devtab), F_SETLKW, &lockinfo) == -1)
+ noerr = FALSE;
+ else {
+ /* Reopen the file (maybe it's moved?) */
+ _enddevtab();
+ if (!_opendevtab(o_mode)) noerr = FALSE;
+ else errno = olderrno;
+ }
+ } else noerr = FALSE;
+ }
+
+ if (!noerr) _enddevtab(); /* Don't keep open if in error */
+
+ } else noerr = FALSE;
+
+ /* Done */
+ return (noerr);
+}
+
+/*
+ * int unlkdevtab()
+ *
+ * Unlock the locked device table.
+ *
+ * Arguments: None
+ *
+ * Returns: int
+ * Whatever fcntl() returns...
+ */
+
+static int
+unlkdevtab(void)
+{
+ /* Automatic data */
+ struct flock lockinfo; /* Locking structure */
+ int noerr; /* FLAG, TRUE if all's well */
+
+ /* Build the locking structure */
+ lockinfo.l_type = F_UNLCK; /* Lock type */
+ lockinfo.l_whence = 0; /* Count from top of file */
+ lockinfo.l_start = 0L; /* From beginning */
+ lockinfo.l_len = 0L; /* Length of locked data */
+
+ /* Unlock it */
+ noerr = (fcntl(fileno(oam_devtab), F_SETLK, &lockinfo) != -1);
+ _enddevtab();
+
+ /* Finished */
+ return (noerr);
+}
+
+/*
+ * struct devtabent *mkdevtabent(alias, attrlist)
+ * char *alias
+ * char **attrlist
+ *
+ * This function builds a struct devtabent structure describing the
+ * alias <alias> using the information in the attribute list <attrlist>.
+ * The <attrlist> contains data of the form attr=value where attr is
+ * the name of an attribute and value is the value of that attribute.
+ *
+ * Arguments:
+ * alias The alias being added to the device table
+ * attrlist The attributes and values for that alias
+ *
+ * Returns: struct devtabent *
+ * A completed struct devtabent structure containing the description
+ * of the alias. The structure, and all of the data in the structure
+ * are each in space allocated using the malloc() function and should
+ * be freed using the free() function (or the _freedevtabent() function).
+ *
+ * Errors:
+ * EINVAL If "alias" is used as an attribute in an attr=val pair
+ * EAGAIN If an attribute is specified more than once
+ */
+
+static struct devtabent *
+mkdevtabent(
+ char *alias, /* Alias of entry */
+ char **attrlist) /* Attributes of new entry */
+{
+ /* Automatic data */
+ struct devtabent *devtabent; /* * to struct we're making */
+ struct attrval *prevattrval; /* * to prev attr/val struct */
+ struct attrval *attrval; /* * to current struct */
+ char **pp; /* Ptr into list of ptrs */
+ char *peq; /* Ptr to '=' in string */
+ char *val; /* Ptr to space for value */
+ char *name; /* Ptr to space for name */
+ ssize_t len; /* Length of name */
+ int noerr; /* TRUE if all's well */
+ int found; /* TRUE the attr is found */
+
+
+ /* No problems (yet) */
+ noerr = TRUE;
+
+ /* Get space for the structure */
+ if (devtabent = malloc(sizeof (struct devtabent))) {
+
+ /* Fill in default values */
+ if (devtabent->alias = malloc(strlen(alias)+1)) {
+
+ (void) strcpy(devtabent->alias, alias); /* alias */
+ devtabent->comment = FALSE; /* data rec */
+ devtabent->cdevice = NULL; /* cdevice */
+ devtabent->bdevice = NULL; /* bdevice */
+ devtabent->pathname = NULL; /* pathname */
+ devtabent->attrstr = NULL; /* string */
+ devtabent->attrlist = NULL; /* attr list */
+
+ /* Add attributes to the structure */
+ prevattrval = NULL;
+ if ((pp = attrlist) != NULL)
+ while (*pp && noerr) {
+
+ /* Valid attr=value pair? */
+ if (((peq = strchr(*pp, '=')) != NULL) &&
+ ((len = peq - *pp) > 0)) {
+
+ /* Get space for the value */
+ if (val = malloc(strlen(peq))) {
+ (void) strcpy(val, peq+1); /* Copy it */
+
+ /* Get space for attribute name */
+ if (name = malloc((size_t)(len + 1))) {
+ (void) strncpy(name, *pp, (size_t)len);
+ *(name+len) = '\0';
+
+ /* Specifying the alias? If so, ERROR */
+ if (strcmp(name, DTAB_ALIAS) == 0) {
+ noerr = FALSE;
+ free(name);
+ free(val);
+ errno = EINVAL;
+ }
+
+ /* Specifying the char device path? */
+ else if (strcmp(name, DTAB_CDEVICE) == 0) {
+ if (!devtabent->cdevice) {
+ if (val[0] != '/') {
+ noerr = FALSE;
+ free(name);
+ free(val);
+ errno = ENXIO;
+ } else {
+ devtabent->cdevice = val;
+ free(name);
+ }
+ } else {
+ noerr = FALSE;
+ free(name);
+ free(val);
+ errno = EAGAIN;
+ }
+ }
+
+ /* Specifying the block device path? */
+ else if (strcmp(name, DTAB_BDEVICE) == 0) {
+ if (!devtabent->bdevice) {
+ if (val[0] != '/') {
+ noerr = FALSE;
+ free(name);
+ free(val);
+ errno = ENXIO;
+ } else {
+ devtabent->bdevice = val;
+ free(name);
+ }
+ } else {
+ noerr = FALSE;
+ free(name);
+ free(val);
+ errno = EAGAIN;
+ }
+ }
+
+ /* Specifying the pathname (generic)? */
+ else if (strcmp(name, DTAB_PATHNAME) == 0) {
+ if (!devtabent->pathname) {
+ if (val[0] != '/') {
+ noerr = FALSE;
+ free(name);
+ free(val);
+ errno = ENXIO;
+ } else {
+ devtabent->pathname = val;
+ free(name);
+ }
+ } else {
+ noerr = FALSE;
+ free(name);
+ free(val);
+ errno = EAGAIN;
+ }
+ }
+
+ /* Some other attribute */
+ else {
+ found = FALSE;
+ if ((attrval = devtabent->attrlist) != NULL)
+ do {
+ if (strcmp(attrval->attr,
+ name) == 0) {
+
+ noerr = FALSE;
+ free(name);
+ free(val);
+ errno = EAGAIN;
+ }
+ } while (!found && noerr &&
+ (attrval = attrval->next));
+
+ if (!found && noerr) {
+
+ /* Get space for attr/val structure */
+ if (attrval =
+ malloc(sizeof (struct attrval))) {
+
+ /* Fill attr/val structure */
+ attrval->attr = name;
+ attrval->val = val;
+ attrval->next = NULL;
+
+ /*
+ * Link into the list of attributes
+ */
+ if (prevattrval)
+ prevattrval->next = attrval;
+ else devtabent->attrlist = attrval;
+ prevattrval = attrval;
+
+ } else {
+ /* malloc() for attrval failed */
+ noerr = FALSE;
+ free(name);
+ free(val);
+ }
+ }
+ } /* End else (some other attribute) */
+
+ } else { /* malloc() for attribute name failed */
+ noerr = FALSE;
+ free(val);
+ }
+
+ } else noerr = FALSE; /* Malloc() for "val" failed */
+
+ /* If we saw an error, free structure, returning NULL */
+ if (!noerr) {
+ _freedevtabent(devtabent);
+ devtabent = NULL;
+ }
+
+ } /* Ignore invalid attr=val pair */
+
+ if (noerr) pp++;
+
+ } /* End attribute processing loop */
+
+ } else { /* malloc() failed */
+ free(devtabent);
+ devtabent = NULL;
+ }
+ }
+
+ /* Finished */
+ return (devtabent);
+}
+
+/*
+ * int _putdevtabrec(stream, rec)
+ * FILE *stream
+ * struct devtabent *rec
+ *
+ * Write a device table record containing the information in the struct
+ * devtab structure <rec> to the current position of the standard I/O
+ * stream <stream>.
+ *
+ * Arguments:
+ * stream The stream to write to
+ * rec The structure containing the information to write
+ *
+ * Returns: int
+ * The number of characters written or EOF if there was some error.
+ */
+
+int
+_putdevtabrec(
+ FILE *stream, /* Stream to which to write */
+ struct devtabent *rec) /* Record to write */
+{
+ /* Automatic Data */
+ struct attrval *attrval; /* Ptr to attr/val pair */
+ char *buf; /* Allocated buffer */
+ char *p; /* Temp char pointer */
+ int count; /* Number of chars written */
+ size_t size = 0; /* Size of needed buffer */
+
+
+ /* Comment or data record? */
+ if (rec->comment) {
+
+ /*
+ * Record is a comment
+ */
+
+ /* Copy (escaping chars) record into temp buffer */
+ size = (strlen(rec->attrstr)*2)+1; /* Max rec size */
+ if (buf = malloc(size+1)) {
+ /* Alloc space */
+ p = strcatesc(buf, rec->attrstr); /* Copy "escaped" */
+ *(p-2) = '\n'; /* Unescape last \n */
+ *(p-1) = '\0'; /* Terminate string */
+
+ /* Write the record */
+ count = fputs(buf, stream);
+ free(buf);
+
+ } else count = EOF; /* malloc() failed */
+ }
+
+ else {
+
+ /*
+ * Record is a data record
+ */
+
+ /*
+ * Figure out maximum amount of space you're going to need.
+ * (Assume every escapable character is escaped to determine the
+ * maximum size needed)
+ */
+
+ if (rec->cdevice)
+ size += (strlen(rec->cdevice)*2) + 1; /* cdevice: */
+ if (rec->bdevice)
+ size += (strlen(rec->bdevice)*2) + 1; /* bdevice: */
+ if (rec->pathname)
+ size += (strlen(rec->pathname)*2) + 1; /* pathname: */
+ if ((attrval = rec->attrlist) != NULL) do { /* Attributes */
+ if (attrval->attr)
+ size += (strlen(attrval->attr)*2); /* attr */
+ if (attrval->val) {
+ /* val & '="" ' or val & '=""\n' */
+ size += (strlen(attrval->val)*2) +4;
+ }
+ } while ((attrval = attrval->next) != NULL); /* Next attr/val */
+ else size++; /* Else make room for trailing '\n' */
+
+ /* Alloc space for "escaped" record */
+ if (buf = malloc(size+1)) {
+
+ /* Initializations */
+ p = buf;
+
+ /* Write the alias ("alias" attribute) */
+ p = strcatesc(p, rec->alias);
+ *p++ = ':';
+
+ /* Write the character device ("cdevice" attribute) */
+ if (rec->cdevice) p = strcatesc(p, rec->cdevice);
+ *p++ = ':';
+
+ /* Write the block device ("bdevice" attribute) */
+ if (rec->bdevice) p = strcatesc(p, rec->bdevice);
+ *p++ = ':';
+
+ /* Write the pathname ("pathname" attribute) */
+ if (rec->pathname) p = strcatesc(p, rec->pathname);
+ *p++ = ':';
+
+ /* Write the rest of the attributes */
+ if ((attrval = rec->attrlist) != NULL)
+ do {
+ p = strcatesc(p, attrval->attr);
+ *p++ = '=';
+ *p++ = '"';
+ p = strcatesc(p, attrval->val);
+ *p++ = '"';
+ if ((attrval = attrval->next) != NULL)
+ *p++ = ' ';
+ } while (attrval);
+
+ /* Terminate the record */
+ *p++ = '\n';
+ *p = '\0';
+
+ /* Write the record */
+ count = fputs(buf, stream);
+ free(buf);
+ } else count = EOF; /* malloc() failed */
+ }
+
+ /* Finished */
+ return (count);
+}
+
+/*
+ * int _adddevtabrec(alias, attrval)
+ * char *alias
+ * char **attrval
+ *
+ * This function adds a record to the device table. That record will
+ * have the alias <alias> and will have the attributes described in
+ * the list referenced by <attrval>.
+ *
+ * It always adds the record to the end of the table.
+ *
+ * Arguments:
+ * alias The alias of the device whose description is being
+ * added to the device table.
+ * attrval The pointer to the first item of a list of attributes
+ * defining the device whose description is being added.
+ * (This value may be (char **) NULL).
+ *
+ * Returns: int
+ * TRUE if successful, FALSE with errno set otherwise.
+ */
+
+int
+_adddevtabrec(
+ char *alias, /* Alias to add to the device table */
+ char **attrval) /* Attributes for that device */
+{
+ /* Automatic data */
+ struct devtabent *devtabent; /* Ptr to dev tab entry */
+ int olderrno; /* Errno on entry */
+ int noerr; /* FLAG, TRUE if all's well */
+
+ /* Validate the device alias. Error (EINVAL) if it's not valid */
+ if (!_validalias(alias)) {
+ errno = EINVAL;
+ return (FALSE);
+ }
+
+ /*
+ * Lock the device table. This only returns if the table is locked or
+ * some error occurred. It waits until the table is available.
+ */
+ if (!lkdevtab("a+", F_WRLCK))
+ return (FALSE);
+
+ /* Make sure that the alias isn't already in the table */
+ noerr = TRUE;
+ olderrno = errno;
+ if (devtabent = _getdevrec(alias)) {
+
+ /* The alias is already in the table */
+ _freedevtabent(devtabent); /* Free device table info */
+ errno = EEXIST; /* Set errno, entry exists */
+ noerr = FALSE; /* All's not well */
+ } else if ((errno == ENOENT) || (errno == ENODEV)) {
+
+ /* The alias wasn't in the table or there wasn't a table. */
+
+ errno = olderrno; /* Reset errno */
+
+ /* Build a struct devtabent that describes the new alias */
+ if (devtabent = mkdevtabent(alias, attrval)) {
+
+ /* Position to the end of the existing table */
+ if (fseek(oam_devtab, 0, SEEK_END) == 0)
+
+ /* Write the new entry */
+ noerr = (_putdevtabrec(oam_devtab, devtabent) != EOF);
+
+ /* Free the info we just wrote */
+ _freedevtabent(devtabent);
+
+ } else noerr = FALSE; /* mkdevtabent() failed */
+ } else noerr = FALSE; /* Some odd error, _devtab */
+
+ /* Unlock and close the device table */
+ (void) unlkdevtab();
+
+ /* Fini */
+ return (noerr);
+}
+
+/*
+ * int _moddevtabrec(device, attrval)
+ * char *device
+ * char **attrval
+ *
+ * This function modifies the description for the specified device
+ * so that it has the attributes and values as specified in the
+ * given list.
+ *
+ * Arguments:
+ * device The name of the device whose description
+ * is being modified
+ * attrval The first attr/val value in the list (attr=val) of
+ * the attributes that are to change
+ *
+ * Returns: int
+ * TRUE if all went well, FALSE with errno set otherwise
+ */
+
+int
+_moddevtabrec(
+ char *device, /* Device to modify */
+ char **attrval) /* Attributes to add or change */
+{
+ /* Automatic data */
+ FILE *fd; /* File ptr, new device table */
+ struct devtabent *ent; /* Device's current description */
+ struct devtabent *chg; /* Changes to make to description */
+ struct attrval *new; /* New attribute/value desc */
+ struct attrval *old; /* Old attribute/value desc */
+ struct attrval *newnew; /* Next "new" value to look at */
+ struct attrval *prevnew; /* Previous item in the 'new' list */
+ char *tname; /* name of temp devtab file */
+ int noerr; /* FLAG, TRUE if all's well */
+ int found; /* FLAG, TRUE if attr found for dev */
+
+ /* Lock the device table */
+ if (!lkdevtab("r", F_WRLCK))
+ return (FALSE);
+
+ /* No problems (so far) */
+ noerr = TRUE;
+
+ /* Get the entry to modify */
+ if (ent = _getdevrec(device)) {
+
+ /* Build a structure describing the changes */
+ if (chg = mkdevtabent(device, attrval)) {
+
+ /* If the "cdevice" field is specified, change it */
+ if (chg->cdevice) {
+ if (ent->cdevice) free(ent->cdevice);
+ ent->cdevice = chg->cdevice;
+ chg->cdevice = NULL;
+ }
+
+ /* If the "bdevice" field is specified, change it */
+ if (chg->bdevice) {
+ if (ent->bdevice) free(ent->bdevice);
+ ent->bdevice = chg->bdevice;
+ chg->bdevice = NULL;
+ }
+
+ /* If the "pathname" field is specified, change it */
+ if (chg->pathname) {
+ if (ent->pathname) free(ent->pathname);
+ ent->pathname = chg->pathname;
+ chg->pathname = NULL;
+ }
+
+ /* Change the other attributes (if any) */
+ if (ent->attrlist) {
+ prevnew = NULL;
+ if ((new = chg->attrlist) != NULL) do {
+
+ found = FALSE;
+ for (old = ent->attrlist; !found && old;
+ old = old->next) {
+ if (strcmp(old->attr, new->attr) == 0) {
+ found = TRUE;
+ free(old->val);
+ old->val = new->val;
+ new->val = NULL;
+ }
+ } /* Loop through the existing attribute list */
+
+ /*
+ * If the attribute wasn't found, add it to the list
+ * of attributes for the device. If it was found, just
+ * bump to the next one and look for it
+ */
+
+ if (!found) {
+
+ /*
+ * Not found. Move attr/val description to the
+ * device's list of attributes
+ */
+
+ if (prevnew) prevnew->next = new->next;
+ else chg->attrlist = new->next;
+ newnew = new->next;
+ new->next = ent->attrlist;
+ ent->attrlist = new;
+ new = newnew;
+ } else {
+
+ /* Attribute changed, bump to the next one */
+ prevnew = new;
+ new = new->next;
+ }
+ } while (new); /* Loop for each attr to add or modify */
+
+ } else {
+
+ /* Device had no attributes -- add entire list */
+ ent->attrlist = chg->attrlist;
+ chg->attrlist = NULL;
+ }
+
+ /* Free the structure containing the changes */
+ _freedevtabent(chg);
+
+ } else noerr = FALSE; /* Couldn't build changes struct */
+
+ /* If there hasn't been an error (so far), write the new record */
+ if (noerr) {
+
+ /* Open the new device table */
+ if (fd = opennewdevtab(&tname)) {
+
+ /*
+ * For each entry in the existing table, write that entry
+ * to the new table. If the entry is the one being
+ * modified, write the modified entry instead of the
+ * original entry.
+ */
+
+ _setdevtab(); /* Rewind existing table */
+ chg = ent; /* Remember new record */
+ while (((ent = _getdevtabent()) != NULL) && noerr) {
+ if (ent->entryno != chg->entryno)
+ noerr = _putdevtabrec(fd, ent) != EOF;
+ else noerr = _putdevtabrec(fd, chg) != EOF;
+ _freedevtabent(ent);
+ }
+
+ /*
+ * If we successfully generated the new table, make it the
+ * new system device table. Otherwise, just remove the
+ * temporary file we've created.
+ */
+
+ if (noerr) {
+ (void) fclose(fd);
+ noerr = mknewdevtab(tname);
+ } else {
+ (void) fclose(fd);
+ (void) rmnewdevtab(tname);
+ }
+
+ /* Free the changed device structure */
+ _freedevtabent(chg);
+
+ } /* if (_opennewdevtab()) */
+ else noerr = FALSE;
+
+ } else _freedevtabent(ent); /* if (noerr) */
+
+ } else noerr = FALSE; /* Device not found? */
+
+ /* Finished. Unlock the device table and quit */
+ (void) unlkdevtab();
+ return (noerr);
+}
+
+/*
+ * int _rmdevtabrec(device)
+ * char *device
+ *
+ * This function removes the record in the device table for the specified
+ * device.
+ *
+ * Arguments:
+ * device The device (alias, cdevice, bdevice, pathname, or link to one)
+ * whose entry is to be removed
+ *
+ * Returns: int
+ * Success indicator: TRUE if successful, FALSE with errno set otherwise.
+ */
+
+int
+_rmdevtabrec(char *device) /* Device to remove */
+{
+ struct devtabent *rment;
+ struct devtabent *devtabent;
+ char *tempname;
+ FILE *fd;
+ int noerr;
+
+ if (!lkdevtab("r", F_WRLCK))
+ return (FALSE);
+ noerr = TRUE;
+ if (rment = _getdevrec(device)) {
+ if (fd = opennewdevtab(&tempname)) {
+ _setdevtab();
+ while (((devtabent = _getdevtabent()) != NULL) && noerr) {
+ if (devtabent->entryno != rment->entryno)
+ noerr = _putdevtabrec(fd, devtabent) != EOF;
+ _freedevtabent(devtabent);
+ }
+ if (noerr) {
+ (void) fclose(fd);
+ noerr = mknewdevtab(tempname);
+ } else {
+ (void) fclose(fd);
+ (void) rmnewdevtab(tempname);
+ }
+ } else noerr = FALSE;
+ _freedevtabent(rment);
+ } else noerr = FALSE;
+ (void) unlkdevtab();
+ return (noerr);
+}
+
+/*
+ * int _rmdevtabattrs(device, attributes, notfounds)
+ * char *device
+ * char **attributes
+ * char ***notfounds
+ *
+ * Remove the specified attributes from the specified device. The
+ * device is specified by <device>, <attributes> is the address of
+ * the first char * in the list of char * pointing to the attributes
+ * to remove from the device, and <notfounds> is the address of a
+ * char ** to put the address of the first element in the malloc()ed
+ * list of (char *) pointing to requested attributes that were not
+ * defined for the device <device>.
+ *
+ * Arguments:
+ * device The device from which attributes are to be removed
+ * attributes The address of the first element in the list of
+ * attributes to remove. This list is terminated by
+ * (char *) NULL.
+ * notfounds The place to put the address of the list of addresses
+ * referencing the requested attributes that are not
+ * defined for the specified device.
+ *
+ * Returns: int
+ * TRUE if successful, FALSE with errno set otherwise.
+ *
+ * Notes:
+ * - "alias" may not be undefined
+ * - "cdevice", "bdevice", and "pathname" are made "null", not really
+ * undefined
+ */
+
+int
+_rmdevtabattrs(
+ char *device, /* Device to modify */
+ char **attributes, /* Attributes to remove */
+ char ***notfounds) /* Attributes req'd but not found */
+{
+ /* Automatics */
+ char **pnxt; /* Ptr to next attribute */
+ char **pp; /* Ptr to current attr name */
+ struct devtabent *modent; /* Entry being modified */
+ struct devtabent *devtabent; /* Entry being copied */
+ struct attrval *attrval; /* Ptr to attr/val desc */
+ struct attrval *prevattrval; /* Ptr to prev attr/val */
+ FILE *fd; /* File desc, temp file */
+ char *tempname; /* Name of temp file */
+ int nattrs; /* Number of attrs to remove */
+ int nobaderr; /* TRUE if no fatal error */
+ int noerr; /* TRUE if no non-fatal error */
+ int found; /* TRUE if attribute found */
+ int nonotfounds; /* TRUE if no attrs not fount */
+
+
+ /* Initializations */
+ nobaderr = TRUE;
+ noerr = TRUE;
+
+ /* Count attributes to remove -- make sure "alias" isn't specified */
+ for (pp = attributes, nattrs = 0; *pp; pp++, nattrs++)
+ if (strcmp(*pp, DTAB_ALIAS) == 0) {
+ *notfounds = NULL;
+ errno = EINVAL;
+ return (FALSE);
+ }
+
+ /* Lock the device table */
+ if (!lkdevtab("r", F_WRLCK))
+ return (FALSE);
+
+ /* Is there a record for the requested device? */
+ if (modent = _getdevrec(device)) {
+
+ /* Record found. Try to modify it */
+ nonotfounds = TRUE;
+
+ /* For each of the attributes in the attribute list ... */
+ for (pp = attributes; nobaderr && *pp; pp++) {
+
+ /*
+ * Modify the device description, removing the requested
+ * attributes from the structure
+ */
+
+ found = FALSE; /* Not found yet */
+
+ /* If it's the "cdevice" attribute, make it a null-string */
+ if (strcmp(*pp, DTAB_CDEVICE) == 0) {
+ if (modent->cdevice) {
+ free(modent->cdevice);
+ modent->cdevice = NULL;
+ }
+ found = TRUE;
+ }
+
+ /* If it's the "bdevice" attribute, make it a null-string */
+ else if (strcmp(*pp, DTAB_BDEVICE) == 0) {
+ if (modent->bdevice) {
+ free(modent->bdevice);
+ modent->bdevice = NULL;
+ }
+ found = TRUE;
+ }
+
+ /* If it's the "pathname" attribute, make it a null-string */
+ else if (strcmp(*pp, DTAB_PATHNAME) == 0) {
+ if (modent->pathname) {
+ free(modent->pathname);
+ modent->pathname = NULL;
+ }
+ found = TRUE;
+ }
+
+ /* Must be one of the other "auxilliary" attributes */
+ else {
+
+ /* Search the attribute list for the attribute */
+ prevattrval = NULL;
+ if ((attrval = modent->attrlist) != NULL) do {
+ if (strcmp(*pp, attrval->attr) == 0) {
+
+ /* Found. Remove from attribute list */
+ found = TRUE;
+ free(attrval->attr);
+ free(attrval->val);
+ if (prevattrval) {
+ prevattrval->next = attrval->next;
+ free(attrval);
+ attrval = prevattrval->next;
+ } else {
+ modent->attrlist = attrval->next;
+ free(attrval);
+ attrval = modent->attrlist;
+ }
+ } else {
+ prevattrval = attrval; /* Advance to next */
+ attrval = attrval->next;
+ }
+ } while (!found && attrval);
+
+ } /* End attribute search loop */
+
+ /*
+ * If the requested attribute wasn't defined for the device,
+ * put it in the list of attributes not found
+ */
+
+ if (!found) {
+
+ /*
+ * If there's no list (yet), alloc enough space for
+ * the list
+ */
+
+ if (nonotfounds)
+ if (*notfounds = malloc(sizeof (char **)*(nattrs+1))) {
+
+ /* List allocated -- put in the first entry */
+ nonotfounds = FALSE;
+ pnxt = *notfounds;
+ if (*pnxt = malloc(strlen(*pp)+1)) {
+ errno = EINVAL;
+ noerr = FALSE;
+ (void) strcpy(*pnxt++, *pp);
+ } else {
+ /* malloc() failed, free list */
+ free(*notfounds);
+ *notfounds = NULL;
+ nonotfounds = TRUE;
+ nobaderr = FALSE;
+ }
+
+ } else nobaderr = FALSE; /* malloc() failed */
+
+ else {
+ /* Already a list, add this attribute to it */
+ if (*pnxt = malloc(strlen(*pp)+1))
+ (void) strcpy(*pnxt++, *pp);
+ else {
+ /* Out of memory, clean up */
+ for (pnxt = *notfounds; *pnxt; pnxt++)
+ free(*pnxt);
+ free(*notfounds);
+ *notfounds = NULL;
+ nonotfounds = TRUE;
+ nobaderr = FALSE;
+ }
+ }
+
+ } /* end if (!found) */
+
+ /* Terminate the not-found list */
+ if (!nonotfounds) *pnxt = NULL;
+
+ } /* end (for each attribute in attribute list) loop */
+
+
+ /*
+ * If we haven't seen any problems so far,
+ * write the new device table
+ */
+
+ if (nobaderr) {
+
+ /* Open the new device table */
+ if (fd = opennewdevtab(&tempname)) {
+
+ /*
+ * For each entry in the existing table, write that entry
+ * to the new table. If the entry is the one being
+ * modified, write the modified entry instead of the
+ * original entry.
+ */
+
+ _setdevtab(); /* Rewind existing table */
+ while (((devtabent = _getdevtabent()) != NULL) &&
+ nobaderr) {
+
+ if (devtabent->entryno != modent->entryno)
+ nobaderr = _putdevtabrec(fd, devtabent) != EOF;
+ else nobaderr = _putdevtabrec(fd, modent) != EOF;
+ _freedevtabent(devtabent);
+ }
+
+ /*
+ * If we successfully generated the new table, make it the
+ * new system device table. Otherwise, just remove the
+ * temporary file we've created.
+ */
+
+ if (nobaderr) {
+ (void) fclose(fd);
+ nobaderr = mknewdevtab(tempname);
+ } else {
+ (void) fclose(fd);
+ (void) rmnewdevtab(tempname);
+ }
+
+ } /* if (_opennewdevtab()) */
+ else nobaderr = FALSE;
+
+ /*
+ * If there was some error, we need to clean up
+ * allocated resources
+ */
+ if (!nobaderr && !nonotfounds) {
+ for (pnxt = *notfounds; *pnxt; pnxt++)
+ free(*pnxt);
+ free(*notfounds);
+ *notfounds = NULL;
+ nonotfounds = TRUE;
+ }
+
+ } /* if (nobaderr) */
+
+ /* Free the resources alloc'ed for <device>'s entry */
+ _freedevtabent(modent);
+
+ } else {
+ /* _getdevrec(device) failed */
+ nobaderr = FALSE;
+ *notfounds = NULL;
+ }
+
+ /* Unlock the device table */
+ (void) unlkdevtab();
+
+ /* We're finished */
+ return (noerr && nobaderr);
+}
diff --git a/usr/src/lib/libadm/common/putdgrp.c b/usr/src/lib/libadm/common/putdgrp.c
new file mode 100644
index 0000000000..856a69468a
--- /dev/null
+++ b/usr/src/lib/libadm/common/putdgrp.c
@@ -0,0 +1,901 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1996-1997, by Sun Microsystems, Inc.
+ * All Rights reserved.
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.2 */
+/* LINTLIBRARY */
+
+/*
+ * putdgrp.c
+ *
+ * Global Definitions:
+ * _putdgrptabrec() Write a device-group record to a stream
+ * _rmdgrptabrec() Remove a device-group table record
+ * _rmdgrpmems() Remove specific members from a device group
+ * _adddgrptabrec() Add a device-group record to the table
+ */
+
+/*
+ * G L O B A L R E F E R E N C E S
+ *
+ * Header Files
+ * Externals Referenced
+ */
+
+/*
+ * Header Files
+ * <sys/types.h> UNIX System Data Types
+ * <stdio.h> Standard I/O definitions
+ * <fcntl.h> Definitions for file control
+ * <errno.h> Error handling definitions
+ * <string.h> String Handling Definitions
+ * <unistd.h> Standard UNIX(r) Definitions
+ * <devmgmt.h> Device Management Definitions
+ * "devtab.h" Local Device Management Definitions
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <devmgmt.h>
+#include "devtab.h"
+
+/*
+ * L O C A L D E F I N I T I O N S
+ * TDGTABNM Name of the temporary device-group table (in the
+ * directory of the existing table)
+ * TDGTABNMLN Number of characters added to the directory
+ * name -- the length of the device-group table temp name
+ */
+
+#define TDGTABNM "%sdgroup.%6.6d"
+#define TDGTABNMLN 13
+
+
+/*
+ * Static functions
+ * lkdgrptab Locks the device-group table
+ * unlkdgrptab Unlocks the device-group table
+ * mkdgrptabent Builds a device-group table entry from the alias and the
+ * list of attr=val pairs given
+ * opennewdgrptab Opens a new device-group table (as a temp file)
+ * mknewdgrptab Makes the temp device-group table the new dgrptab
+ * rmnewdgrptab Remove the temporary device-group table and free space
+ * allocated to the filename of that file.
+ */
+
+static int lkdgrptab(char *o_mode, short lktype);
+static int unlkdgrptab(void);
+static struct dgrptabent *mkdgrptabent(char *dgroup, char **members);
+static FILE *opennewdgrptab(char **pname);
+static int mknewdgrptab(char *tempname);
+static int rmnewdgrptab(char *tempname);
+
+/*
+ * FILE *opennewdgrptab(pname)
+ * char **pname
+ *
+ * Generates a temporary device-group table name from the existing
+ * device-group table name (in the same directory) and opens that
+ * file for writing. It puts a pointer to the malloc()ed space
+ * containing the temp device-group table's name at the place
+ * referenced by <pname>.
+ *
+ * Arguments:
+ * pname Pointer to the char * to contain the address of the name
+ * of the temporary file
+ *
+ * Returns: FILE *
+ * A pointer to the opened stream or (FILE *) NULL if an error occurred.
+ * If an error occurred, "errno" will be set to reflect the problem.
+ */
+
+static FILE *
+opennewdgrptab(char **pname) /* A(ptr to temp filename's path) */
+{
+ char *oldname; /* Ptr to the dgrptab name */
+ char *buf; /* Ptr to the temp file's name */
+ char *dirname; /* Directory containing dgrptab */
+ char *p; /* Ptr to last '/' in dgrptab name */
+ int fd; /* Opened file descriptor */
+ FILE *fp; /* Opened file pointer */
+ struct stat64 sbuf; /* stat buf for old dgrptab file */
+
+
+ /* Initializations */
+ fp = NULL;
+
+ /* Get the name of the device-group table */
+ if (oldname = _dgrptabpath()) {
+ /*
+ * It is possible for us to have sufficient permissions to create
+ * the new file without having sufficient permissions to write the
+ * original dgrptab file. For consistency with the operations which
+ * modify the original file by writing it directly we require write
+ * permissions for the original file in order to make a new one.
+ */
+ if ((fd = open(oldname, O_WRONLY)) == -1)
+ return (NULL);
+
+ if (fstat64(fd, &sbuf) == -1) {
+ (void) close(fd);
+ return (NULL);
+ }
+ (void) close(fd);
+
+ /* Get the directory that the device-group table lives in */
+ if (p = strrchr(oldname, '/')) {
+ *(p+1) = '\0';
+ dirname = oldname;
+ } else
+ dirname = "./";
+
+ /* Get space for the temp dgrptab pathname */
+ if (buf = malloc(TDGTABNMLN+strlen(dirname)+1)) {
+
+ /*
+ * Build the name of the temp dgrptab and open the
+ * file. We must reset the owner, group and perms to those
+ * of the original dgrptab file.
+ */
+ (void) sprintf(buf, TDGTABNM, dirname, getpid());
+ if (fp = fopen(buf, "w")) {
+ *pname = buf;
+ (void) fchmod(fileno(fp), sbuf.st_mode & 0777);
+ (void) fchown(fileno(fp), sbuf.st_uid, sbuf.st_gid);
+ } else {
+ free(buf);
+ }
+ }
+
+ /* Free the space containing the dgrptab's name */
+ free(oldname);
+ }
+
+ /* Finished. Return what we've got */
+ return (fp);
+}
+
+/*
+ * int rmnewdgrptab(tempname)
+ * char *tempname
+ *
+ * Unlink the temp dgrptab and free the memory allocated to
+ * contain the name of that file
+ *
+ * Arguments:
+ * tempname Name of the temporary file
+ *
+ * Returns: int
+ * TRUE if successful, FALSE otherwise
+ */
+
+static int
+rmnewdgrptab(char *tempname)
+{
+ /* Automatic data */
+ int noerr;
+
+ /* Unlink the temporary file */
+ noerr = (unlink(tempname) == 0);
+ free(tempname);
+
+ /* Finished */
+ return (noerr);
+}
+
+/*
+ * int mknewdgrptab(tempname)
+ * char *tempname
+ *
+ * Make the temporary device-group table the new system
+ * device-group table
+ *
+ * Arguments:
+ * tempname Name of the temporary file
+ *
+ * Returns: int
+ * TRUE if successful, FALSE otherwise
+ *
+ * Notes:
+ * - Need to use rename() someday instead of link()/unlink()
+ * - This code is somewhat ineffecient in that asks for the name
+ * of the device-group table more than once. Done so that we don't
+ * have to manage that space, but this may be somewhat lazy.
+ */
+
+static int
+mknewdgrptab(char *tempname) /* Ptr to name of temp dgrp tab */
+{
+ char *dgrpname; /* Ptr to the dgrptab's name */
+ int noerr; /* FLAG, TRUE if all's well */
+
+ /* Get the dgrptab's pathname */
+ if (dgrpname = _dgrptabpath()) {
+
+ /* Unlink the existing file */
+ if (unlink(dgrpname) == 0) {
+
+ /* Make the temp file the real device-group table */
+ noerr = (link(tempname, dgrpname) == 0) ? TRUE : FALSE;
+
+ /* Remove the temp file */
+ if (noerr) noerr = rmnewdgrptab(tempname);
+
+ } else noerr = FALSE; /* unlink() failed */
+
+ /* Free the dgrptab's name */
+ free(dgrpname);
+
+ } else noerr = FALSE; /* dgrptabpath() failed */
+
+ /* Finished. Return success indicator */
+ return (noerr);
+}
+
+/*
+ * int lkdgrptab(o_mode, lktype)
+ * char *o_mode
+ * short lktype
+ *
+ * Lock the device-group table for writing. If it isn't available, it
+ * waits until it is.
+ *
+ * Arguments:
+ * o_mode The open() mode to use when opening the device-group table
+ * lktype The type of lock to apply
+ *
+ * Returns: int
+ * TRUE if successful, FALSE with errno set otherwise
+ */
+
+static int
+lkdgrptab(
+ char *o_mode, /* Open mode */
+ short lktype) /* Lock type */
+{
+ /* Automatic data */
+ struct flock lockinfo; /* File locking structure */
+ int noerr; /* FLAG, TRUE if no error */
+ int olderrno; /* Former value of errno */
+
+
+ /* Close the device-group table (if it's open) */
+ _enddgrptab();
+
+ /* Open the device-group table for read/append */
+ noerr = TRUE;
+ if (_opendgrptab(o_mode)) {
+
+ /*
+ * Lock the device-group table (for writing). If it's not
+ * available, wait until it is, then close and open the
+ * table (modify and delete change the table!) and try
+ * to lock it again
+ */
+
+ /* Build the locking structure */
+ lockinfo.l_type = lktype;
+ lockinfo.l_whence = 0;
+ lockinfo.l_start = 0L;
+ lockinfo.l_len = 0L;
+ olderrno = errno;
+
+ /* Keep on going until we lock the file or an error happens */
+ while ((fcntl(fileno(oam_dgroup), F_SETLK, &lockinfo) == -1) &&
+ !noerr) {
+
+ /*
+ * fcntl() failed.
+ * If errno=EACCES, it's because the file's locked by someone
+ * else. Wait for the file to be unlocked, then close and
+ * reopen the file and try the lock again.
+ */
+
+ if (errno == EACCES) {
+ if (fcntl(fileno(oam_dgroup), F_SETLKW, &lockinfo) == -1)
+ noerr = FALSE;
+ else {
+ _enddgrptab();
+ if (!_opendgrptab(o_mode)) noerr = FALSE;
+ else errno = olderrno;
+ }
+
+ } else noerr = FALSE; /* fcntl() failed hard */
+
+ } /* End while (fcntl() && !noerr) */
+
+ /* Don't keep file open if an error happened */
+ if (!noerr) _enddgrptab();
+
+ } else noerr = FALSE; /* _opendgrptab() failed */
+
+ /* Done */
+ return (noerr);
+}
+
+/*
+ * int unlkdgrptab()
+ *
+ * Unlock the locked device-group table.
+ *
+ * Arguments: None
+ *
+ * Returns: int
+ * Whatever fcntl() returns...
+ */
+
+static int
+unlkdgrptab(void)
+{
+ /* Automatic data */
+ struct flock lockinfo; /* Locking structure */
+ int noerr; /* FLAG, TRUE if all's well */
+
+ /* Build the locking structure */
+ lockinfo.l_type = F_UNLCK; /* Lock type */
+ lockinfo.l_whence = 0; /* Count from top of file */
+ lockinfo.l_start = 0L; /* From beginning */
+ lockinfo.l_len = 0L; /* Length of locked data */
+
+ /* Unlock it */
+ noerr = (fcntl(fileno(oam_dgroup), F_SETLK, &lockinfo) != -1);
+ _enddgrptab();
+
+ /* Finished */
+ return (noerr);
+}
+
+/*
+ * struct dgrptabent *mkdgrptabent(dgroup, members)
+ * char *dgroup
+ * char **members
+ *
+ * This function builds a struct dgrptabent structure describing the
+ * device-group <dgroup> so that it contains the members in the
+ * membership list <members>.
+ *
+ * Arguments:
+ * dgroup The device-group being added to the device-group table
+ * members The members of the device-group
+ *
+ * Returns: struct dgrptabent *
+ * A completed struct dgrptabent structure containing the description
+ * of the device group. The structure, and all of the data in the
+ * structure are each in space allocated using the malloc() function
+ * and should be freed using the free() function (or the _freedgrptabent()
+ * function.
+ */
+
+static struct dgrptabent *
+mkdgrptabent(
+ char *dgroup, /* Device-group being created (or modified) */
+ char **members) /* Members to add to that entry */
+{
+ /* Automatic data */
+ struct dgrptabent *ent; /* Ptr to struct we're making */
+ struct member *prev; /* Ptr to prev attr/val struct */
+ struct member *member; /* Ptr to current struct */
+ char **pp; /* Ptr into list of ptrs */
+ int noerr; /* TRUE if all's well */
+
+
+ /* No problems (yet) */
+ noerr = TRUE;
+
+ /* Get space for the structure */
+ if (ent = malloc(sizeof (struct dgrptabent))) {
+
+ /* Fill in default values */
+ ent->name = NULL; /* alias */
+ ent->entryno = 0; /* Entry no. */
+ ent->comment = FALSE; /* data rec */
+ ent->dataspace = NULL; /* string */
+ ent->membership = NULL; /* attr list */
+
+ /* Fill in the device-group name */
+ if (ent->name = malloc(strlen(dgroup)+1)) {
+ (void) strcpy(ent->name, dgroup);
+
+ /* Add membership to the structure */
+ prev = NULL;
+ if ((pp = members) != NULL)
+ while (*pp && noerr) {
+
+ if (member = malloc(sizeof (struct member))) {
+
+ if (member->name = malloc(strlen(*pp)+1)) {
+ (void) strcpy(member->name, *pp);
+ if (prev) prev->next = member;
+ else ent->membership = member;
+ member->next = NULL;
+ prev = member;
+ } else {
+ noerr = FALSE;
+ free(member);
+ }
+ } else noerr = FALSE;
+ pp++;
+ } /* End membership processing loop */
+
+ } else noerr = FALSE; /* malloc() failed */
+
+ /*
+ * If there was a problem, clean up the mess we've made
+ */
+
+ if (!noerr) {
+
+ _freedgrptabent(ent);
+ ent = NULL;
+
+ } /* if (noerr) */
+
+ } else noerr = FALSE; /* if (malloc(dgrptabent space)) */
+
+ /* Finished */
+ return (ent);
+}
+
+/*
+ * int _putdgrptabrec(stream, rec)
+ * FILE *stream
+ * struct dgrptabent *rec
+ *
+ * Write a device-group table record containing the information in the
+ * struct dgrptab structure <rec> to the current position of the
+ * standard I/O stream <stream>.
+ *
+ * Arguments:
+ * stream The stream to write to
+ * rec The structure containing the information to write
+ *
+ * Returns: int
+ * The number of characters written or EOF if there was some error.
+ */
+
+int
+_putdgrptabrec(
+ FILE *stream, /* Stream to write to */
+ struct dgrptabent *rec) /* Record to write */
+{
+ /* Automatic Data */
+ struct member *mem; /* Ptr to attr/val pair */
+ char *buf; /* Allocated buffer */
+ char *p; /* Temp char pointer */
+ char *q; /* Temp char pointer */
+ int count; /* Number of chars written */
+ int size; /* Size of needed buffer */
+
+
+ /* Comment or data record? */
+ if (rec->comment) count = fputs(rec->dataspace, stream);
+ else {
+
+ /*
+ * Record is a data record
+ */
+
+ /* Figure out the amount of space the record needs */
+ size = (int)strlen(rec->name) + 1; /* "name:" */
+ if ((mem = rec->membership) != NULL)
+ do { /* members */
+ /* "membername " or "membername\n" */
+ size += (int)strlen(mem->name) + 1;
+ } while ((mem = mem->next) != NULL); /* Next attr/val */
+ else
+ size++; /* Count trailing '\n' if empty grp */
+
+
+ /* Alloc space for the record */
+ if (buf = malloc((size_t) size+1)) {
+
+ /* Initializations */
+ p = buf;
+
+ /* Write the device-group name */
+ q = rec->name;
+ while (*q) *p++ = *q++;
+ *p++ = ':';
+
+ /* Write the membership list */
+ if ((mem = rec->membership) != NULL) do {
+ q = mem->name;
+ while (*q) *p++ = *q++;
+ if ((mem = mem->next) != NULL) *p++ = ',';
+ } while (mem);
+
+ /* Terminate the record */
+ *p++ = '\n';
+ *p = '\0';
+
+ /* Write the record */
+ count = fputs(buf, stream);
+ free(buf);
+ } else
+ count = EOF; /* malloc() failed */
+ }
+
+ /* Finished */
+ return (count);
+}
+
+/*
+ * int _adddgrptabrec(dgrp, members)
+ * char *dgrp
+ * char **members
+ *
+ * If <dgrp> doesn't exist, this function adds a record to the
+ * device-group table for that device-group. That record will
+ * have the name <dgrp> and will have a membership described in
+ * the list referenced by <members>. The record is added to the
+ * end of the table.
+ *
+ * If <dgrp> already exists in the table, the function adds the
+ * members in the <members> list to the group's membership.
+ *
+ * Arguments:
+ * dgrp The name of the device-group being added to the
+ * device-group table.
+ * members A pointer to the first item of the list of members
+ * in the device-group being added to the table.
+ * (This value may be (char **) NULL).
+ *
+ * Returns: int
+ * TRUE if successful, FALSE with "errno" set otherwise.
+ */
+
+int
+_adddgrptabrec(
+ char *dgrp, /* Devgrp to add to the table */
+ char **members) /* Members for that devgrp */
+{
+ /* Automatic data */
+ struct dgrptabent *ent; /* Ptr to dev tab entry */
+ struct dgrptabent *new; /* Ptr to new dev tab info */
+ struct dgrptabent *p; /* Temp ptr to dev tab info */
+ struct member *pm, *qm, *rm; /* Tmp ptrs to struct member */
+ FILE *fd; /* File descr, temp file */
+ char *path; /* Ptr to new devtab name */
+ int olderrno; /* Errno on entry */
+ int noerr; /* FLAG, TRUE if all's well */
+
+
+ /* Make a structure describing the new information */
+ if ((new = mkdgrptabent(dgrp, members)) == NULL)
+ return (FALSE);
+
+ /*
+ * Lock the device-group table. This only returns if the
+ * table is locked or some error occurred. It waits until the
+ * table is available.
+ */
+ if (!lkdgrptab("a+", F_WRLCK)) {
+ _freedgrptabent(new);
+ return (FALSE);
+ }
+
+ /*
+ * If the device-group is already in the table, add
+ * the specified members
+ */
+
+ noerr = TRUE;
+ olderrno = errno;
+ if (ent = _getdgrprec(dgrp)) {
+
+ /* Any members to add? If not, do nothing. */
+ if (new->membership) {
+
+ /* Any existing members? */
+ if ((pm = ent->membership) != NULL) {
+
+ /* Find the end of the existing membership list */
+ while (pm->next) pm = pm->next;
+
+ /* Append the new members to the membership list */
+ pm->next = new->membership;
+
+ /* Remove any duplicates */
+ for (pm = ent->membership; pm; pm = pm->next) {
+ qm = pm;
+ while ((rm = qm->next) != NULL) {
+ if (strcmp(pm->name, rm->name) == 0) {
+ qm->next = rm->next;
+ free(rm->name);
+ free(rm);
+ } else qm = rm;
+ }
+ }
+ } else ent->membership = new->membership;
+
+ /* No members in the new list any more */
+ new->membership = NULL;
+
+ /*
+ * Make a new device-group table, replacing the
+ * record for the specified device-group
+ */
+
+ _setdgrptab(); /* Rewind existing table */
+
+ /* Open a temp file */
+ if (fd = opennewdgrptab(&path)) {
+
+ /* While there's more records and no error ... */
+ while (((p = _getdgrptabent()) != NULL) && noerr) {
+
+ /*
+ * If this isn't the record we're replacing,
+ * write it to the temporary file. Otherwise,
+ * write the updated record
+ */
+
+ if (ent->entryno != p->entryno)
+ noerr = _putdgrptabrec(fd, p) != EOF;
+ else noerr = _putdgrptabrec(fd, ent) != EOF;
+ _freedgrptabent(p);
+ }
+
+ /* Fix the files */
+ if (noerr) {
+ (void) fclose(fd);
+ noerr = mknewdgrptab(path);
+ } else {
+ (void) fclose(fd);
+ (void) rmnewdgrptab(path);
+ }
+ } /* if (opennewdgrptab()) */
+
+ } /* If there's members to add */
+
+ /* Free the memory associated with the updated entry */
+ _freedgrptabent(ent);
+ }
+
+ /*
+ * Otherwise, add the device-group to the end of the table
+ */
+
+ else if (errno == EINVAL) {
+ errno = olderrno;
+ if (fseek(oam_dgroup, 0, SEEK_END) == 0)
+ noerr = (_putdgrptabrec(oam_dgroup, new) != EOF);
+ } else noerr = FALSE;
+
+ /* Finished */
+ (void) unlkdgrptab(); /* Unlock the file */
+ _freedgrptabent(new); /* Free the new dgrptab info struct */
+ return (noerr); /* Return with success indicator */
+}
+
+/*
+ * int _rmdgrptabrec(dgrp)
+ * char *dgrp
+ *
+ * This function removes the record in the device-group table
+ * for the specified device-group.
+ *
+ * Arguments:
+ * dgrp The device-group to be removed
+ *
+ * Returns: int
+ * Success indicator: TRUE if successful, FALSE with errno set otherwise.
+ */
+
+int
+_rmdgrptabrec(char *dgrp) /* Device-group to remove */
+{
+ /* Automatic data */
+ struct dgrptabent *ent; /* Entry to remove */
+ struct dgrptabent *p; /* Entry being copied */
+ FILE *fd; /* Temp file's file descriptor */
+ char *path; /* Pathname of temp file */
+ int noerr; /* FLAG, TRUE if all's well */
+
+ noerr = TRUE;
+ if (!lkdgrptab("r", F_WRLCK))
+ return (FALSE);
+ if (ent = _getdgrprec(dgrp)) {
+ _setdgrptab();
+ if (fd = opennewdgrptab(&path)) {
+ while (((p = _getdgrptabent()) != NULL) && noerr) {
+ if (ent->entryno != p->entryno)
+ noerr = _putdgrptabrec(fd, p) != EOF;
+ _freedgrptabent(p);
+ }
+ if (noerr) {
+ (void) fclose(fd);
+ noerr = mknewdgrptab(path);
+ } else {
+ (void) fclose(fd);
+ (void) rmnewdgrptab(path);
+ }
+ } else noerr = FALSE;
+ _freedgrptabent(ent);
+ } else noerr = FALSE;
+ (void) unlkdgrptab();
+ return (noerr);
+}
+
+/*
+ * int _rmdgrpmems(dgrp, mems, notfounds)
+ * char *dgrp
+ * char **mems
+ * char ***notfounds
+ *
+ * Remove the specified members from the membership of the specified
+ * device-group. Any members not found in that device-group are
+ * returned in the list referenced by <notfounds>.
+ *
+ * Arguments:
+ * dgrp The device-group from which members are to be removed
+ * mems The address of the first element in the list of
+ * members to remove. This list is terminated by
+ * (char *) NULL.
+ * notfounds The place to put the address of the list of addresses
+ * referencing the requested members that were not
+ * members of the specified device-group
+ *
+ * Returns: int
+ * TRUE if successful, FALSE with errno set otherwise.
+ */
+
+int
+_rmdgrpmems(
+ char *dgrp, /* Device-group to modify */
+ char **mems, /* Members to remove */
+ char ***notfounds) /* Members req'd but not found */
+{
+ /* Automatic data */
+ struct dgrptabent *ent; /* Entry to modify */
+ struct dgrptabent *p; /* Entry being copied */
+ struct member *pm; /* Ptr to member being examined */
+ struct member *prev; /* Ptr to previous member */
+ char **nflst; /* Ptr to not-found list */
+ char **pnf; /* Ptr into not-found list */
+ char **pp; /* Ptr into members-to-rm list */
+ FILE *fd; /* Temp file's file descriptor */
+ char *path; /* Pathname of temp file */
+ int noerr; /* TRUE if all's well */
+ int found; /* TRUE if member is in membership */
+ int i; /* Temp counter */
+
+ noerr = TRUE;
+
+ /* Lock the device-group table */
+ if (!lkdgrptab("r", F_WRLCK))
+ return (FALSE);
+
+ /* Nothing is "not found" yet */
+ *notfounds = NULL;
+
+ /* Get the entry we're to modify */
+ if (ent = _getdgrprec(dgrp)) {
+
+ /* Allocate space for the not-found list */
+ i = 1;
+ if (mems)
+ for (pp = mems; *pp; pp++)
+ i++;
+ if (nflst = malloc(i*sizeof (char *))) {
+ pnf = nflst;
+ *pnf = NULL;
+
+ /* For each member to remove ... (if any) */
+ if (mems)
+ for (pp = mems; *pp; pp++) {
+
+ found = FALSE;
+
+ /* Compare against each member in the membership list */
+ pm = ent->membership;
+ prev = NULL;
+ while (pm && !found) {
+
+ if (strcmp(*pp, pm->name) == 0) {
+
+ /* Found. Remove from linked list */
+ if (prev) prev->next = pm->next;
+ else ent->membership = pm->next;
+ if (pm->name) free(pm->name);
+ free(pm);
+ found = TRUE;
+
+ } else {
+
+ /* Bump to the next member */
+ prev = pm;
+ pm = pm->next;
+
+ }
+
+ } /* For each member in the group */
+
+ /*
+ * If the requested member-to-remove wasn't found,
+ * add it to the list of not-found members
+ */
+ if (!found) {
+ if (*pnf = malloc(strlen(*pp)+1)) {
+ (void) strcpy(*pnf++, *pp);
+ *pnf = NULL;
+ } else noerr = FALSE;
+ }
+
+ } /* for (each requested member to remove */
+
+ _setdgrptab(); /* Rewind existing table */
+
+ if (fd = opennewdgrptab(&path)) {
+ while (((p = _getdgrptabent()) != NULL) && noerr) {
+ if (ent->entryno != p->entryno)
+ noerr = _putdgrptabrec(fd, p) != EOF;
+ else noerr = _putdgrptabrec(fd, ent) != EOF;
+ _freedgrptabent(p);
+ }
+ if (noerr) {
+ (void) fclose(fd);
+ noerr = mknewdgrptab(path);
+ } else {
+ (void) fclose(fd);
+ (void) rmnewdgrptab(path);
+ }
+ } else noerr = FALSE; /* if (opennewdgrptab()) */
+
+ /*
+ * If there was no error but there was requested members
+ * that weren't found, set the not-found list and the error
+ * information. Otherwise, free the not-found list
+ */
+
+ if (noerr && (pnf != nflst)) {
+ *notfounds = nflst;
+ errno = ENODEV;
+ noerr = FALSE;
+ } else {
+ for (pnf = nflst; *pnf; pnf++) free(*pnf);
+ free(nflst);
+ if (!noerr) *notfounds = NULL;
+ }
+ } else noerr = FALSE;
+
+ /* Free the description of the modified device group */
+ _freedgrptabent(ent);
+
+ } else noerr = FALSE; /* _getdgrprec() failed */
+
+ /* Unlock the original device-group table */
+ (void) unlkdgrptab();
+ return (noerr);
+}
diff --git a/usr/src/lib/libadm/common/puterror.c b/usr/src/lib/libadm/common/puterror.c
new file mode 100644
index 0000000000..36f1f31692
--- /dev/null
+++ b/usr/src/lib/libadm/common/puterror.c
@@ -0,0 +1,91 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright (c) 1997, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+/*LINTLIBRARY*/
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "libadm.h"
+
+#define DEFMSG "ERROR: "
+#define MS sizeof (DEFMSG)
+#define INVINP "invalid input"
+
+void
+puterror(FILE *fp, char *defmesg, char *error)
+{
+ char *tmp;
+ size_t n;
+
+ if (error == NULL) {
+ /* use default message since no error was provided */
+ n = (defmesg ? strlen(defmesg) : strlen(INVINP));
+ tmp = calloc(MS+n+1, sizeof (char));
+ (void) strcpy(tmp, DEFMSG);
+ (void) strcat(tmp, defmesg ? defmesg : INVINP);
+
+ } else if (defmesg != NULL) {
+ n = strlen(error);
+ if (error[0] == '~') {
+ /* prepend default message */
+ tmp = calloc(MS+n+strlen(defmesg)+2, sizeof (char));
+ (void) strcpy(tmp, DEFMSG);
+ (void) strcat(tmp, defmesg);
+ (void) strcat(tmp, "\n");
+ ++error;
+ (void) strcat(tmp, error);
+ } else if (n && (error[n-1] == '~')) {
+ /* append default message */
+ tmp = calloc(MS+n+strlen(defmesg)+2, sizeof (char));
+ (void) strcpy(tmp, DEFMSG);
+ (void) strcat(tmp, error);
+ /* first -1 'cuz sizeof (DEFMSG) includes terminator */
+ tmp[MS-1+n-1] = '\0';
+ (void) strcat(tmp, "\n");
+ (void) strcat(tmp, defmesg);
+ } else {
+ tmp = calloc(MS+n+1, sizeof (char));
+ (void) strcpy(tmp, DEFMSG);
+ (void) strcat(tmp, error);
+ }
+ } else {
+ n = strlen(error);
+ tmp = calloc(MS+n+1, sizeof (char));
+ (void) strcpy(tmp, DEFMSG);
+ (void) strcat(tmp, error);
+ }
+ (void) puttext(fp, tmp, ckindent, ckwidth);
+ (void) fputc('\n', fp);
+ free(tmp);
+}
diff --git a/usr/src/lib/libadm/common/puthelp.c b/usr/src/lib/libadm/common/puthelp.c
new file mode 100644
index 0000000000..b0e1d6d1a0
--- /dev/null
+++ b/usr/src/lib/libadm/common/puthelp.c
@@ -0,0 +1,75 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright (c) 1997, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+/*LINTLIBRARY*/
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include "libadm.h"
+
+void
+puthelp(FILE *fp, char *defmesg, char *help)
+{
+ char *tmp;
+ size_t n;
+
+ tmp = NULL;
+ if (help == NULL) {
+ /* use default message since no help was provided */
+ help = defmesg ? defmesg : "No help available.";
+ } else if (defmesg != NULL) {
+ n = strlen(help);
+ if (help[0] == '~') {
+ /* prepend default message */
+ tmp = calloc(n+strlen(defmesg)+1, sizeof (char));
+ (void) strcpy(tmp, defmesg);
+ (void) strcat(tmp, "\n");
+ ++help;
+ (void) strcat(tmp, help);
+ help = tmp;
+ } else if (n && (help[n-1] == '~')) {
+ /* append default message */
+ tmp = calloc(n+strlen(defmesg)+2, sizeof (char));
+ (void) strcpy(tmp, help);
+ tmp[n-1] = '\0';
+ (void) strcat(tmp, "\n");
+ (void) strcat(tmp, defmesg);
+ help = tmp;
+ }
+ }
+ (void) puttext(fp, help, ckindent, ckwidth);
+ (void) fputc('\n', fp);
+ if (tmp)
+ free(tmp);
+}
diff --git a/usr/src/lib/libadm/common/putprmpt.c b/usr/src/lib/libadm/common/putprmpt.c
new file mode 100644
index 0000000000..1e15b7fb20
--- /dev/null
+++ b/usr/src/lib/libadm/common/putprmpt.c
@@ -0,0 +1,71 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright (c) 1997-2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+/*LINTLIBRARY*/
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include "libadm.h"
+
+void
+putprmpt(FILE *fp, char *prompt, char *choices[], char *defstr)
+{
+ char buffer[1024] = ""; /* NB: code should prevent overflow... */
+ int i, n;
+
+ (void) fputc('\n', fp);
+ if (prompt == NULL) {
+ (void) strlcpy(buffer, defstr ? defstr : "No default prompt.",
+ sizeof (buffer));
+ } else if (n = (int)strlen(prompt)) {
+ if (defstr == NULL)
+ defstr = "";
+ if (prompt[0] == '~')
+ (void) snprintf(buffer, sizeof (buffer), "%s%s",
+ defstr, prompt + 1);
+ else if (prompt[n-1] == '~')
+ (void) snprintf(buffer, sizeof (buffer), "%.*s%s",
+ n - 1, prompt, defstr);
+ else
+ (void) strlcpy(buffer, prompt, sizeof (buffer));
+ } else
+ (void) strlcpy(buffer, "", sizeof (buffer));
+
+ (void) strlcat(buffer, "\\ [", sizeof (buffer));
+ for (i = 0; choices && choices[i]; ++i) {
+ (void) strlcat(buffer, choices[i], sizeof (buffer));
+ (void) strlcat(buffer, ",", sizeof (buffer));
+ }
+ (void) strlcat(buffer, ckquit ? "?,q] " : "?] ", sizeof (buffer));
+
+ (void) puttext(fp, buffer, 0, ckwidth);
+}
diff --git a/usr/src/lib/libadm/common/puttext.c b/usr/src/lib/libadm/common/puttext.c
new file mode 100644
index 0000000000..71870a8078
--- /dev/null
+++ b/usr/src/lib/libadm/common/puttext.c
@@ -0,0 +1,307 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright (c) 1997-1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+/*LINTLIBRARY*/
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.2 */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <wchar.h>
+#include <libintl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include "libadm.h"
+
+#define MWIDTH 256
+#define WIDTH 60
+
+int
+puttext(FILE *fp, char *str, int lmarg, int rmarg)
+{
+ wchar_t *wstr, *wp;
+ wchar_t *copy, *lastword, *lastend, temp[MWIDTH+1];
+ size_t len, ret;
+ int width, i, n, force, wordcnt;
+ int wlen, mlen, bdg;
+ char mbs[MB_LEN_MAX];
+ char mbtemp[(MWIDTH+1) * MB_LEN_MAX];
+
+ width = rmarg ? (rmarg - lmarg) : (WIDTH - lmarg);
+ if (width > MWIDTH)
+ width = MWIDTH;
+
+ if (!str || !*str)
+ return (width);
+
+ len = strlen(str);
+ wstr = (wchar_t *)malloc(sizeof (wchar_t) * (len + 1));
+ if (wstr == NULL)
+ return (width);
+
+ ret = mbstowcs(wstr, (const char *)str, len + 1);
+ if (ret == (size_t)-1) {
+ free(wstr);
+ return (width);
+ }
+
+ wp = wstr;
+
+ if (*wp == L'!') {
+ wp++;
+ force = 1;
+ for (i = 0; i < lmarg; i++)
+ (void) putc(' ', fp);
+ } else {
+ while (iswspace(*wp))
+ ++wp; /* eat leading white space */
+ force = 0;
+ }
+
+ wordcnt = 0;
+ n = 0;
+ copy = temp;
+ lastword = wp;
+ lastend = NULL;
+ do {
+ if (force) {
+ if (*wp == L'\n') {
+ (void) putc('\n', fp);
+ for (i = 0; i < lmarg; i++)
+ (void) putc(' ', fp);
+ wp++;
+ n = 0;
+ } else {
+ wlen = wcwidth(*wp);
+ /*
+ * Using putc instead of fputwc here to avoid
+ * mixing up the byte stream and the wide stream
+ * for fp.
+ */
+ mlen = wctomb(mbs, *wp);
+ if (mlen == -1) {
+ /*
+ * wctomb failed
+ * nothing will be outputted
+ */
+ wp++;
+ } else {
+ for (i = 0; i < mlen; i++)
+ (void) putc(mbs[i], fp);
+ wp++;
+ /*
+ * if wlen is a negative value (*wp is not printable),
+ * add 1 to n. (non-printable char shares 1 column.
+ */
+ if (wlen >= 0)
+ n += wlen;
+ else
+ n++;
+ }
+ }
+ continue;
+ }
+ if (iswspace(*wp)) {
+ /* eat multiple tabs/nl after whitespace */
+ while ((*++wp == L'\t') || (*wp == '\n'));
+ wordcnt++;
+ lastword = wp;
+ lastend = copy;
+ *copy++ = L' ';
+ n++;
+ } else if (*wp == L'\\') {
+ if (*(wp + 1) == L'n') {
+ wordcnt++;
+ n = width + 1;
+ wp += 2;
+ lastword = wp;
+ lastend = copy;
+ } else if (*(wp + 1) == L't') {
+ wordcnt++;
+ do {
+ *copy++ = L' ';
+ } while (++n % 8);
+ n++;
+ wp += 2;
+ lastword = wp;
+ lastend = copy;
+ } else if (*(wp + 1) == L' ') {
+ *copy++ = L' ';
+ wp += 2;
+ n++;
+ } else {
+ if (iswprint(*wp) && iswprint(*(wp + 1))) {
+ /*
+ * Only if both *wp and *(wp +1) are printable,
+ * tries to check the binding weight between them.
+ */
+ wlen = wcwidth(*wp);
+ if (n + wlen > width) {
+ /*
+ * if (n + wlen) is larger than width, *wp will be
+ * put to the next line.
+ */
+ *copy++ = *wp++;
+ n = width + 1;
+ goto fold;
+ } else {
+ n += wlen;
+ bdg = wdbindf(*wp,
+ *(wp + 1), 1);
+ *copy++ = *wp++;
+ if (bdg < 5) {
+ /*
+ * binding weight between *wp and *(wp + 1) is
+ * enough small to fold the line there.
+ */
+ lastword = wp;
+ lastend = copy;
+ wordcnt++;
+ }
+ }
+ } else {
+ wlen = wcwidth(*wp);
+ if (wlen > 0) {
+ /*
+ * *wp is printable
+ */
+ if (n + wlen > width) {
+ /*
+ * if (n + wlen) is larger than width, *wp will
+ * be put to the next line.
+ */
+ *copy++ = *wp++;
+ n = width + 1;
+ goto fold;
+ } else {
+ n += wlen;
+ }
+ } else {
+ /*
+ * *wp is not printable, and shares 1 column.
+ */
+ n++;
+ }
+ *copy++ = *wp++;
+ }
+ }
+ } else {
+ if (iswprint(*wp) && iswprint(*(wp + 1))) {
+ /*
+ * Only if both *wp and *(wp + 1) are printable,
+ * tries to check the binding weight between them.
+ */
+ wlen = wcwidth(*wp);
+ if (n + wlen > width) {
+ /*
+ * if (n + wlen) is larger than width, *wp will be
+ * put to the next line.
+ */
+ *copy++ = *wp++;
+ n = width + 1;
+ goto fold;
+ }
+ n += wlen;
+ bdg = wdbindf(*wp, *(wp + 1), 1);
+ *copy++ = *wp++;
+ if (bdg < 5) {
+ /*
+ * binding weight between *wp and *(wp + 1) is
+ * enough small to fold the line there.
+ */
+ lastword = wp;
+ lastend = copy;
+ wordcnt++;
+ }
+ } else {
+ wlen = wcwidth(*wp);
+ if (wlen > 0) {
+ /*
+ * *wp is printable
+ */
+ if (n + wlen > width) {
+ /*
+ * if (n + wlen) is larger than width, *wp will
+ * be put to the next line.
+ */
+ *copy++ = *wp++;
+ n = width + 1;
+ goto fold;
+ } else {
+ n += wlen;
+ }
+ } else {
+ /*
+ * *wp is not printable, and shares 1 column.
+ */
+ n++;
+ }
+ *copy++ = *wp++;
+ }
+ }
+
+fold:
+ if (n >= width) {
+ if (lastend)
+ *lastend = L'\0';
+ else
+ *copy = L'\0';
+ for (i = 0; i < lmarg; i++)
+ (void) putc(' ', fp);
+ mlen = wcstombs(mbtemp, temp, MWIDTH+1);
+ for (i = 0; i < mlen; i++)
+ (void) putc(mbtemp[i], fp);
+ (void) putc('\n', fp);
+
+ lastend = NULL;
+ copy = temp;
+ if (wordcnt)
+ wp = lastword;
+
+ wordcnt = 0;
+ n = 0;
+ if (!force) {
+ while (iswspace(*wp))
+ wp++;
+ }
+ }
+ } while (*wp != L'\0');
+ if (!force) {
+ *copy = L'\0';
+ for (i = 0; i < lmarg; i++)
+ (void) putc(' ', fp);
+ mlen = wcstombs(mbtemp, temp, MWIDTH+1);
+ for (i = 0; i < mlen; i++)
+ (void) putc(mbtemp[i], fp);
+ }
+ free(wstr);
+ return (width - n - !force);
+}
diff --git a/usr/src/lib/libadm/common/rdwr_vtoc.c b/usr/src/lib/libadm/common/rdwr_vtoc.c
new file mode 100644
index 0000000000..b662bded7c
--- /dev/null
+++ b/usr/src/lib/libadm/common/rdwr_vtoc.c
@@ -0,0 +1,162 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1991-1997,2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*LINTLIBRARY*/
+
+
+#include <stdio.h>
+#include <errno.h>
+#include <memory.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/dkio.h>
+#include <sys/vtoc.h>
+
+/*
+ * Read VTOC - return partition number.
+ */
+int
+read_vtoc(int fd, struct vtoc *vtoc)
+{
+ struct dk_cinfo dki_info;
+
+ /*
+ * Read the vtoc.
+ */
+ if (ioctl(fd, DKIOCGVTOC, (caddr_t)vtoc) == -1) {
+ switch (errno) {
+ case EIO:
+ return (VT_EIO);
+ case EINVAL:
+ return (VT_EINVAL);
+ /* for disks > 1TB */
+ case ENOTSUP:
+ return (VT_ENOTSUP);
+ default:
+ return (VT_ERROR);
+ }
+ }
+
+ /*
+ * Sanity-check the vtoc.
+ */
+ if (vtoc->v_sanity != VTOC_SANE) {
+ return (VT_EINVAL);
+ }
+
+ /*
+ * Convert older-style vtoc's.
+ */
+ switch (vtoc->v_version) {
+ case 0:
+ /*
+ * No vtoc information. Install default
+ * nparts/sectorsz and version. We are
+ * assuming that the driver returns the
+ * current partition information correctly.
+ */
+
+ vtoc->v_version = V_VERSION;
+ if (vtoc->v_nparts == 0)
+ vtoc->v_nparts = V_NUMPAR;
+ if (vtoc->v_sectorsz == 0)
+ vtoc->v_sectorsz = DEV_BSIZE;
+
+ break;
+
+ case V_VERSION:
+ break;
+
+ default:
+ return (VT_EINVAL);
+ }
+
+ /*
+ * Return partition number for this file descriptor.
+ */
+ if (ioctl(fd, DKIOCINFO, (caddr_t)&dki_info) == -1) {
+ switch (errno) {
+ case EIO:
+ return (VT_EIO);
+ case EINVAL:
+ return (VT_EINVAL);
+ default:
+ return (VT_ERROR);
+ }
+ }
+ if (dki_info.dki_partition > V_NUMPAR) {
+ return (VT_EINVAL);
+ }
+ return ((int)dki_info.dki_partition);
+}
+
+/*
+ * Write VTOC
+ */
+int
+write_vtoc(int fd, struct vtoc *vtoc)
+{
+ int i;
+ /*
+ * Sanity-check the vtoc
+ */
+ if (vtoc->v_sanity != VTOC_SANE || vtoc->v_nparts > V_NUMPAR) {
+ return (-1);
+ }
+
+ /*
+ * since many drivers won't allow opening a device make sure
+ * all partitions aren't being set to zero. If all are zero then
+ * we have no way to set them to something else
+ */
+
+ for (i = 0; i < (int)vtoc->v_nparts; i++)
+ if (vtoc->v_part[i].p_size > 0)
+ break;
+ if (i == (int)vtoc->v_nparts)
+ return (-1);
+
+ /*
+ * Write the vtoc
+ */
+ if (ioctl(fd, DKIOCSVTOC, (caddr_t)vtoc) == -1) {
+ switch (errno) {
+ case EIO:
+ return (VT_EIO);
+ case EINVAL:
+ return (VT_EINVAL);
+ /* for disks > 1TB */
+ case ENOTSUP:
+ return (VT_ENOTSUP);
+ default:
+ return (VT_ERROR);
+ }
+ }
+ return (0);
+}
diff --git a/usr/src/lib/libadm/common/regexp.c b/usr/src/lib/libadm/common/regexp.c
new file mode 100644
index 0000000000..8fc7505581
--- /dev/null
+++ b/usr/src/lib/libadm/common/regexp.c
@@ -0,0 +1,66 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#define INIT char *sp = instring;
+#define GETC() (*sp++)
+#define PEEKC() (*sp)
+#define UNGETC(c) (--sp)
+#define RETURN(pt) return (pt)
+#define ERROR(c) return (NULL)
+
+/*
+ * Keep these symbols private to the library.
+ * The originals, which were exported from libadm by mistake,
+ * are now redirected to libgen.so.1 via 'filter' in adm.spec
+ */
+
+#define advance __advance
+#define compile __compile
+#define step __step
+
+#define loc1 __loc1
+#define loc2 __loc2
+#define locs __locs
+#define nbra __nbra
+
+/*
+ * We should do the same for these too, but they don't exist in libgen.so.1.
+ * We continue to export them from libadm.so.1, even though they are dummies.
+ */
+
+int circf;
+int sed;
+
+#define circf __circf
+#define sed __sed
+
+#include <regexp.h>
diff --git a/usr/src/lib/libadm/common/space.c b/usr/src/lib/libadm/common/space.c
new file mode 100644
index 0000000000..f19d7cf18b
--- /dev/null
+++ b/usr/src/lib/libadm/common/space.c
@@ -0,0 +1,36 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright (c) 1997, by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+/*LINTLIBRARY*/
+
+int ckquit = 1;
+int ckwidth = 79;
+int ckindent = 8;
diff --git a/usr/src/lib/libadm/i386/Makefile b/usr/src/lib/libadm/i386/Makefile
new file mode 100644
index 0000000000..6351d70dde
--- /dev/null
+++ b/usr/src/lib/libadm/i386/Makefile
@@ -0,0 +1,33 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 1997-2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libadm/i386/Makefile
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/libadm/inc/devtab.h b/usr/src/lib/libadm/inc/devtab.h
new file mode 100644
index 0000000000..3373cad5e5
--- /dev/null
+++ b/usr/src/lib/libadm/inc/devtab.h
@@ -0,0 +1,243 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1997 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ifndef _DEVTAB_H
+#define _DEVTAB_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * devtab.h
+ *
+ * This header file is local to the liboam component
+ * and should not contain any data that may need to
+ * be reference anywhere. The definitions here are used
+ * to reference the device tables and the device-group
+ * tables.
+ */
+
+/*
+ * Constant definitions
+ * NULL Manifest constant NULL (null-address)
+ * TRUE Boolean TRUE value
+ * FALSE Boolean FALSE value
+ * DTAB_BUFSIZ Initial buffersize for reading device table records
+ * DTAB_BUFINC Amount to increase device table record buffer
+ * DGRP_BUFSIZ Initial buffersize for reading devgrp table records
+ * DGRP_BUFINC Amount to increase device-group table record buffer
+ * XTND_MAXCNT Maximum extend count (may have insane tables)
+ * DTAB_ESCS Characters that are escaped in fields in the devtab
+ */
+
+#ifndef NULL
+#define NULL (0)
+#endif
+
+#ifndef TRUE
+#define TRUE (1)
+#endif
+
+#ifndef FALSE
+#define FALSE (0)
+#endif
+
+#define DTAB_BUFSIZ 512
+#define DTAB_BUFINC 512
+#define DGRP_BUFSIZ 512
+#define DGRP_BUFINC 512
+#define XTND_MAXCNT 16
+
+#define DTAB_ESCS ":\\\"\n"
+
+/*
+ * oam_devtab File descriptor of the open device table
+ */
+
+extern FILE *oam_devtab;
+extern FILE *oam_dgroup;
+
+/*
+ * Structure definitions for device table records:
+ * devtabent Describes an entry in the device table
+ * dgrpent Describes an entry in the device-group table
+ * attrval Describes an attribute/value pair
+ */
+
+/*
+ * struct devtabent
+ *
+ * Describes an entry in the device table.
+ *
+ * entryno This record's entry number in the device table
+ * comment Comment flag, TRUE if record is a comment
+ * alias The device's alias
+ * cdevice A pathname to the inode describing the device as
+ * a character-special device
+ * bdevice A pathname to the inode describing the device as
+ * a block-special device
+ * pathname A pathname to the device (not char or blk special)
+ * attrstr The character-string containing the attributes
+ * attrlist The address of the first attribute description
+ */
+
+struct devtabent {
+ int entryno; /* Entry number of this record */
+ int comment; /* Comment flag */
+ char *alias; /* Alias of the device */
+ char *cdevice; /* Character device pathname */
+ char *bdevice; /* Block device pathname */
+ char *pathname; /* Vanilla pathname */
+ char *attrstr; /* String containing attributes */
+ struct attrval *attrlist; /* Addr of 1st attribute description */
+};
+
+/*
+ * struct attrval
+ *
+ * Describes an attribute-value pair
+ *
+ * char *attr Pointer to the name of the attribute
+ * char *val Pointer to the name of the value of the attr
+ * struct attrval *next Pointer to the next item in the list
+ */
+
+struct attrval {
+ char *attr; /* Attribute name */
+ char *val; /* Value of the attribute */
+ struct attrval *next; /* Next attrval in list */
+};
+
+/*
+ * Structure definitions for device-group records:
+ * struct dgrptabent Describes a record in the device-group table
+ * struct member Describes a member of a device group
+ */
+
+/*
+ * struct dgrptabent
+ * entryno The entry number of this record
+ * comment Comment flag, TRUE if record is a comment
+ * name The name of the device group
+ * memberspace The buffer containing the members of the
+ * device group
+ * membership Pointer to the head of the list of
+ * members in the group.
+ */
+
+struct dgrptabent {
+ int entryno; /* Entry number of this record */
+ int comment; /* TRUE if a comment record */
+ char *name; /* Device group name */
+ char *dataspace; /* Buffer containing membership */
+ struct member *membership; /* Ptr to top of membership list */
+};
+
+
+/*
+ * struct member
+ * name Member name (a device alias or pathname)
+ * next Ptr to next item in the list
+ */
+
+struct member {
+ char *name; /* Member name */
+ struct member *next; /* Next member in the list */
+};
+
+/*
+ * Global function and data definitions:
+ * _setdevtab() Rewinds the open device table
+ * _enddevtab() Closes the open device table
+ * _getdevtabent() Gets the next device table entry
+ * _freedevtabent() Frees space allocated to a device-table entry
+ * _getdevrec() Gets a specific device table entry
+ * _opendevtab() Open the device table
+ * _devtabpath() Get the pathname of the device table file
+ *
+ * _setdgrptab() Rewind the open device-group table
+ * _enddgrptab() Close the open device table
+ * _getdgrptabent() Get the next device-group table entry
+ * _freedgrptabent() Frees space alloced to a dev-grp table entry
+ * _getdgrprec() Gets a specific device-group table entry
+ * _opendgrptab() Open the device group table
+ * _dgrptabpath() Get the pathname of the device group table file
+ *
+ * _openlkfile() Open device lock file
+ * rsvtabpath() Get device lock file pathname
+ * _closelkfile() Close device lock file
+ *
+ * _validalias() Determine if a character-string is a valid alias
+ * unreserv() Remove a device reservation
+ */
+
+ void _setdevtab(void);
+ void _enddevtab(void);
+ struct devtabent *_getdevtabent(void);
+ void _freedevtabent(struct devtabent *);
+ struct devtabent *_getdevrec(char *);
+ int _opendevtab(char *);
+ char *_devtabpath(void);
+
+ void _setdgrptab(void);
+ void _enddgrptab(void);
+ struct dgrptabent *_getdgrptabent(void);
+ void _freedgrptabent(struct dgrptabent *);
+ struct dgrptabent *_getdgrprec(char *);
+ int _opendgrptab(char *);
+ char *_dgrptabpath(void);
+
+ int _openlkfile(void);
+ char *_rsvtabpath(void);
+ int _closelkfile(void);
+
+ int _validalias(char *);
+ int unreserv(int, char *);
+
+extern int _adddevtabrec(char *, char **);
+extern int _moddevtabrec(char *, char **);
+extern int _putdevtabrec(FILE *stream, struct devtabent *rec);
+extern int _rmdevtabattrs(char *, char **, char ***);
+extern int _rmdevtabrec(char *);
+
+extern int _adddgrptabrec(char *dgrp, char **members);
+extern int _putdgrptabrec(FILE *stream, struct dgrptabent *rec);
+extern int _rmdgrpmems(char *dgrp, char **mems, char ***notfounds);
+extern int _rmdgrptabrec(char *dgrp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DEVTAB_H */
diff --git a/usr/src/lib/libadm/inc/libadm.h b/usr/src/lib/libadm/inc/libadm.h
new file mode 100644
index 0000000000..68927cfb96
--- /dev/null
+++ b/usr/src/lib/libadm/inc/libadm.h
@@ -0,0 +1,128 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * This is where all the interfaces that are internal to libadm
+ * which do not have a better home live
+ */
+
+#ifndef _LIBADM_H
+#define _LIBADM_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <valtools.h>
+#include <stdio.h>
+#include <pkginfo.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int ckquit;
+extern int ckwidth;
+extern int ckindent;
+
+extern int _getvol(char *, char *, int, char *, char *);
+extern CKMENU *allocmenu(char *, int);
+extern int ckdate(char *, char *, char *, char *, char *, char *);
+extern int ckdate_err(char *, char *);
+extern int ckdate_hlp(char *, char *);
+extern int ckdate_val(char *, char *);
+extern int ckgid(char *, short, char *, char *, char *, char *);
+extern int ckgid_dsp(void);
+extern void ckgid_err(int, char *);
+extern void ckgid_hlp(int, char *);
+extern int ckgid_val(char *);
+extern int ckgrpfile(void);
+extern int ckint(long *, short, char *, char *, char *, char *);
+extern void ckint_err(short, char *);
+extern void ckint_hlp(short, char *);
+extern int ckint_val(char *, short);
+extern void ckitem_err(CKMENU *, char *);
+extern void ckitem_hlp(CKMENU *, char *);
+extern int ckitem(CKMENU *, char **, short, char *, char *, char *, char *);
+extern int ckkeywd(char *, char **, char *, char *, char *, char *);
+extern int ckpath(char *, int, char *, char *, char *, char *);
+extern void ckpath_err(int, char *, char *);
+extern void ckpath_hlp(int, char *);
+extern int ckpath_stx(int);
+extern int ckpath_val(char *, int);
+extern int ckpwdfile(void);
+extern int ckrange(long *, long, long, short, char *, char *, char *, char *);
+extern void ckrange_err(long, long, int, char *);
+extern void ckrange_hlp(long, long, int, char *);
+extern int ckrange_val(long, long, int, char *);
+extern int ckstr(char *, char **, int, char *, char *, char *, char *);
+extern void ckstr_err(char **, int, char *, char *);
+extern void ckstr_hlp(char **, int, char *);
+extern int ckstr_val(char **, int, char *);
+extern int cktime(char *, char *, char *, char *, char *, char *);
+extern int cktime_val(char *, char *);
+extern int cktime_err(char *, char *);
+extern int cktime_hlp(char *, char *);
+extern int ckuid(char *, short, char *, char *, char *, char *);
+extern int ckuid_dsp(void);
+extern void ckuid_err(short, char *);
+extern void ckuid_hlp(int, char *);
+extern int ckuid_val(char *);
+extern int ckyorn(char *, char *, char *, char *, char *);
+extern void ckyorn_err(char *);
+extern void ckyorn_hlp(char *);
+extern int ckyorn_val(char *);
+extern void doremovecmd(char *, int);
+extern int fpkginfo(struct pkginfo *, char *);
+extern char *fpkginst(char *, ...);
+extern char *fpkgparam(FILE *, char *);
+extern char *get_PKGADM(void);
+extern char *get_PKGLOC(void);
+extern char *get_PKGOLD(void);
+extern int getinput(char *);
+extern char *getfullblkname(char *);
+extern char *getfullrawname(char *);
+extern int pkginfofind(char *, char *, char *);
+extern FILE *pkginfopen(char *, char *);
+extern void puterror(FILE *, char *, char *);
+extern void puthelp(FILE *, char *, char *);
+extern void putprmpt(FILE *, char *, char **, char *);
+extern int puttext(FILE *, char *, int, int);
+extern void printmenu(CKMENU *);
+extern int setinvis(CKMENU *, char *);
+extern int setitem(CKMENU *, char *);
+extern void set_PKGADM(char *);
+extern void set_PKGLOC(char *);
+extern void set_PKGpaths(char *);
+extern void set_ABI_namelngth(void);
+extern int get_ABI_namelngth(void);
+extern void set_install_root(char *path);
+extern char *get_install_root(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBADM_H */
diff --git a/usr/src/lib/libadm/sparc/Makefile b/usr/src/lib/libadm/sparc/Makefile
new file mode 100644
index 0000000000..38a07e9239
--- /dev/null
+++ b/usr/src/lib/libadm/sparc/Makefile
@@ -0,0 +1,33 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 1997-2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libadm/sparc/Makefile
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/libadm/sparcv9/Makefile b/usr/src/lib/libadm/sparcv9/Makefile
new file mode 100644
index 0000000000..a4498e6166
--- /dev/null
+++ b/usr/src/lib/libadm/sparcv9/Makefile
@@ -0,0 +1,34 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 1998-2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libadm/sparcv9/Makefile
+#
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
diff --git a/usr/src/lib/libadm/spec/Makefile b/usr/src/lib/libadm/spec/Makefile
new file mode 100644
index 0000000000..4367acf239
--- /dev/null
+++ b/usr/src/lib/libadm/spec/Makefile
@@ -0,0 +1,29 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright (c) 1998-1999 by Sun Microsystems, Inc.
+# All rights reserved.
+#
+# lib/libadm/spec/Makefile
+
+include $(SRC)/lib/Makefile.spec.arch
diff --git a/usr/src/lib/libadm/spec/Makefile.targ b/usr/src/lib/libadm/spec/Makefile.targ
new file mode 100644
index 0000000000..021fec95d0
--- /dev/null
+++ b/usr/src/lib/libadm/spec/Makefile.targ
@@ -0,0 +1,34 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright (c) 1998-1999 by Sun Microsystems, Inc.
+# All rights reserved.
+#
+# lib/libadm/spec/Makefile.targ
+
+LIBRARY = libadm.a
+VERS = .1
+
+OBJECTS = adm.o
+
+SPECCPP =
diff --git a/usr/src/lib/libadm/spec/adm.spec b/usr/src/lib/libadm/spec/adm.spec
new file mode 100644
index 0000000000..0400628969
--- /dev/null
+++ b/usr/src/lib/libadm/spec/adm.spec
@@ -0,0 +1,746 @@
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# lib/libadm/spec/adm.spec
+
+# OA&M Device Managment
+function devattr
+declaration char *devattr( char *device, char *attribute)
+version SUNWprivate_1.1
+end
+
+# OA&M Device Managment
+function devfree
+declaration int devfree(int key, char *device)
+version SUNWprivate_1.1
+end
+
+# OA&M Device Managment
+function devreserv
+declaration char **devreserv(int key, char **rsvlist[])
+version SUNWprivate_1.1
+end
+
+# OA&M Device Managment
+function getdev
+declaration char **getdev(char **devices, char **criteria, int options)
+version SUNWprivate_1.1
+end
+
+# OA&M Device Managment
+function getdgrp
+declaration char **getdgrp(char **dgroups, char **criteria, int options)
+version SUNWprivate_1.1
+end
+
+# OA&M Device Managment
+function getvol
+declaration int getvol(char *device, char *label, int options, char *prompt)
+version SUNWprivate_1.1
+end
+
+# OA&M Device Managment
+function listdev
+declaration char **listdev(char *device)
+version SUNWprivate_1.1
+end
+
+# OA&M Device Managment
+function listdgrp
+declaration char **listdgrp(char *dgroup)
+version SUNWprivate_1.1
+end
+
+# OA&M Device Managment
+function reservdev
+include <sys/types.h>, <devmgmt.h>
+declaration struct reservdev **reservdev(void)
+version SUNWprivate_1.1
+end
+
+# VTOC reading/writing
+function read_vtoc
+include <sys/types.h>, <sys/vtoc.h>
+declaration int read_vtoc(int fd, struct vtoc *vtoc)
+version SUNW_0.7
+exception $return < 0
+end
+
+# VTOC reading/writing
+function write_vtoc
+include <sys/types.h>, <sys/vtoc.h>
+declaration int write_vtoc(int fd, struct vtoc *vtoc)
+version SUNW_0.7
+exception $return < 0
+end
+
+# Regular Expressions =============================================
+#
+# It was a mistake ever to have exported these symbols from libadm:
+# advance
+# circf
+# compile
+# loc1
+# loc2
+# locs
+# nbra
+# sed
+# step
+# They are now being redirected to libgen where they really belong,
+# except for 'circf' and 'sed', which do not exist in libgen and
+# are being retained as dummy variables in libadm.
+#
+# This corrects a mistake of the past. Never compound the mistake
+# by adding another 'arch' value to these symbols.
+
+function advance extends libgen/spec/gen.spec
+arch i386 sparc sparcv9
+version SUNWprivate_1.1
+filter libgen.so.1
+end
+
+data circf
+arch i386 sparc sparcv9
+version SUNW_0.7
+end
+
+function compile extends libgen/spec/gen.spec compile
+arch i386 sparc sparcv9
+version SUNWprivate_1.1
+filter libgen.so.1
+end
+
+data loc1
+arch i386 sparc
+version SUNW_0.7
+filter libgen.so.1 S0x4
+end
+
+data loc1
+arch sparcv9
+version SUNW_0.7
+filter libgen.so.1 S0x8
+end
+
+data loc2
+arch i386 sparc
+version SUNW_0.7
+filter libgen.so.1 S0x4
+end
+
+data loc2
+arch sparcv9
+version SUNW_0.7
+filter libgen.so.1 S0x8
+end
+
+data locs
+arch i386 sparc
+version SUNW_0.7
+filter libgen.so.1 S0x4
+end
+
+data locs
+arch sparcv9
+version SUNW_0.7
+filter libgen.so.1 S0x8
+end
+
+data nbra
+arch i386 sparc sparcv9
+version SUNW_0.7
+filter libgen.so.1 S0x4
+end
+
+data sed
+arch i386 sparc sparcv9
+version SUNW_0.7
+end
+
+function step extends libgen/spec/gen.spec
+arch i386 sparc sparcv9
+version SUNWprivate_1.1
+filter libgen.so.1
+end
+
+# End Regular Expressions =========================================
+
+# Packaging Stuff
+data pkgdir
+version SUNW_0.7
+end
+
+# Packaging Stuff
+function pkginfo
+include <pkginfo.h>, <valtools.h>
+declaration int pkginfo(struct pkginfo *info, char *pkginst, ...)
+version SUNWprivate_1.1
+end
+
+# Packaging Stuff
+function set_ABI_namelngth
+include <pkginfo.h>, <valtools.h>
+declaration void set_ABI_namelngth(void)
+version SUNWprivate_1.1
+end
+
+# Packaging Stuff
+function get_ABI_namelngth
+include <pkginfo.h>, <valtools.h>
+declaration int get_ABI_namelngth(void)
+version SUNWprivate_1.1
+end
+
+# Packaging Stuff
+function pkgnmchk
+include <pkginfo.h>, <valtools.h>
+declaration int pkgnmchk(char *pkg, char *spec, int presvr4flg)
+version SUNWprivate_1.1
+end
+
+# Packaging Stuff
+function pkgparam
+include <pkginfo.h>, <valtools.h>
+declaration char *pkgparam( char *pkg, char *param)
+version SUNWprivate_1.1
+end
+
+# cmd/oampkg/pkgadd
+function fpkginfo
+declaration int fpkginfo(struct pkginfo *info, char *pkginst)
+version SUNWprivate_1.1
+end
+
+# cmd/oampkg/pkgadd
+data ckquit
+version SUNWprivate_1.1
+end
+
+# cmd/oampkg/pkgadd
+function ckpath
+declaration int ckpath(char *pathval, int pflags, char *defstr, \
+ char *error, char *help, char *prompt)
+version SUNWprivate_1.1
+end
+
+# cmd/oampkg/pkgadd
+function ckyorn
+declaration int ckyorn(char *yorn, char *defstr, char *error, \
+ char *help, char *prompt)
+version SUNWprivate_1.1
+end
+
+# cmd/oampkg/pkgadd
+function _getvol
+declaration int _getvol(char *device, char *label, int options, \
+ char *prompt, char *norewind)
+version SUNWprivate_1.1
+end
+
+# cmd/oampkg/pkgadd
+function ckitem
+declaration int ckitem(CKMENU *menup, char *item[], short max, \
+ char *defstr, char *error, char *help, char *prompt)
+version SUNWprivate_1.1
+end
+
+# cmd/oampkg/pkgadd
+function fpkginst
+declaration char *fpkginst(char *pkg, ... )
+version SUNWprivate_1.1
+end
+
+# cmd/oampkg/pkgadd
+function get_install_root
+declaration char *get_install_root(void)
+version SUNWprivate_1.1
+end
+
+# cmd/oampkg/pkgadd
+function set_install_root
+declaration void set_install_root(char *path)
+version SUNWprivate_1.1
+end
+
+# cmd/oampkg/pkgadd
+function get_PKGADM
+declaration char *get_PKGADM(void)
+version SUNWprivate_1.1
+end
+
+# cmd/oampkg/pkgadd
+function set_PKGpaths
+declaration void set_PKGpaths(char *path)
+version SUNWprivate_1.1
+end
+
+# cmd/oampkg/pkgadd
+function fpkgparam
+declaration char *fpkgparam(FILE *fp, char *param)
+version SUNWprivate_1.1
+end
+
+# cmd/oampkg/pkgadd
+function allocmenu
+declaration CKMENU *allocmenu(char *label, int attr)
+version SUNWprivate_1.1
+end
+
+# cmd/oampkg/pkgadd
+function setinvis
+declaration int setinvis(CKMENU *menup, char *choice)
+version SUNWprivate_1.1
+end
+
+# cmd/oampkg/pkgadd
+function puttext
+declaration int puttext(FILE *fp, char *str, int lmarg, int rmarg)
+version SUNWprivate_1.1
+end
+
+# cmd/oampkg/pkgadd
+function setitem
+declaration int setitem(CKMENU *menup, char *choice)
+version SUNWprivate_1.1
+end
+
+# cmd/oampkg/pkginstall
+function get_PKGOLD
+declaration char * get_PKGOLD(void)
+version SUNWprivate_1.1
+end
+
+# cmd/oampkg/pkginstall
+function get_PKGLOC
+declaration char * get_PKGLOC(void)
+version SUNWprivate_1.1
+end
+
+function set_PKGADM
+declaration void set_PKGADM(char *newpath)
+version SUNWprivate_1.1
+end
+
+function set_PKGLOC
+declaration void set_PKGLOC(char *newpath)
+version SUNWprivate_1.1
+end
+
+function getinput
+declaration int getinput(char *s)
+version SUNWprivate_1.1
+end
+
+# cmd/oampkg/pkginstall
+function printmenu
+declaration void printmenu(CKMENU *menup)
+version SUNWprivate_1.1
+end
+
+# cmd/oampkg/pkgrm
+function ckstr
+declaration int ckstr(char *strval, char *regexp[], int length, \
+ char *defstr, char *error, char *help, char *prompt)
+version SUNWprivate_1.1
+end
+
+# cmd/oampkg/pkgparam
+data pkgfile
+version SUNWprivate_1.1
+end
+
+# cmd/volmgt/util
+function getfullrawname
+declaration char * getfullrawname(char *cp)
+version SUNWprivate_1.1
+end
+
+# cmd/volmgt/util
+function getfullblkname
+declaration char * getfullblkname(char *cp)
+version SUNWprivate_1.1
+end
+
+# cmd/devmgt/de
+function _devtabpath
+declaration char * _devtabpath(void)
+version SUNWprivate_1.1
+end
+
+# cmd/devmgt/de
+function _opendevtab
+declaration int _opendevtab(char *mode)
+version SUNWprivate_1.1
+end
+
+# cmd/devmgt/de
+function _rsvtabpath
+declaration char * _rsvtabpath(void)
+version SUNWprivate_1.1
+end
+
+# cmd/devmgt/ge
+data ckwidth
+version SUNWprivate_1.1
+end
+
+# cmd/devmgt/putdgrp
+function _dgrptabpath
+declaration char * _dgrptabpath(void)
+version SUNWprivate_1.1
+end
+
+# cmd/devmgt/putdgrp
+function _rmdgrpmems
+declaration int _rmdgrpmems( char *dgrp, char **mems, char ***notfounds)
+version SUNWprivate_1.1
+end
+
+# cmd/devmgt/putdgrp
+function _rmdgrptabrec
+declaration int _rmdgrptabrec(char *dgrp)
+version SUNWprivate_1.1
+end
+
+# cmd/devmgt/putdgrp
+function _adddgrptabrec
+declaration int _adddgrptabrec( char *dgrp, char **members)
+version SUNWprivate_1.1
+end
+
+# cmd/devmgmt/libstrgrp
+function _opendgrptab
+declaration int _opendgrptab(char *mode)
+version SUNWprivate_1.1
+end
+
+# cmd/devmgt/putdev
+function _rmdevtabrec
+declaration int _rmdevtabrec(char *device)
+version SUNWprivate_1.1
+end
+
+# cmd/devmgt/putdev
+function _adddevtabrec
+declaration int _adddevtabrec( char *alias, char **attrval)
+version SUNWprivate_1.1
+end
+
+# cmd/devmgt/putdev
+function _rmdevtabattrs
+declaration int _rmdevtabattrs( char *device, char **attributes, char ***notfounds)
+version SUNWprivate_1.1
+end
+
+# cmd/devmgt/putdev
+function _validalias
+declaration int _validalias(char *alias)
+version SUNWprivate_1.1
+end
+
+# cmd/devmgt/putdev
+function _moddevtabrec
+declaration int _moddevtabrec( char *device, char **attrval)
+version SUNWprivate_1.1
+end
+
+# cmd/devmgmt/mkdtab
+function _enddevtab
+declaration void _enddevtab(void)
+version SUNWprivate_1.1
+end
+
+# cmd/valtools
+function ckint
+declaration int ckint(long *intval, short base, char *defstr, \
+ char *error, char *help, char *prompt)
+version SUNWprivate_1.1
+end
+
+# cmd/valtools
+function ckint_hlp
+declaration void ckint_hlp(short base, char *help)
+version SUNWprivate_1.1
+end
+
+# cmd/valtools
+function ckint_val
+declaration int ckint_val(char *value, short base)
+version SUNWprivate_1.1
+end
+
+# cmd/valtools
+data ckindent
+version SUNWprivate_1.1
+end
+
+# cmd/valtools
+function ckint_err
+declaration void ckint_err(short base, char *error)
+version SUNWprivate_1.1
+end
+
+# cmd/valtools
+function ckitem_hlp
+declaration void ckitem_hlp(CKMENU *menup, char *help)
+version SUNWprivate_1.1
+end
+
+# cmd/valtools
+function ckitem_err
+declaration void ckitem_err(CKMENU *menup, char *error)
+version SUNWprivate_1.1
+end
+
+# cmd/valtools
+function ckpath_stx
+declaration int ckpath_stx(int pflags)
+version SUNWprivate_1.1
+end
+
+# cmd/valtools
+function ckpath_hlp
+declaration void ckpath_hlp(int pflags, char *help)
+version SUNWprivate_1.1
+end
+
+# cmd/valtools
+function ckpath_val
+declaration int ckpath_val(char *path, int pflags)
+version SUNWprivate_1.1
+end
+
+# cmd/valtools
+function ckpath_err
+declaration void ckpath_err(int pflags, char *error, char *input)
+version SUNWprivate_1.1
+end
+
+# cmd/valtools
+function ckrange_hlp
+declaration void ckrange_hlp(long lower, long upper, int base, char *help)
+version SUNWprivate_1.1
+end
+# cmd/valtools
+
+function ckrange_err
+declaration void ckrange_err(long lower, long upper, int base, char *error)
+version SUNWprivate_1.1
+end
+
+# cmd/valtools
+function ckrange_val
+declaration int ckrange_val(long lower, long upper, int base, char *input)
+version SUNWprivate_1.1
+end
+
+# cmd/valtools
+function ckrange
+declaration int ckrange(long *rngval, long lower, long upper, \
+ short base, char *defstr, char *error, \
+ char *help, char *prompt)
+# cmd/valtools
+version SUNWprivate_1.1
+end
+
+# cmd/valtools
+function ckstr_hlp
+declaration void ckstr_hlp(char *regexp[], int length, char *help)
+version SUNWprivate_1.1
+end
+
+# cmd/valtools
+function ckstr_val
+declaration int ckstr_val(char *regexp[], int length, char *input)
+version SUNWprivate_1.1
+end
+
+# cmd/valtools
+function ckstr_err
+declaration void ckstr_err(char *regexp[], int length, \
+ char *error, char *input)
+version SUNWprivate_1.1
+end
+
+# cmd/valtools
+function ckyorn_hlp
+declaration void ckyorn_hlp(char *help)
+version SUNWprivate_1.1
+end
+
+# cmd/valtools
+function ckyorn_val
+declaration int ckyorn_val(char *str)
+version SUNWprivate_1.1
+end
+
+# cmd/valtools
+function ckyorn_err
+declaration void ckyorn_err(char *error)
+version SUNWprivate_1.1
+end
+
+# cmd/valtools
+function ckkeywd
+declaration int ckkeywd(char *strval, char *keyword[], \
+ char *defstr, char *error, char *help, char *prompt)
+version SUNWprivate_1.1
+end
+
+# cmd/valtools
+function ckdate_hlp
+declaration int ckdate_hlp(char *fmt, char *hlp)
+version SUNWprivate_1.1
+end
+
+# cmd/valtools
+function ckdate_val
+declaration int ckdate_val(char *fmt, char *input)
+version SUNWprivate_1.1
+end
+
+# cmd/valtools
+function ckdate
+declaration int ckdate(char *date, char *fmt, char *defstr, \
+ char *error, char *help, char *prompt)
+version SUNWprivate_1.1
+end
+
+# cmd/valtools
+function ckdate_err
+declaration int ckdate_err(char *fmt, char *error)
+version SUNWprivate_1.1
+end
+
+# cmd/valtools
+function cktime_hlp
+declaration int cktime_hlp(char *fmt, char *help)
+version SUNWprivate_1.1
+end
+
+# cmd/valtools
+function cktime_val
+declaration int cktime_val(char *fmt, char *input)
+version SUNWprivate_1.1
+end
+
+# cmd/valtools
+function cktime_err
+declaration int cktime_err(char *fmt, char *error)
+version SUNWprivate_1.1
+end
+
+# cmd/valtools
+function cktime
+declaration int cktime(char *tod, char *fmt, char *defstr, \
+ char *error, char *help, char *prompt)
+version SUNWprivate_1.1
+end
+
+# cmd/valtools
+function ckuid
+declaration int ckuid(char *uid, short disp, char *defstr, \
+ char *error, char *help, char *prompt)
+version SUNWprivate_1.1
+end
+
+# cmd/valtools
+function ckuid_hlp
+declaration void ckuid_hlp(int disp, char *help)
+version SUNWprivate_1.1
+end
+
+# cmd/valtools
+function ckuid_dsp
+declaration int ckuid_dsp(void)
+version SUNWprivate_1.1
+end
+
+# cmd/valtools
+function ckuid_val
+declaration int ckuid_val(char *usrnm)
+version SUNWprivate_1.1
+end
+
+# cmd/valtools
+function ckuid_err
+declaration void ckuid_err(short disp, char *error)
+version SUNWprivate_1.1
+end
+
+# cmd/valtools
+function ckgid_err
+declaration void ckgid_err(int disp, char *error)
+version SUNWprivate_1.1
+end
+
+# cmd/valtools
+function ckgid
+declaration int ckgid(char *gid, short disp, char *defstr, \
+ char *error, char *help, char *prompt)
+version SUNWprivate_1.1
+end
+
+# cmd/valtools
+function ckgid_hlp
+declaration void ckgid_hlp(int disp, char *help)
+version SUNWprivate_1.1
+end
+
+# cmd/valtools
+function ckgid_dsp
+declaration int ckgid_dsp(void)
+version SUNWprivate_1.1
+end
+
+# cmd/valtools
+function ckgid_val
+declaration int ckgid_val(char *grpnm)
+version SUNWprivate_1.1
+end
+
+# required by pkginfo
+function pkginfofind
+declaration int pkginfofind(char *path, char *pkg_dir, char *pkginst)
+version SUNWprivate_1.1
+end
+
+function puterror
+declaration void puterror(FILE *fp, char *defmesg, char *error)
+version SUNWprivate_1.1
+end
+
+function puthelp
+declaration void puthelp(FILE *fp, char *defmesg, char *help)
+version SUNWprivate_1.1
+end
+
+function putprmpt
+declaration void putprmpt(FILE *fp, char *prompt, \
+ char *choices[], char *defstr)
+version SUNWprivate_1.1
+end
+
diff --git a/usr/src/lib/libadm/spec/amd64/Makefile b/usr/src/lib/libadm/spec/amd64/Makefile
new file mode 100644
index 0000000000..453c0ea671
--- /dev/null
+++ b/usr/src/lib/libadm/spec/amd64/Makefile
@@ -0,0 +1,44 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+.KEEP_STATE:
+
+include ../Makefile.targ
+
+# Add arch specific objects here
+OBJECTS +=
+
+include $(SRC)/lib/Makefile.lib
+include $(SRC)/lib/Makefile.lib.64
+
+# Uncomment the following if the linker complains
+#amd64_C_PICFLAGS = -K PIC
+
+include $(SRC)/lib/Makefile.spec
+
+install: $(ROOTABILIB64)
diff --git a/usr/src/lib/libadm/spec/i386/Makefile b/usr/src/lib/libadm/spec/i386/Makefile
new file mode 100644
index 0000000000..c7d5274776
--- /dev/null
+++ b/usr/src/lib/libadm/spec/i386/Makefile
@@ -0,0 +1,44 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright (c) 1998-1999 by Sun Microsystems, Inc.
+# All rights reserved.
+#
+# lib/libadm/spec/i386/Makefile
+
+.KEEP_STATE:
+
+include ../Makefile.targ
+
+# Add arch specific objects here
+OBJECTS +=
+
+include $(SRC)/lib/Makefile.lib
+
+# Uncomment the following if the linker complains
+#i386_C_PICFLAGS = -K PIC
+
+include $(SRC)/lib/Makefile.spec
+
+install: $(ROOTABILIB)
diff --git a/usr/src/lib/libadm/spec/sparc/Makefile b/usr/src/lib/libadm/spec/sparc/Makefile
new file mode 100644
index 0000000000..cd4364e37d
--- /dev/null
+++ b/usr/src/lib/libadm/spec/sparc/Makefile
@@ -0,0 +1,44 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright (c) 1998-1999 by Sun Microsystems, Inc.
+# All rights reserved.
+#
+# lib/libadm/spec/sparc/Makefile
+
+.KEEP_STATE:
+
+include ../Makefile.targ
+
+# Add arch specific objects here
+OBJECTS +=
+
+include $(SRC)/lib/Makefile.lib
+
+# Uncomment the following if the linker complains
+#sparc_C_PICFLAGS = -K PIC
+
+include $(SRC)/lib/Makefile.spec
+
+install: $(ROOTABILIB)
diff --git a/usr/src/lib/libadm/spec/sparcv9/Makefile b/usr/src/lib/libadm/spec/sparcv9/Makefile
new file mode 100644
index 0000000000..1a73918201
--- /dev/null
+++ b/usr/src/lib/libadm/spec/sparcv9/Makefile
@@ -0,0 +1,45 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright (c) 1998-1999 by Sun Microsystems, Inc.
+# All rights reserved.
+#
+# lib/libadm/spec/sparcv9/Makefile
+
+.KEEP_STATE:
+
+include ../Makefile.targ
+
+# Add arch specific objects here
+OBJECTS +=
+
+include $(SRC)/lib/Makefile.lib
+include $(SRC)/lib/Makefile.lib.64
+
+# Uncomment the following if the linker complains
+sparcv9_C_PICFLAGS = -K PIC
+
+include $(SRC)/lib/Makefile.spec
+
+install: $(ROOTABILIB64)
diff --git a/usr/src/lib/libadm/spec/versions b/usr/src/lib/libadm/spec/versions
new file mode 100644
index 0000000000..2fed5f1c60
--- /dev/null
+++ b/usr/src/lib/libadm/spec/versions
@@ -0,0 +1,52 @@
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Note: Even though the SUNW_1.1 version now contains no symbols
+# beyond what was present at Solaris 2.3, the SUNW_1.1 version MUST be
+# present. This is because applications built on 2.6 Beta
+# (when it did contain symbols explicitly) may depend on it.
+#
+
+sparc {
+ SUNW_1.1: {SUNW_0.7};
+ SUNW_0.7;
+ SUNWprivate_1.1;
+}
+sparcv9 {
+ SUNW_1.1: {SUNW_0.7};
+ SUNW_0.7;
+ SUNWprivate_1.1;
+}
+i386 {
+ SUNW_1.1: {SUNW_0.7};
+ SUNW_0.7;
+ SUNWprivate_1.1;
+}
+amd64 {
+ SUNW_1.1: {SUNW_0.7};
+ SUNW_0.7;
+ SUNWprivate_1.1;
+}