/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (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) 1989, 2010, Oracle and/or its affiliates. All rights reserved. */ /*LINTLIBRARY*/ #include #include #include #include #include #include #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 10 #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, size_t sz) { if ((fmt == NULL) || strcmp(fmt, "%D") == 0) fmt = "%m/%d/%y"; (void) snprintf(msg, sz, "%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; int begin = -1; int iday = 0; int idaymax = 2; if (*string == BLANK) { string++; idaymax--; } copy = string; while (isdigit((unsigned char)*copy) && (iday < idaymax)) { copy++; iday++; } 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, MSGSIZ); 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, MSGSIZ); 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 == '\0') && ((input != NULL) && *input != '\0')) { 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, MSGSIZ); (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); } /* * 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*/ #include #include #include #include #include #include "libadm.h" #include #include #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); } /* * 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*/ #include #include #include #include #include #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); } /* * 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. */ /* * Copyright 2010 Nexenta Systems, Inc. All rights reserved. */ /*LINTLIBRARY*/ #include #include #include #include "valtools.h" #include #include #include #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); /* LINTED E_SEC_PRINTF_VAR_FMT */ (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", ""); /* LINTED E_SEC_PRINTF_VAR_FMT */ (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 for more choices, 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 end[MAX_INPUT]; *end = '\0'; if (defstr) { (void) snprintf(end, MAX_INPUT, "(default: %s) ", defstr); } if (ckquit) { (void) strlcat(end, "[?,??,q]", MAX_INPUT); } else { (void) strlcat(end, "[?,??]", MAX_INPUT); } 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); } /* * 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*/ #include #include #include #include #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); } /* * 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. */ /* * Copyright 2010 Nexenta Systems, Inc. All rights reserved. */ /*LINTLIBRARY*/ #include #include #include #include #include #include #include "valtools.h" #include #include #include #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) snprintf(buffer, sizeof (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) snprintf(buffer, sizeof (buffer), "Pathname %s.", errstr); puterror(stderr, buffer, error); goto start; } (void) strcpy(pathval, input); free(defhlp); return (0); } /* * 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*/ #include #include #include #include #include #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); } /* * 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. */ #include #include #include #include #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 embedded, \ 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 embedded, 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)) { /* LINTED E_SEC_PRINTF_VAR_FMT */ (void) snprintf(temp, sizeof (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)) { /* LINTED E_SEC_PRINTF_VAR_FMT */ (void) snprintf(errbuf, sizeof (errbuf), errstr, length); puterror(stderr, errbuf, error); goto start; } (void) strcpy(strval, input); return (0); } /* * 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. */ /* * Copyright 2010 Nexenta Systems, Inc. All rights reserved. */ /*LINTLIBRARY*/ #include #include #include #include #include #include #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, size_t sz) { if (fmt == NULL) fmt = DEFAULT; (void) snprintf(msg, sz, "%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, sizeof (defmesg)); 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, sizeof (defmesg)); 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, sizeof (defmesg)); 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); } /* * 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*/ #include #include #include #include #include #include #include #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); } /* * 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. */ /*LINTLIBRARY*/ #include #include #include #include #include #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); } /* * 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: * Standard I/O definitions */ #include FILE *oam_devtab = (FILE *) NULL; FILE *oam_dgroup = (FILE *) NULL; /* * 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*/ /* * devattr.c * * Contents: * devattr() Get the value of a attribute for a specific device */ /* * Header files needed * System Data Types * Standard I/O Definitions * Error-value definitions * String function and constant definitions * Device table definitions available to the world * "devtab.h" Local device table definitions */ #include #include #include #include #include #include #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 . If it finds a record corresponding to that * device (see below for a definition of that correspondence), it * extracts the value of the field 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 for the 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); } /* * 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*/ /* * 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: * System data types * Error definitions (including "errno") * String handling definitions * File control definitions * Unix standard value definitions * Global Device Management definitions * "devtab.h" Local Device Management definitions */ #include #include #include #include #include #include #include #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 * * 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". 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); } /* * 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 */ /*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 * * System macro definitions * System data types * Device Macros * System Symbolic Constants * Standard I/O definitions * String handling definitions * Character types and macros * Error codes * File status information * Global Device Management definitions * "devtab.h" Local Device Management definitions */ #include #include #ifndef SUNOS41 #include #endif #include #include #include #include #include #include #include #include "devtab.h" #include /* * 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 , or, if 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 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 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 is a valid alias. Returns TRUE if it is * a valid alias, FALSE otherwise. * * Arguments: * alias Value to check out * * Returns: int * TRUE if is a valid alias, FALSE otherwise. */ int _validalias(char *alias) /* Alias to validate */ { /* Automatic data */ char *p; /* Temp pointer */ size_t len; /* Length of */ 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 . * * The 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, */ 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 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 . If fails, invalid device */ if (stat64(device, &devstatbuf) != 0) errno = ENODEV; else { /* * If 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 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 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 succeeded */ } /* End case handling pathname not explicitly in device table */ } /* End case handling as a fully-qualified pathname */ /* * Otherwise the device is an alias. * Search the table for a record that has as the "alias" attribute * the value . */ 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); } /* * 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. */ /*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 * System data types * Standard UNIX(r) definitions * Standard I/O Definitions * String handling definitions * Character types and macros * Errorcode definitions * File status information * Global Device Management definitions * "devtab.h" Local device table definitions */ #include #include #include #include #include #include #include #include #include "devtab.h" #include /* * 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 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 . */ 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 . * * 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); } /* * 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. */ /*LINTLIBRARY*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #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); } /* * 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*/ /* * getdev.c * * Contents: * getdev() List devices that match certain criteria. */ /* * Header files referenced: * System Data Types * Error handling * File controlling * Character types * String handling * Global device-management def'ns * "devtab.h" Local device-management dev'ns */ #include #include #include #include #include #include #include "devtab.h" #include /* * 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 * 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 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 . * * 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 is satisfied by * comparing the value with . 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); } /* * 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*/ /* * getdgrp.c * * Contains the following global functions: * getdgrp() Get the device groups that meet certain criteria. */ /* * Header Files Referenced * Data Types * Standard I/O definitions * Character-string definitions * Definitions for accessing device table files * "devtab.h" Local definitions for device tables */ #include #include #include #include #include #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 for any of the devices listed in the list of devices * . It returns TRUE if at least one device in is * found in , 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 is a member of the device * group , 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 . */ /* 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); } } /* * 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*/ #include #include #include #include #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); } /* * 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*/ #include #include #include #include #include "libadm.h" #include #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) snprintf(buffer, sizeof (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) { /* LINTED E_SEC_SPRINTF_UNBOUNDED_COPY */ (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) snprintf(buffer, sizeof (buffer), "/etc/labelit %s \"%s\" \"%s\" -n 1>&2", cdevice, fsname, volname); } else { (void) snprintf(buffer, sizeof (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) /* LINTED E_SEC_SPRINTF_UNBOUNDED_COPY */ (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) strlcpy(prmpt, prompt, sizeof (prmpt)); 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 { /* LINTED E_SEC_SPRINTF_UNBOUNDED_COPY */ (void) sprintf(prmpt, "Insert a %s into %s.", voltxt, pname); if (label && (options & DM_ELABEL)) { (void) strcat(prmpt, " The following external label "); /* LINTED E_SEC_SPRINTF_UNBOUNDED_COPY */ (void) sprintf(prmpt+strlen(prmpt), " should appear on the %s:\\n\\t%s", voltxt, label); } if (label && !(options & DM_ELABEL)) { /* LINTED E_SEC_SPRINTF_UNBOUNDED_COPY */ (void) sprintf(prmpt+strlen(prmpt), " The %s should be internally labeled as follows:", voltxt); /* LINTED E_SEC_SPRINTF_UNBOUNDED_COPY */ (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) { /* LINTED E_SEC_SPRINTF_UNBOUNDED_COPY */ pt += sprintf(pt, FORMFS_MSG, voltxt); keyword[n++] = "f"; } else if (fmtcmd && *fmtcmd) { /* LINTED E_SEC_SPRINTF_UNBOUNDED_COPY */ pt += sprintf(pt, FORMAT_MSG, voltxt); keyword[n++] = "f"; } if (mkfscmd && *mkfscmd) { /* LINTED E_SEC_SPRINTF_UNBOUNDED_COPY */ pt += sprintf(pt, MAKEFS_MSG, voltxt); keyword[n++] = "m"; } } else if (options & DM_FORMAT) { if (fmtcmd && *fmtcmd) { /* LINTED E_SEC_SPRINTF_UNBOUNDED_COPY */ pt += sprintf(pt, FORMAT_MSG, voltxt); keyword[n++] = "f"; } } if (options & DM_WLABEL) { /* LINTED E_SEC_SPRINTF_UNBOUNDED_COPY */ 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) { /* LINTED E_SEC_SPRINTF_UNBOUNDED_COPY */ pt += sprintf(pt, EJECT_MSG, voltxt); keyword[n++] = "e"; } else { /* LINTED E_SEC_SPRINTF_UNBOUNDED_COPY */ 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) snprintf(buffer, sizeof (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) snprintf(buffer, sizeof (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) snprintf(buffer, sizeof (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); } /* * 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*/ /* * listdev.c * * Contains: * listdev() List attributes defined for a device */ /* * Header files needed: * System Data Types * Standard string definitions * Device management definitions * "devtab.h" Local device table definitions */ #include #include #include #include "devtab.h" #include /* * 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 . * * 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 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); } /* * 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*/ /* * listdgrp.c * * Contents: * listdgrp() List devices that belong to a device group. */ /* * Header files referenced: * System Data Types * UNIX and C error definitions * String handling definitions * Device management definitions * "devtab.h" Local device table definitions */ #include #include #include #include #include #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); } # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (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) 2006, 2010, Oracle and/or its affiliates. All rights reserved. # # # MAPFILE HEADER START # # WARNING: STOP NOW. DO NOT MODIFY THIS FILE. # Object versioning must comply with the rules detailed in # # usr/src/lib/README.mapfiles # # You should not be making modifications here until you've read the most current # copy of that file. If you need help, contact a gatekeeper for guidance. # # MAPFILE HEADER END # $mapfile_version 2 SYMBOL_VERSION SUNW_1.2 { global: read_extvtoc; write_extvtoc; } SUNW_1.1; # Due to mistakes made early in the history of this library, there are # no SUNW_1.1 symbols, but the version is now kept as a placeholder. # Don't add any symbols to this version. SYMBOL_VERSION SUNW_1.1 { global: SUNW_1.1; } SUNW_0.7; SYMBOL_VERSION SUNW_0.7 { global: pkgdir { ASSERT = { TYPE = OBJECT; SIZE = addrsize; }; }; read_vtoc; write_vtoc; }; SYMBOL_VERSION SUNWprivate_1.1 { global: _adddevtabrec; _adddgrptabrec; allocmenu; ckdate; ckdate_err; ckdate_hlp; ckdate_val; ckgid; ckgid_dsp; ckgid_err; ckgid_hlp; ckgid_val; ckindent { ASSERT = { TYPE = OBJECT; SIZE = 4; }; }; ckint; ckint_err; ckint_hlp; ckint_val; ckitem; ckitem_err; ckitem_hlp; ckkeywd; ckpath; ckpath_err; ckpath_hlp; ckpath_stx; ckpath_val; ckquit { ASSERT = { TYPE = OBJECT; SIZE = 4; }; }; ckrange; ckrange_err; ckrange_hlp; ckrange_val; ckstr; ckstr_err; ckstr_hlp; ckstr_val; cktime; cktime_err; cktime_hlp; cktime_val; ckuid; ckuid_dsp; ckuid_err; ckuid_hlp; ckuid_val; ckwidth { ASSERT = { TYPE = OBJECT; SIZE = 4; }; }; ckyorn; ckyorn_err; ckyorn_hlp; ckyorn_val; devattr; devfree; devreserv; _devtabpath; _dgrptabpath; _enddevtab; fpkginfo; fpkginst; fpkgparam; get_ABI_namelngth; getdev; getdgrp; getfullblkname; getfullrawname; getinput; get_install_root; get_PKGADM; get_PKGLOC; getvol; _getvol; listdev; listdgrp; _moddevtabrec; _opendevtab; _opendgrptab; pkgfile { ASSERT = { TYPE = OBJECT; SIZE = addrsize; }; }; pkginfo; pkginfofind; pkgnmchk; pkgparam; printmenu; puterror; puthelp; putprmpt; puttext; reservdev; _rmdevtabattrs; _rmdevtabrec; _rmdgrpmems; _rmdgrptabrec; _rsvtabpath; set_ABI_namelngth; set_install_root; setinvis; setitem; set_PKGADM; set_PKGLOC; set_PKGpaths; _validalias; local: *; }; $if _sparc || (_x86 && _ELF32) # The following applies to sparc (32/64-bit), and 32-bit x86: # # It was a mistake ever to have exported these symbols from libadm. # 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. SYMBOL_VERSION SUNW_0.7 { global: circf { ASSERT = { TYPE = OBJECT; SIZE = 4; }; }; sed { ASSERT = { TYPE = OBJECT; SIZE = 4; }; }; nbra { TYPE = DATA; FILTER = libgen.so.1; SIZE = addrsize; }; loc1 { TYPE = DATA; FILTER = libgen.so.1; SIZE = addrsize; }; loc2 { TYPE = DATA; FILTER = libgen.so.1; SIZE = addrsize; }; locs { TYPE = DATA; FILTER = libgen.so.1; SIZE = addrsize; }; }; SYMBOL_VERSION SUNWprivate_1.1 { global: advance { TYPE = FUNCTION; FILTER = libgen.so.1; }; compile { TYPE = FUNCTION; FILTER = libgen.so.1; }; step { TYPE = FUNCTION; FILTER = libgen.so.1; }; }; $endif /* * 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. */ /*LINTLIBRARY*/ /* 5-20-92 added newroot functions */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "libadm.h" static void initpkg(struct pkginfo *); static int rdconfig(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) { 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) snprintf(temp, sizeof (temp), "%s/%s/!I-Lock!", pkgdir, pkginst); if (access(temp, 0) == 0) info->status = PI_PARTIAL; else { (void) snprintf(temp, sizeof (temp), "%s/%s/!R-Lock!", pkgdir, pkginst); if (access(temp, 0) == 0) info->status = PI_PARTIAL; } } info->pkginst = strdup(pkginst); 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 *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; } 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); } errno = ESRCH; /* close any file we might have open */ (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) snprintf(temp, sizeof (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) snprintf(file, sizeof (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); } /* * 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. */ /*LINTLIBRARY*/ #include #include #include #include #include "libadm.h" static char *rsvrd[] = { "all", "install", "new", NULL }; #define NMBRK ".*" #define WILD1 ".*" #define WILD2 "*" #define ABI_NAMELNGTH 9 #define NON_ABI_NAMELNGTH 32 static int abi_namelngth = 0; static int valname(char *pkg, int wild) { 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 used to do this * first since we needed to look for SVR3 ".name" * before we validate the package abbreviation */ if (pt = strpbrk(pkg, NMBRK)) { 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 (!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) { _NOTE(ARGUNUSED(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))) 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)) 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)) if ((pkg[0] == '\0') || (pkg[0] == '.')) return (0); return (1); } void set_ABI_namelngth(void) { abi_namelngth = 1; } int get_ABI_namelngth(void) { return (abi_namelngth); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (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 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright 2010 Nexenta Systems, Inc. All rights reserved. */ /*LINTLIBRARY*/ /* 5-20-92 newroot support added */ #include #include #include #include #include #include #include #include #include #include #include #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_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 to .save.. If the * pkgadd fails it will be renamed back to . 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) { int len = 0; /* Construct the temporary pkginfo file name. */ len = snprintf(path, PATH_MAX, "%s/.save.%s/pkginfo", pkg_dir, pkginst); if (len > PATH_MAX) return (0); if (access(path, 0)) { /* * This isn't a temporary directory, so we look for a * regular one. */ len = snprintf(path, PATH_MAX, "%s/%s/pkginfo", pkg_dir, pkginst); if (len > PATH_MAX) return (0); 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; boolean_t check_end_quote = B_FALSE; boolean_t begline, quoted, escape; int idx = 0; 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 = 0; quoted = escape = B_FALSE; begline = B_TRUE; /* Value's line begins */ /* Now read the parameter value. */ while ((c = getc(fp)) != EOF) { ch = (char)c; if (begline && ((ch == ' ') || (ch == '\t'))) continue; /* Ignore leading white space */ /* * Take last end quote 'verbatim' if anything * other than space, newline and escape. * Example: * PARAM1="zonename="test-zone"" * Here in this example the letter 't' inside * the value is followed by '"', this makes * the previous end quote candidate '"', * a part of value and the end quote * disqualfies. Reset check_end_quote. * PARAM2="value"<== newline here * PARAM3="value"\ * "continued"<== newline here. * Check for end quote continues. */ if (ch != NEWLINE && ch != ' ' && ch != ESCAPE && ch != '\t' && check_end_quote) check_end_quote = B_FALSE; if (ch == NEWLINE) { if (!escape) { /* * The end quote candidate qualifies. * Eat any trailing spaces. */ if (check_end_quote) { copy -= n - idx; n = idx; check_end_quote = B_FALSE; quoted = B_FALSE; } break; /* End of entry */ } /* * The end quote if exists, doesn't qualify. * Eat end quote and trailing spaces if any. * Value spans to next line. */ if (check_end_quote) { copy -= n - idx; n = idx; check_end_quote = B_FALSE; } else if (copy) { copy--; /* Eat previous esc */ n--; } escape = B_FALSE; begline = B_TRUE; /* New input line */ continue; } else { if (!escape && strchr(qset, ch)) { /* Handle quotes */ if (begline) { /* Starting quote */ quoted = B_TRUE; begline = B_FALSE; continue; } else if (quoted) { /* * This is the candidate * for end quote. Check * to see it qualifies. */ check_end_quote = B_TRUE; idx = n; } } if (ch == ESCAPE) escape = B_TRUE; else if (escape) escape = B_FALSE; if (copy) *copy++ = ch; begline = B_FALSE; } 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") == 0 || strcmp(param, "CATEGORY") == 0) { /* 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) snprintf(Adm_pkgloc, sizeof (Adm_pkgloc), "%s%s", path, PKGLOC); (void) snprintf(Adm_pkgadm, sizeof (Adm_pkgadm), "%s%s", path, PKGADM); set_install_root(path); } else { (void) snprintf(Adm_pkgloc, sizeof (Adm_pkgloc), "%s", PKGLOC); (void) snprintf(Adm_pkgadm, sizeof (Adm_pkgadm), "%s", PKGADM); } canonize_name(Adm_pkgloc); canonize_name(Adm_pkgadm); pkgdir = Adm_pkgloc; } char * get_PKGLOC(void) { if (Adm_pkgloc[0] == '\0') return (PKGLOC); else return (Adm_pkgloc); } char * get_PKGADM(void) { if (Adm_pkgadm[0] == '\0') 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); } /* * 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 */ /* * Copyright 2010 Nexenta Systems, Inc. All rights reserved. */ /* 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 * UNIX(r) Data Types * * Standard I/O definitions * Definitions for file control * Error handling definitions * String Handling Definitions * Device Management Definitions * Get UNIX(r) Standard Definitions * "devtab.h" Local Device Management Definitions */ #include #include #include #include #include #include #include #include #include #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) */ #define TDTABNM "%sdevtab.%6.6d" /* * 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 . * * 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 (asprintf(&buf, TDTABNM, dirname, getpid()) >= 0) { /* * 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. */ 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 using the information in the attribute list . * The 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 to the current position of the standard I/O * 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 and will have the attributes described in * the list referenced by . * * 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 , is the address of * the first char * in the list of char * pointing to the attributes * to remove from the device, and 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 . * * 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 's entry */ _freedevtabent(modent); } else { /* _getdevrec(device) failed */ nobaderr = FALSE; *notfounds = NULL; } /* Unlock the device table */ (void) unlkdevtab(); /* We're finished */ return (noerr && nobaderr); } /* * 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 */ /* * Copyright 2010 Nexenta Systems, Inc. All rights reserved. */ /* 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 * UNIX System Data Types * Standard I/O definitions * Definitions for file control * Error handling definitions * String Handling Definitions * Standard UNIX(r) Definitions * Device Management Definitions * "devtab.h" Local Device Management Definitions */ #include #include #include #include #include #include #include #include #include #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) */ #define TDGTABNM "%sdgroup.%6.6d" /* * 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 . * * 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 (asprintf(&buf, TDGTABNM, dirname, getpid()) >= 0) { /* * 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. */ 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 so that it contains the members in the * membership list . * * 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 to the current position of the * standard I/O 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 doesn't exist, this function adds a record to the * device-group table for that device-group. That record will * have the name and will have a membership described in * the list referenced by . The record is added to the * end of the table. * * If already exists in the table, the function adds the * members in the 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 . * * 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); } /* * 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*/ #include #include #include #include #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); } /* * 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*/ #include #include #include #include #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); } /* * 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. */ /*LINTLIBRARY*/ #include #include #include #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); } /* * 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*/ #include #include #include #include #include #include #include #include #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); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (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 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /*LINTLIBRARY*/ #include #include #include #include #include #include #include #include #include #include /* * To copy each field of vtoc individually for copying extvtoc * to 32 bit vtoc and vs. * Currently bootinfo and timestamp are not really supported. */ #define libadm_vtoc_copy(vs, vd) \ { \ int i; \ vd->v_bootinfo[0] = (unsigned)vs->v_bootinfo[0]; \ vd->v_bootinfo[1] = (unsigned)vs->v_bootinfo[1]; \ vd->v_bootinfo[2] = (unsigned)vs->v_bootinfo[2]; \ vd->v_sanity = (unsigned)vs->v_sanity; \ vd->v_version = (unsigned)vs->v_version; \ bcopy(vs->v_volume, vd->v_volume, LEN_DKL_VVOL); \ vd->v_sectorsz = vs->v_sectorsz; \ vd->v_nparts = vs->v_nparts; \ vd->v_version = (unsigned)vs->v_version; \ for (i = 0; i < 10; i++) \ vd->v_reserved[i] = (unsigned)vs->v_reserved[i];\ for (i = 0; i < V_NUMPAR; i++) { \ vd->v_part[i].p_tag = vs->v_part[i].p_tag; \ vd->v_part[i].p_flag = vs->v_part[i].p_flag; \ vd->v_part[i].p_start = (unsigned)vs->v_part[i].p_start;\ vd->v_part[i].p_size = (unsigned)vs->v_part[i].p_size; \ } \ for (i = 0; i < V_NUMPAR; i++) \ if ((sizeof (vd->timestamp[i]) != sizeof (vs->timestamp[i])) &&\ (vs->timestamp[i] > INT32_MAX)) \ vd->timestamp[i] = INT32_MAX; \ else \ vd->timestamp[i] = (unsigned)vs->timestamp[i]; \ bcopy(vs->v_asciilabel, vd->v_asciilabel, LEN_DKL_ASCII); \ } /* * 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); case ENOTSUP: /* GPT labeled or disk > 1TB with no extvtoc support */ return (VT_ENOTSUP); case EOVERFLOW: return (VT_EOVERFLOW); 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); case ENOTSUP: /* GPT labeled or disk > 1TB with no extvtoc support */ return (VT_ENOTSUP); case EOVERFLOW: return (VT_EOVERFLOW); default: return (VT_ERROR); } } return (0); } int read_extvtoc(int fd, struct extvtoc *extvtoc) { struct dk_cinfo dki_info; struct vtoc oldvtoc; struct vtoc *oldvtocp = &oldvtoc; int ret; /* * Read the vtoc. */ if (ioctl(fd, DKIOCGEXTVTOC, (caddr_t)extvtoc) == -1) { switch (errno) { case EIO: return (VT_EIO); case EINVAL: return (VT_EINVAL); /* for disks > 1TB */ case ENOTSUP: return (VT_ENOTSUP); case EOVERFLOW: return (VT_EOVERFLOW); case ENOTTY: if ((ret = read_vtoc(fd, oldvtocp)) < 0) return (ret); #ifdef _LP64 /* * 64-bit vtoc and extvtoc have the same field sizes * and offsets. */ bcopy(oldvtocp, extvtoc, sizeof (struct extvtoc)); #else bzero(extvtoc, sizeof (struct extvtoc)); libadm_vtoc_copy(oldvtocp, extvtoc); #endif return (ret); default: return (VT_ERROR); } } /* * Sanity-check the vtoc. */ if (extvtoc->v_sanity != VTOC_SANE) { return (VT_EINVAL); } switch (extvtoc->v_version) { case 0: /* * For pre-version 1 vtoc keep same functionality * as read_vtoc. */ extvtoc->v_version = V_VERSION; if (extvtoc->v_nparts == 0) extvtoc->v_nparts = V_NUMPAR; if (extvtoc->v_sectorsz == 0) extvtoc->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 ext VTOC. */ int write_extvtoc(int fd, struct extvtoc *extvtoc) { int i; struct vtoc oldvtoc; struct vtoc *oldvtocp = &oldvtoc; /* * Sanity-check the vtoc */ if (extvtoc->v_sanity != VTOC_SANE || extvtoc->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)extvtoc->v_nparts; i++) if (extvtoc->v_part[i].p_size > 0) break; if (i == (int)extvtoc->v_nparts) return (-1); /* * Write the extvtoc */ if (ioctl(fd, DKIOCSEXTVTOC, (caddr_t)extvtoc) == -1) { switch (errno) { case EIO: return (VT_EIO); case EINVAL: return (VT_EINVAL); /* for disks > 1TB */ case ENOTSUP: return (VT_ENOTSUP); case EOVERFLOW: return (VT_EOVERFLOW); case ENOTTY: #ifdef _LP64 /* * 64-bit vtoc and extvtoc have the same field sizes * and offsets. */ bcopy(extvtoc, oldvtocp, sizeof (struct vtoc)); #else bzero(oldvtocp, sizeof (struct vtoc)); libadm_vtoc_copy(extvtoc, oldvtocp); #endif return (write_vtoc(fd, &oldvtoc)); default: return (VT_ERROR); } } return (0); } /* * 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. */ #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 /* * 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*/ int ckquit = 1; int ckwidth = 79; int ckindent = 8;