/* $OpenBSD: subr_userconf.c,v 1.34 2005/12/09 09:09:52 jsg Exp $ */ /* * Copyright (c) 1996-2001 Mats O Jansson <moj@stacken.kth.se> * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include <sys/param.h> #include <sys/systm.h> #include <sys/device.h> #include <sys/malloc.h> #include <sys/time.h> #include <dev/cons.h> extern char *locnames[]; extern short locnamp[]; extern short cfroots[]; extern int cfroots_size; extern int pv_size; extern short pv[]; extern struct timezone tz; extern char *pdevnames[]; extern int pdevnames_size; extern struct pdevinit pdevinit[]; int userconf_base = 16; /* Base for "large" numbers */ int userconf_maxdev = -1; /* # of used device slots */ int userconf_totdev = -1; /* # of device slots */ int userconf_maxlocnames = -1; /* # of locnames */ int userconf_cnt = -1; /* Line counter for ... */ int userconf_lines = 12; /* ... # of lines per page */ int userconf_histlen = 0; int userconf_histcur = 0; char userconf_history[1024]; int userconf_histsz = sizeof(userconf_history); char userconf_argbuf[40]; /* Additional input */ char userconf_cmdbuf[40]; /* Command line */ char userconf_histbuf[40]; void userconf_init(void); int userconf_more(void); void userconf_modify(char *, int *); void userconf_hist_cmd(char); void userconf_hist_int(int); void userconf_hist_eoc(void); void userconf_pnum(int); void userconf_pdevnam(short); void userconf_pdev(short); int userconf_number(char *, int *); int userconf_device(char *, int *, short *, short *); int userconf_attr(char *, int *); void userconf_modify(char *, int *); void userconf_change(int); void userconf_disable(int); void userconf_enable(int); void userconf_help(void); void userconf_list(void); void userconf_show(void); void userconf_common_attr_val(short, int *, char); void userconf_show_attr(char *); void userconf_common_dev(char *, int, short, short, char); void userconf_common_attr(char *, int, char); void userconf_add_read(char *, char, char *, int, int *); void userconf_add(char *, int, short, short); int userconf_parse(char *); #define UC_CHANGE 'c' #define UC_DISABLE 'd' #define UC_ENABLE 'e' #define UC_FIND 'f' #define UC_SHOW 's' char *userconf_cmds[] = { "add", "a", "base", "b", "change", "c", #if defined(DDB) "ddb", "D", #endif "disable", "d", "enable", "e", "exit", "q", "find", "f", "help", "h", "list", "l", "lines", "L", "quit", "q", "show", "s", "timezone", "t", "verbose", "v", "?", "h", "", "", }; void userconf_init(void) { int i = 0; struct cfdata *cd; int ln; while (cfdata[i].cf_attach != 0) { userconf_maxdev = i; userconf_totdev = i; cd = &cfdata[i]; ln = cd->cf_locnames; while (locnamp[ln] != -1) { if (locnamp[ln] > userconf_maxlocnames) userconf_maxlocnames = locnamp[ln]; ln++; } i++; } while (cfdata[i].cf_attach == 0) { userconf_totdev = i; i++; } userconf_totdev = userconf_totdev - 1; } int userconf_more(void) { int quit = 0; char c = '\0'; if (userconf_cnt != -1) { if (userconf_cnt == userconf_lines) { printf("--- more ---"); c = cngetc(); userconf_cnt = 0; printf("\r \r"); } userconf_cnt++; if (c == 'q' || c == 'Q') quit = 1; } return (quit); } void userconf_hist_cmd(char cmd) { userconf_histcur = userconf_histlen; if (userconf_histcur < userconf_histsz) { userconf_history[userconf_histcur] = cmd; userconf_histcur++; } } void userconf_hist_int(int val) { snprintf(userconf_histbuf, sizeof userconf_histbuf, " %d",val); if (userconf_histcur + strlen(userconf_histbuf) < userconf_histsz) { bcopy(userconf_histbuf, &userconf_history[userconf_histcur], strlen(userconf_histbuf)); userconf_histcur = userconf_histcur + strlen(userconf_histbuf); } } void userconf_hist_eoc(void) { if (userconf_histcur < userconf_histsz) { userconf_history[userconf_histcur] = '\n'; userconf_histcur++; userconf_histlen = userconf_histcur; } } void userconf_pnum(int val) { if (val > -2 && val < 16) { printf("%d",val); return; } switch (userconf_base) { case 8: printf("0%o",val); break; case 10: printf("%d",val); break; case 16: default: printf("0x%x",val); break; } } void userconf_pdevnam(short dev) { struct cfdata *cd; cd = &cfdata[dev]; printf("%s", cd->cf_driver->cd_name); switch (cd->cf_fstate) { case FSTATE_NOTFOUND: case FSTATE_DNOTFOUND: printf("%d", cd->cf_unit); break; case FSTATE_FOUND: printf("*FOUND*"); break; case FSTATE_STAR: case FSTATE_DSTAR: printf("*"); break; default: printf("*UNKNOWN*"); break; } } void userconf_pdev(short devno) { struct cfdata *cd; short *p; int *l; int ln; char c; if (devno > userconf_maxdev && devno <= userconf_totdev) { printf("%3d free slot (for add)\n", devno); return; } if (devno > userconf_totdev && devno <= userconf_totdev+pdevnames_size) { printf("%3d %s count %d (pseudo device)\n", devno, pdevnames[devno-userconf_totdev-1], pdevinit[devno-userconf_totdev-1].pdev_count); return; } if (devno > userconf_maxdev) { printf("Unknown devno (max is %d)\n", userconf_maxdev); return; } cd = &cfdata[devno]; printf("%3d ", devno); userconf_pdevnam(devno); printf(" at"); c = ' '; p = cd->cf_parents; if (*p == -1) printf(" root"); while (*p != -1) { printf("%c", c); userconf_pdevnam(*p++); c = '|'; } switch (cd->cf_fstate) { case FSTATE_NOTFOUND: case FSTATE_FOUND: case FSTATE_STAR: break; case FSTATE_DNOTFOUND: case FSTATE_DSTAR: printf(" disable"); break; default: printf(" ???"); break; } l = cd->cf_loc; ln = cd->cf_locnames; while (locnamp[ln] != -1) { printf(" %s ", locnames[locnamp[ln]]); ln++; userconf_pnum(*l++); } printf(" flags 0x%x\n", cd->cf_flags); } int userconf_number(char *c, int *val) { u_int num = 0; int neg = 0; int base = 10; if (*c == '-') { neg = 1; c++; } if (*c == '0') { base = 8; c++; if (*c == 'x' || *c == 'X') { base = 16; c++; } } while (*c != '\n' && *c != '\t' && *c != ' ' && *c != '\0') { u_char cc = *c; if (cc >= '0' && cc <= '9') cc = cc - '0'; else if (cc >= 'a' && cc <= 'f') cc = cc - 'a' + 10; else if (cc >= 'A' && cc <= 'F') cc = cc - 'A' + 10; else return (-1); if (cc > base) return (-1); num = num * base + cc; c++; } if (neg && num > INT_MAX) /* overflow */ return (1); *val = neg ? - num : num; return (0); } int userconf_device(char *cmd, int *len, short *unit, short *state) { short u = 0, s = FSTATE_FOUND; int l = 0; char *c; c = cmd; while (*c >= 'a' && *c <= 'z') { l++; c++; } if (*c == '*') { s = FSTATE_STAR; c++; } else { while (*c >= '0' && *c <= '9') { s = FSTATE_NOTFOUND; u = u*10 + *c - '0'; c++; } } while (*c == ' ' || *c == '\t' || *c == '\n') c++; if (*c == '\0') { *len = l; *unit = u; *state = s; return(0); } return(-1); } int userconf_attr(char *cmd, int *val) { char *c; short attr = -1, i = 0, l = 0; c = cmd; while (*c != ' ' && *c != '\t' && *c != '\n' && *c != '\0') { c++; l++; } while (i <= userconf_maxlocnames) { if (strlen(locnames[i]) == l) { if (strncasecmp(cmd, locnames[i], l) == 0) attr = i; } i++; } if (attr == -1) { return (-1); } *val = attr; return(0); } void userconf_modify(char *item, int *val) { int ok = 0; int a; char *c; int i; while (!ok) { printf("%s [", item); userconf_pnum(*val); printf("] ? "); i = getsn(userconf_argbuf, sizeof(userconf_argbuf)); c = userconf_argbuf; while (*c == ' ' || *c == '\t' || *c == '\n') c++; if (*c != '\0') { if (userconf_number(c, &a) == 0) { *val = a; ok = 1; } else { printf("Unknown argument\n"); } } else { ok = 1; } } } void userconf_change(int devno) { struct cfdata *cd; char c = '\0'; int *l; int ln; if (devno <= userconf_maxdev) { userconf_pdev(devno); while (c != 'y' && c != 'Y' && c != 'n' && c != 'N') { printf("change (y/n) ?"); c = cngetc(); printf("\n"); } if (c == 'y' || c == 'Y') { int share = 0, i, *lk; /* XXX add cmd 'c' <devno> */ userconf_hist_cmd('c'); userconf_hist_int(devno); cd = &cfdata[devno]; l = cd->cf_loc; ln = cd->cf_locnames; /* * Search for some other driver sharing this * locator table. if one does, we may need to * replace the locators with a malloc'd copy. */ for (i = 0; cfdata[i].cf_driver; i++) if (i != devno && cfdata[i].cf_loc == l) share = 1; if (share) { for (i = 0; locnamp[ln+i] != -1 ; i++) ; lk = l = (int *)malloc(sizeof(int) * i, M_TEMP, M_NOWAIT); if (lk == NULL) { printf("out of memory.\n"); return; } bcopy(cd->cf_loc, l, sizeof(int) * i); } while (locnamp[ln] != -1) { userconf_modify(locnames[locnamp[ln]], l); /* XXX add *l */ userconf_hist_int(*l); ln++; l++; } userconf_modify("flags", &cd->cf_flags); userconf_hist_int(cd->cf_flags); if (share) { if (bcmp(cd->cf_loc, lk, sizeof(int) * i)) cd->cf_loc = lk; else free(lk, M_TEMP); } printf("%3d ", devno); userconf_pdevnam(devno); printf(" changed\n"); userconf_pdev(devno); } return; } if (devno > userconf_maxdev && devno <= userconf_totdev) { printf("%3d can't change free slot\n", devno); return; } if (devno > userconf_totdev && devno <= userconf_totdev+pdevnames_size) { userconf_pdev(devno); while (c != 'y' && c != 'Y' && c != 'n' && c != 'N') { printf("change (y/n) ?"); c = cngetc(); printf("\n"); } if (c == 'y' || c == 'Y') { /* XXX add cmd 'c' <devno> */ userconf_hist_cmd('c'); userconf_hist_int(devno); userconf_modify("count", &pdevinit[devno-userconf_totdev-1].pdev_count); userconf_hist_int(pdevinit[devno-userconf_totdev-1].pdev_count); printf("%3d %s changed\n", devno, pdevnames[devno-userconf_totdev-1]); userconf_pdev(devno); /* XXX add eoc */ userconf_hist_eoc(); } return; } printf("Unknown devno (max is %d)\n", userconf_totdev+pdevnames_size); } void userconf_disable(int devno) { int done = 0; if (devno <= userconf_maxdev) { switch (cfdata[devno].cf_fstate) { case FSTATE_NOTFOUND: cfdata[devno].cf_fstate = FSTATE_DNOTFOUND; break; case FSTATE_STAR: cfdata[devno].cf_fstate = FSTATE_DSTAR; break; case FSTATE_DNOTFOUND: case FSTATE_DSTAR: done = 1; break; default: printf("Error unknown state\n"); break; } printf("%3d ", devno); userconf_pdevnam(devno); if (done) { printf(" already"); } else { /* XXX add cmd 'd' <devno> eoc */ userconf_hist_cmd('d'); userconf_hist_int(devno); userconf_hist_eoc(); } printf(" disabled\n"); return; } if (devno > userconf_maxdev && devno <= userconf_totdev) { printf("%3d can't disable free slot\n", devno); return; } if (devno > userconf_totdev && devno <= userconf_totdev+pdevnames_size) { printf("%3d %s can't disable pseudo device\n", devno, pdevnames[devno-userconf_totdev-1]); return; } printf("Unknown devno (max is %d)\n", userconf_totdev+pdevnames_size); } void userconf_enable(int devno) { int done = 0; if (devno <= userconf_maxdev) { switch (cfdata[devno].cf_fstate) { case FSTATE_DNOTFOUND: cfdata[devno].cf_fstate = FSTATE_NOTFOUND; break; case FSTATE_DSTAR: cfdata[devno].cf_fstate = FSTATE_STAR; break; case FSTATE_NOTFOUND: case FSTATE_STAR: done = 1; break; default: printf("Error unknown state\n"); break; } printf("%3d ", devno); userconf_pdevnam(devno); if (done) { printf(" already"); } else { /* XXX add cmd 'e' <devno> eoc */ userconf_hist_cmd('e'); userconf_hist_int(devno); userconf_hist_eoc(); } printf(" enabled\n"); return; } if (devno > userconf_maxdev && devno <= userconf_totdev) { printf("%3d can't enable free slot\n", devno); return; } if (devno > userconf_totdev && devno <= userconf_totdev+pdevnames_size) { printf("%3d %s can't enable pseudo device\n", devno, pdevnames[devno-userconf_totdev-1]); return; } printf("Unknown devno (max is %d)\n", userconf_totdev+pdevnames_size); } void userconf_help(void) { int j = 0, k; printf("command args description\n"); while (*userconf_cmds[j] != '\0') { printf(userconf_cmds[j]); k = strlen(userconf_cmds[j]); while (k < 10) { printf(" "); k++; } switch (*userconf_cmds[j+1]) { case 'L': printf("[count] number of lines before more"); break; case 'a': printf("dev add a device"); break; case 'b': printf("8|10|16 base on large numbers"); break; case 'c': printf("devno|dev change devices"); break; #if defined(DDB) case 'D': printf(" enter ddb"); break; #endif case 'd': printf("attr val|devno|dev disable devices"); break; case 'e': printf("attr val|devno|dev enable devices"); break; case 'f': printf("devno|dev find devices"); break; case 'h': printf(" this message"); break; case 'l': printf(" list configuration"); break; case 'q': printf(" leave UKC"); break; case 's': printf("[attr [val]] " "show attributes (or devices with an attribute)"); break; case 't': printf("[mins [dst]] set timezone/dst"); break; case 'v': printf(" toggle verbose booting"); break; default: printf(" don't know"); break; } printf("\n"); j += 2; } } void userconf_list(void) { int i = 0; userconf_cnt = 0; while (i <= (userconf_totdev+pdevnames_size)) { if (userconf_more()) break; userconf_pdev(i++); } userconf_cnt = -1; } void userconf_show(void) { int i = 0; userconf_cnt = 0; while (i <= userconf_maxlocnames) { if (userconf_more()) break; printf("%s\n", locnames[i++]); } userconf_cnt = -1; } void userconf_common_attr_val(short attr, int *val, char routine) { struct cfdata *cd; int *l; int ln; int i = 0, quit = 0; userconf_cnt = 0; while (i <= userconf_maxdev) { cd = &cfdata[i]; l = cd->cf_loc; ln = cd->cf_locnames; while (locnamp[ln] != -1) { if (locnamp[ln] == attr) { if (val == NULL) { quit = userconf_more(); userconf_pdev(i); } else { if (*val == *l) { quit = userconf_more(); switch (routine) { case UC_ENABLE: userconf_enable(i); break; case UC_DISABLE: userconf_disable(i); break; case UC_SHOW: userconf_pdev(i); break; default: printf("Unknown routine /%c/\n", routine); break; } } } } if (quit) break; ln++; l++; } if (quit) break; i++; } userconf_cnt = -1; } void userconf_show_attr(char *cmd) { char *c; short attr = -1, i = 0, l = 0; int a; c = cmd; while (*c != ' ' && *c != '\t' && *c != '\n' && *c != '\0') { c++; l++; } while (*c == ' ' || *c == '\t' || *c == '\n') { c++; } while (i <= userconf_maxlocnames) { if (strlen(locnames[i]) == l) { if (strncasecmp(cmd, locnames[i], l) == 0) { attr = i; } } i++; } if (attr == -1) { printf("Unknown attribute\n"); return; } if (*c == '\0') { userconf_common_attr_val(attr, NULL, UC_SHOW); } else { if (userconf_number(c, &a) == 0) { userconf_common_attr_val(attr, &a, UC_SHOW); } else { printf("Unknown argument\n"); } } } void userconf_common_dev(char *dev, int len, short unit, short state, char routine) { int i = 0; switch (routine) { case UC_CHANGE: break; default: userconf_cnt = 0; break; } while (cfdata[i].cf_attach != 0) { if (strlen(cfdata[i].cf_driver->cd_name) == len) { /* * Ok, if device name is correct * If state == FSTATE_FOUND, look for "dev" * If state == FSTATE_STAR, look for "dev*" * If state == FSTATE_NOTFOUND, look for "dev0" */ if (strncasecmp(dev, cfdata[i].cf_driver->cd_name, len) == 0 && (state == FSTATE_FOUND || (state == FSTATE_STAR && (cfdata[i].cf_fstate == FSTATE_STAR || cfdata[i].cf_fstate == FSTATE_DSTAR)) || (state == FSTATE_NOTFOUND && cfdata[i].cf_unit == unit && (cfdata[i].cf_fstate == FSTATE_NOTFOUND || cfdata[i].cf_fstate == FSTATE_DNOTFOUND)))) { if (userconf_more()) break; switch (routine) { case UC_CHANGE: userconf_change(i); break; case UC_ENABLE: userconf_enable(i); break; case UC_DISABLE: userconf_disable(i); break; case UC_FIND: userconf_pdev(i); break; default: printf("Unknown routine /%c/\n", routine); break; } } } i++; } for (i = 0; i < pdevnames_size; i++) { if (strncasecmp(dev, pdevnames[i], len) == 0 && state == FSTATE_FOUND) { switch(routine) { case UC_CHANGE: userconf_change(userconf_totdev+1+i); break; case UC_ENABLE: userconf_enable(userconf_totdev+1+i); break; case UC_DISABLE: userconf_disable(userconf_totdev+1+i); break; case UC_FIND: userconf_pdev(userconf_totdev+1+i); break; default: printf("Unknown pseudo routine /%c/\n",routine); break; } } } switch (routine) { case UC_CHANGE: break; default: userconf_cnt = -1; break; } } void userconf_common_attr(char *cmd, int attr, char routine) { char *c; short l = 0; int a; c = cmd; while (*c != ' ' && *c != '\t' && *c != '\n' && *c != '\0') { c++; l++; } while (*c == ' ' || *c == '\t' || *c == '\n') c++; if (*c == '\0') { printf("Value missing for attribute\n"); return; } if (userconf_number(c, &a) == 0) { userconf_common_attr_val(attr, &a, routine); } else { printf("Unknown argument\n"); } } void userconf_add_read(char *prompt, char field, char *dev, int len, int *val) { int ok = 0; int a; char *c; int i; *val = -1; while (!ok) { printf("%s ? ", prompt); i = getsn(userconf_argbuf, sizeof(userconf_argbuf)); c = userconf_argbuf; while (*c == ' ' || *c == '\t' || *c == '\n') c++; if (*c != '\0') { if (userconf_number(c, &a) == 0) { if (a > userconf_maxdev) { printf("Unknown devno (max is %d)\n", userconf_maxdev); } else if (strncasecmp(dev, cfdata[a].cf_driver->cd_name, len) != 0 && field == 'a') { printf("Not same device type\n"); } else { *val = a; ok = 1; } } else if (*c == '?') { userconf_common_dev(dev, len, 0, FSTATE_FOUND, UC_FIND); } else if (*c == 'q' || *c == 'Q') { ok = 1; } else { printf("Unknown argument\n"); } } else { ok = 1; } } } void userconf_add(char *dev, int len, short unit, short state) { int i = 0, found = 0; struct cfdata new; int val, max_unit, star_unit, orig; bzero(&new, sizeof(struct cfdata)); if (userconf_maxdev == userconf_totdev) { printf("No more space for new devices.\n"); return; } if (state == FSTATE_FOUND) { printf("Device not complete number or * is missing\n"); return; } for (i = 0; cfdata[i].cf_driver; i++) if (strlen(cfdata[i].cf_driver->cd_name) == len && strncasecmp(dev, cfdata[i].cf_driver->cd_name, len) == 0) found = 1; if (!found) { printf("No device of this type exists.\n"); return; } userconf_add_read("Clone Device (DevNo, 'q' or '?')", 'a', dev, len, &val); if (val != -1) { orig = val; new = cfdata[val]; new.cf_unit = unit; new.cf_fstate = state; userconf_add_read("Insert before Device (DevNo, 'q' or '?')", 'i', dev, len, &val); } if (val != -1) { /* XXX add cmd 'a' <orig> <val> eoc */ userconf_hist_cmd('a'); userconf_hist_int(orig); userconf_hist_int(unit); userconf_hist_int(state); userconf_hist_int(val); userconf_hist_eoc(); /* Insert the new record */ for (i = userconf_maxdev; val <= i; i--) cfdata[i+1] = cfdata[i]; cfdata[val] = new; /* Fix indexs in pv */ for (i = 0; i < pv_size; i++) { if (pv[i] != -1 && pv[i] >= val) pv[i]++; } /* Fix indexs in cfroots */ for (i = 0; i < cfroots_size; i++) { if (cfroots[i] != -1 && cfroots[i] >= val) cfroots[i]++; } userconf_maxdev++; max_unit = -1; /* Find max unit number of the device type */ i = 0; while (cfdata[i].cf_attach != 0) { if (strlen(cfdata[i].cf_driver->cd_name) == len && strncasecmp(dev, cfdata[i].cf_driver->cd_name, len) == 0) { switch (cfdata[i].cf_fstate) { case FSTATE_NOTFOUND: case FSTATE_DNOTFOUND: if (cfdata[i].cf_unit > max_unit) max_unit = cfdata[i].cf_unit; break; default: break; } } i++; } /* * For all * entries set unit number to max+1, and update * cf_starunit1 if necessary. */ max_unit++; star_unit = -1; i = 0; while (cfdata[i].cf_attach != 0) { if (strlen(cfdata[i].cf_driver->cd_name) == len && strncasecmp(dev, cfdata[i].cf_driver->cd_name, len) == 0) { switch (cfdata[i].cf_fstate) { case FSTATE_NOTFOUND: case FSTATE_DNOTFOUND: if (cfdata[i].cf_unit > star_unit) star_unit = cfdata[i].cf_unit; break; default: break; } } i++; } star_unit++; i = 0; while (cfdata[i].cf_attach != 0) { if (strlen(cfdata[i].cf_driver->cd_name) == len && strncasecmp(dev, cfdata[i].cf_driver->cd_name, len) == 0) { switch (cfdata[i].cf_fstate) { case FSTATE_STAR: case FSTATE_DSTAR: cfdata[i].cf_unit = max_unit; if (cfdata[i].cf_starunit1 < star_unit) cfdata[i].cf_starunit1 = star_unit; break; default: break; } } i++; } userconf_pdev(val); } /* cf_attach, cf_driver, cf_unit, cf_fstate, cf_loc, cf_flags, cf_parents, cf_locnames, cf_locnames and cf_ivstubs */ } int userconf_parse(char *cmd) { char *c, *v; int i = 0, j = 0, k, a; short unit, state; c = cmd; while (*c == ' ' || *c == '\t') c++; v = c; while (*c != ' ' && *c != '\t' && *c != '\n' && *c != '\0') { c++; i++; } k = -1; while (*userconf_cmds[j] != '\0') { if (strlen(userconf_cmds[j]) == i) { if (strncasecmp(v, userconf_cmds[j], i) == 0) k = j; } j += 2; } while (*c == ' ' || *c == '\t' || *c == '\n') c++; if (k == -1) { if (*v != '\n') printf("Unknown command, try help\n"); } else { switch (*userconf_cmds[k+1]) { case 'L': if (*c == '\0') printf("Argument expected\n"); else if (userconf_number(c, &a) == 0) userconf_lines = a; else printf("Unknown argument\n"); break; case 'a': if (*c == '\0') printf("Dev expected\n"); else if (userconf_device(c, &a, &unit, &state) == 0) userconf_add(c, a, unit, state); else printf("Unknown argument\n"); break; case 'b': if (*c == '\0') printf("8|10|16 expected\n"); else if (userconf_number(c, &a) == 0) { if (a == 8 || a == 10 || a == 16) { userconf_base = a; } else { printf("8|10|16 expected\n"); } } else printf("Unknown argument\n"); break; case 'c': if (*c == '\0') printf("DevNo or Dev expected\n"); else if (userconf_number(c, &a) == 0) userconf_change(a); else if (userconf_device(c, &a, &unit, &state) == 0) userconf_common_dev(c, a, unit, state, UC_CHANGE); else printf("Unknown argument\n"); break; #if defined(DDB) case 'D': Debugger(); break; #endif case 'd': if (*c == '\0') printf("Attr, DevNo or Dev expected\n"); else if (userconf_attr(c, &a) == 0) userconf_common_attr(c, a, UC_DISABLE); else if (userconf_number(c, &a) == 0) userconf_disable(a); else if (userconf_device(c, &a, &unit, &state) == 0) userconf_common_dev(c, a, unit, state, UC_DISABLE); else printf("Unknown argument\n"); break; case 'e': if (*c == '\0') printf("Attr, DevNo or Dev expected\n"); else if (userconf_attr(c, &a) == 0) userconf_common_attr(c, a, UC_ENABLE); else if (userconf_number(c, &a) == 0) userconf_enable(a); else if (userconf_device(c, &a, &unit, &state) == 0) userconf_common_dev(c, a, unit, state, UC_ENABLE); else printf("Unknown argument\n"); break; case 'f': if (*c == '\0') printf("DevNo or Dev expected\n"); else if (userconf_number(c, &a) == 0) userconf_pdev(a); else if (userconf_device(c, &a, &unit, &state) == 0) userconf_common_dev(c, a, unit, state, UC_FIND); else printf("Unknown argument\n"); break; case 'h': userconf_help(); break; case 'l': if (*c == '\0') userconf_list(); else printf("Unknown argument\n"); break; case 'q': /* XXX add cmd 'q' eoc */ userconf_hist_cmd('q'); userconf_hist_eoc(); return(-1); break; case 's': if (*c == '\0') userconf_show(); else userconf_show_attr(c); break; case 't': if (*c == '\0' || userconf_number(c, &a) == 0) { if (*c != '\0') { tz.tz_minuteswest = a; while (*c != '\n' && *c != '\t' && *c != ' ' && *c != '\0') c++; while (*c == '\t' || *c == ' ') c++; if (*c != '\0' && userconf_number(c, &a) == 0) tz.tz_dsttime = a; userconf_hist_cmd('t'); userconf_hist_int(tz.tz_minuteswest); userconf_hist_int(tz.tz_dsttime); userconf_hist_eoc(); } printf("timezone = %d, dst = %d\n", tz.tz_minuteswest, tz.tz_dsttime); } else printf("Unknown argument\n"); break; case 'v': autoconf_verbose = !autoconf_verbose; printf("autoconf verbose %sabled\n", autoconf_verbose ? "en" : "dis"); break; default: printf("Unknown command\n"); break; } } return(0); } void user_config(void) { userconf_init(); printf("User Kernel Config\n"); while (1) { printf("UKC> "); if (getsn(userconf_cmdbuf, sizeof(userconf_cmdbuf)) > 0 && userconf_parse(userconf_cmdbuf)) break; } printf("Continuing...\n"); }