diff options
Diffstat (limited to 'usr/src/lib/libadm')
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", <rl); + 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", <rl); + } + } 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; +} |