diff options
author | kbyanc <kbyanc@FreeBSD.org> | 2000-08-08 06:24:17 +0000 |
---|---|---|
committer | kbyanc <kbyanc@FreeBSD.org> | 2000-08-08 06:24:17 +0000 |
commit | 8f0afc6b0aa752cb23dfcf91f2285bf6c825405d (patch) | |
tree | 034cb732a278c59e0304f2f93947626f19ea5385 /sbin/camcontrol/util.c | |
parent | 18a0d975369707cba8c9deeb3de4db05dafb9487 (diff) | |
download | FreeBSD-src-8f0afc6b0aa752cb23dfcf91f2285bf6c825405d.zip FreeBSD-src-8f0afc6b0aa752cb23dfcf91f2285bf6c825405d.tar.gz |
This is an overhaul of the mode page handling in camcontrol as well as
related patches. These include:
* Mode page editting can be scripted. This involves two
things: first, if stdin is not a tty, changes are read from
stdin rather than invoking $EDITOR. Second, and more
importantly, not all modepage entries must be included in the
change set. This means that camcontrol can now gracefully handle
more intrusive editting from the $EDITOR, including removal or
rearrangement of lines. It also means that you can do stuff
like:
# echo "WCE: 1" | camcontrol modepage da3 -m 8 -e
# newfs /dev/da3
# echo "WCE: 0" | camcontrol modepage da3 -m 8 -e
* Range-checking on user-supplied input values. modeedit.c now
uses the field width specifiers to determine the maximum
allowable value for a field. If the user enters a value larger
than the maximum, it clips the value to the max and warns the
user. This also involved patching cam_cmdparse.c to be more
consistent with regards to the "count" parameter to arg_put
(previously is was the length of strings and 1 for all integral
types). The cam_cdbparse(3) man page was also updated to reflect
the revised semantics.
* In the process, I removed the 64 entry limit on mode pages (not
that we were even close to hitting that limit). This was a nice
side-effect of the other changes.
* Technically, the new mode editting functionality allows editting
of character array entries in mode pages (type 'c' or 'z'),
however since buff_encode doesn't grok them it is currently
useless.
* Camcontrol gained two new options related to mode pages: -l and
-b. The former lists all available mode pages for a given
device. The latter forces mode page display in binary format
(the default when no mode page definition was found in
scsi_modes).
* Added support for mode page names to scsi_modes. Allows names to
be displayed alongside mode numbers in the mode page
listing. Updated scsi_modes to use the new functionality. This
also adds the semicolon into the scsi_modes syntax as an
optional mode page definition terminator. This is needed to name
pages without providing a page format definition.
* Updated scsi_all.h to include a structure describing mode page
headers.
* Added $FreeBSD$ line to scsi_modes.
Inspired by: dwhite
Reviewed by: ken
Diffstat (limited to 'sbin/camcontrol/util.c')
-rw-r--r-- | sbin/camcontrol/util.c | 357 |
1 files changed, 3 insertions, 354 deletions
diff --git a/sbin/camcontrol/util.c b/sbin/camcontrol/util.c index 32f5c78..93f409b 100644 --- a/sbin/camcontrol/util.c +++ b/sbin/camcontrol/util.c @@ -48,22 +48,15 @@ static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ -#include <ctype.h> -#include <err.h> -#include <errno.h> -#include <string.h> #include <stdlib.h> #include <stdio.h> -#include <sys/file.h> -#include <signal.h> -#include <unistd.h> +#include <string.h> +#include <sys/types.h> -#include <cam/cam.h> -#include <cam/cam_ccb.h> #include <camlib.h> #include "camcontrol.h" -int verbose = 0; +int verbose; /* iget: Integer argument callback */ @@ -157,347 +150,3 @@ arg_put(void *hook, int letter, void *arg, int count, char *name) if (verbose) putchar('\n'); } - -#define START_ENTRY '{' -#define END_ENTRY '}' - -static void -skipwhite(FILE *f) -{ - int c; - -skip_again: - - while (isspace(c = getc(f))) - ; - - if (c == '#') { - while ((c = getc(f)) != '\n' && c != EOF) - ; - goto skip_again; - } - - ungetc(c, f); -} - -/* mode_lookup: Lookup a format description for a given page. - */ -char *mode_db = "/usr/share/misc/scsi_modes"; -static char * -mode_lookup(int page) -{ - char *new_db; - FILE *modes; - int match, next, found, c; - static char fmt[4096]; /* XXX This should be with strealloc */ - int page_desc; - new_db = getenv("SCSI_MODES"); - - if (new_db) - mode_db = new_db; - - modes = fopen(mode_db, "r"); - if (modes == 0) - return 0; - - next = 0; - found = 0; - - while (!found) { - - skipwhite(modes); - - if (fscanf(modes, "%i", &page_desc) != 1) - break; - - if (page_desc == page) - found = 1; - - skipwhite(modes); - if (getc(modes) != START_ENTRY) - errx(1, "expected %c", START_ENTRY); - - match = 1; - while (match != 0) { - c = getc(modes); - if (c == EOF) { - warnx("expected %c", END_ENTRY); - } - - if (c == START_ENTRY) { - match++; - } - if (c == END_ENTRY) { - match--; - if (match == 0) - break; - } - if (found && c != '\n') { - if (next >= sizeof(fmt)) - errx(1, "buffer overflow"); - - fmt[next++] = (u_char)c; - } - } - } - fmt[next] = 0; - - return (found) ? fmt : 0; -} - -/* -------- edit: Mode Select Editor --------- - */ -struct editinfo -{ - int can_edit; - int default_value; -} editinfo[64]; /* XXX Bogus fixed size */ - -static int editind; -volatile int edit_opened; -static FILE *edit_file; -static char edit_name[L_tmpnam]; - -static inline void -edit_rewind(void) -{ - editind = 0; -} - -static void -edit_done(void) -{ - int opened; - - sigset_t all, prev; - sigfillset(&all); - - (void)sigprocmask(SIG_SETMASK, &all, &prev); - - opened = (int)edit_opened; - edit_opened = 0; - - (void)sigprocmask(SIG_SETMASK, &prev, 0); - - if (opened) - { - if (fclose(edit_file)) - warn("%s", edit_name); - if (unlink(edit_name)) - warn("%s", edit_name); - } -} - -static void -edit_init(void) -{ - int fd; - - edit_rewind(); - strlcpy(edit_name, "/tmp/camXXXXXX", sizeof(edit_name)); - if ((fd = mkstemp(edit_name)) == -1) - errx(1, "mkstemp failed"); - if ((edit_file = fdopen(fd, "w")) == 0) - err(1, "%s", edit_name); - edit_opened = 1; - - atexit(edit_done); -} - -static void -edit_check(void *hook, int letter, void *arg, int count, char *name) -{ - if (letter != 'i' && letter != 'b') - errx(1, "can't edit format %c", letter); - - if (editind >= sizeof(editinfo) / sizeof(editinfo[0])) - errx(1, "edit table overflow"); - - editinfo[editind].can_edit = (arg != NULL); - editind++; -} - -static void -edit_defaults(void *hook, int letter, void *arg, int count, char *name) -{ - if (letter != 'i' && letter != 'b') - errx(1, "can't edit format %c", letter); - - editinfo[editind].default_value = (intptr_t)arg; /* truncated */ - editind++; -} - -static void -edit_report(void *hook, int letter, void *arg, int count, char *name) -{ - if (editinfo[editind].can_edit) { - if (letter != 'i' && letter != 'b') - errx(1, "can't report format %c", letter); - - fprintf(edit_file, "%s: %d\n", name, (intptr_t)arg); - } - - editind++; -} - -static int -edit_get(void *hook, char *name) -{ - int arg = editinfo[editind].default_value; - - if (editinfo[editind].can_edit) { - char line[80]; - if (fgets(line, sizeof(line), edit_file) == 0) - err(1, "fgets"); - - line[strlen(line) - 1] = 0; - - if (strncmp(name, line, strlen(name)) != 0) - errx(1, "expected \"%s\" and read \"%s\"", name, line); - - arg = strtoul(line + strlen(name) + 2, 0, 0); - } - - editind++; - return arg; -} - -static void -edit_edit(void) -{ - char *system_line; - char *editor = getenv("EDITOR"); - if (!editor) - editor = "vi"; - - fclose(edit_file); - - system_line = malloc(strlen(editor) + strlen(edit_name) + 6); - sprintf(system_line, "%s %s", editor, edit_name); - system(system_line); - free(system_line); - - if ((edit_file = fopen(edit_name, "r")) == 0) - err(1, "%s", edit_name); -} - -void -mode_edit(struct cam_device *device, int page, int page_control, int dbd, - int edit, int retry_count, int timeout) -{ - int i; - u_char data[255]; - u_char *mode_pars; - struct mode_header - { - u_char mdl; /* Mode data length */ - u_char medium_type; - u_char dev_spec_par; - u_char bdl; /* Block descriptor length */ - }; - - struct mode_page_header - { - u_char page_code; - u_char page_length; - }; - - struct mode_header *mh; - struct mode_page_header *mph; - - char *fmt = mode_lookup(page); - if (!fmt && verbose) { - fprintf(stderr, - "No mode data base entry in \"%s\" for page %d; " - " binary %s only.\n", - mode_db, page, (edit ? "edit" : "display")); - } - - if (edit) { - if (!fmt) - errx(1, "can't edit without a format"); - - if (page_control != 0 && page_control != 3) - errx(1, "it only makes sense to edit page 0 " - "(current) or page 3 (saved values)"); - - verbose = 1; - - mode_sense(device, page, 1, dbd, retry_count, timeout, - data, sizeof(data)); - - mh = (struct mode_header *)data; - mph = (struct mode_page_header *) - (((char *)mh) + sizeof(*mh) + mh->bdl); - - mode_pars = (char *)mph + sizeof(*mph); - - edit_init(); - buff_decode_visit(mode_pars, mh->mdl, fmt, edit_check, 0); - - mode_sense(device, page, 0, dbd, retry_count, timeout, - data, sizeof(data)); - - edit_rewind(); - buff_decode_visit(mode_pars, mh->mdl, fmt, edit_defaults, 0); - - edit_rewind(); - buff_decode_visit(mode_pars, mh->mdl, fmt, edit_report, 0); - - edit_edit(); - - edit_rewind(); - buff_encode_visit(mode_pars, mh->mdl, fmt, edit_get, 0); - - /* Eliminate block descriptors: - */ - bcopy((char *)mph, ((char *)mh) + sizeof(*mh), - sizeof(*mph) + mph->page_length); - - mh->bdl = mh->dev_spec_par = 0; - mph = (struct mode_page_header *) (((char *)mh) + sizeof(*mh)); - mode_pars = ((char *)mph) + 2; - -#if 0 - /* Turn this on to see what you're sending to the - * device: - */ - edit_rewind(); - buff_decode_visit(mode_pars, mh->mdl, fmt, arg_put, 0); -#endif - - edit_done(); - - /* Make it permanent if pageselect is three. - */ - - mph->page_code &= ~0xC0; /* Clear PS and RESERVED */ - mh->mdl = 0; /* Reserved for mode select */ - - mode_select(device, (page_control == 3), retry_count, - timeout, (u_int8_t *)mh, sizeof(*mh) + mh->bdl + - sizeof(*mph) + mph->page_length); - - return; - } - - mode_sense(device, page, page_control, dbd, retry_count, timeout, - data, sizeof(data)); - - /* Skip over the block descriptors. - */ - mh = (struct mode_header *)data; - mph = (struct mode_page_header *)(((char *)mh) + sizeof(*mh) + mh->bdl); - mode_pars = (char *)mph + sizeof(*mph); - - if (!fmt) { - for (i = 0; i < mh->mdl; i++) { - printf("%02x%c",mode_pars[i], - (((i + 1) % 8) == 0) ? '\n' : ' '); - } - putc('\n', stdout); - } else { - verbose = 1; - buff_decode_visit(mode_pars, mh->mdl, fmt, arg_put, NULL); - } -} |