summaryrefslogtreecommitdiffstats
path: root/sbin/camcontrol/util.c
diff options
context:
space:
mode:
authorkbyanc <kbyanc@FreeBSD.org>2000-08-08 06:24:17 +0000
committerkbyanc <kbyanc@FreeBSD.org>2000-08-08 06:24:17 +0000
commit8f0afc6b0aa752cb23dfcf91f2285bf6c825405d (patch)
tree034cb732a278c59e0304f2f93947626f19ea5385 /sbin/camcontrol/util.c
parent18a0d975369707cba8c9deeb3de4db05dafb9487 (diff)
downloadFreeBSD-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.c357
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);
- }
-}
OpenPOWER on IntegriCloud