diff options
author | dufault <dufault@FreeBSD.org> | 1995-05-05 20:42:00 +0000 |
---|---|---|
committer | dufault <dufault@FreeBSD.org> | 1995-05-05 20:42:00 +0000 |
commit | 3f2591aedf14f1c6ff03a8b6a756b40d10002414 (patch) | |
tree | c0fff714fbc2ae639d35519522226afda6766544 /sbin | |
parent | e667a82b93eca984232265aee558968b7d0e327a (diff) | |
download | FreeBSD-src-3f2591aedf14f1c6ff03a8b6a756b40d10002414.zip FreeBSD-src-3f2591aedf14f1c6ff03a8b6a756b40d10002414.tar.gz |
Add support for editing mode pages.
Diffstat (limited to 'sbin')
-rw-r--r-- | sbin/scsi/scsi.8 | 24 | ||||
-rw-r--r-- | sbin/scsi/scsi.c | 264 |
2 files changed, 266 insertions, 22 deletions
diff --git a/sbin/scsi/scsi.8 b/sbin/scsi/scsi.8 index 356b57c..5735e1b 100644 --- a/sbin/scsi/scsi.8 +++ b/sbin/scsi/scsi.8 @@ -39,7 +39,7 @@ .\" SUCH DAMAGE. .\" .\" -.\" $Id: scsi.8,v 1.3 1995/04/28 19:24:38 dufault Exp $ +.\" $Id: scsi.8,v 1.4 1995/05/01 12:35:04 dufault Exp $ .\" .Dd October 11, 1993 .Dt SCSI 8 @@ -52,7 +52,7 @@ Usage: scsi -f device -d debug_level # To set debug level scsi -f device [-v] -z seconds # To freeze bus -scsi -f device -m page [-P pc] # To read mode pages +scsi -f device -m page [-P pc] [-e] # To read mode pages scsi -f device -p [-b bus] [-l lun] # To probe all devices scsi -f device -r [-b bus] [-t targ] [-l lun] # To reprobe a device scsi -f device [-v] [-s seconds] -c cmd_fmt [arg0 ... argn] # A command... @@ -95,6 +95,8 @@ option is used to read a device mode page. The file .Fr /usr/share/misc/scsi_modes is read to look at for how to interpret the mode data. The environment variable SCSI_MODES can specify a different file to use. +.Pp +.in +.25i The .Fr -P option can be used to specify a page control field. The page control @@ -106,9 +108,14 @@ fields are 3 Saved Values .Ed .Pp -Eventually this will also support a +The .Fr -e -option to permit editing the fields. +option permits you to edit the fields. It will use the editor specified +by your EDITOR environment variable. To store changes permanently, +edit page control 3 using the +.Fr -P +flag. +.in -.25i .Pp The .Fr -p @@ -143,6 +150,7 @@ for full details of which minor devices permit the ioctl, and .Xr scsi 3 for the full details on how to build up the commands and data phases using the format arguments. +.in +.25i .Pp .Fr -v turns on more verbose information. @@ -181,6 +189,7 @@ and displayed on the standard output. can be specified as a hyphen ("-") to indicate that the .Fr count bytes of data input should be written to the standard output. +.in -.25i .Sh EXAMPLES To verify that the device type for the disk /dev/rsd0c is 0 (direct access device): @@ -193,6 +202,11 @@ To do an inquiry to /dev/rsd2c: .Bd -literal -offset root# scsi -f /dev/rsd2c -c "12 0 0 0 64 0" -i 64 "s8 z8 z16 z4" FUJITSU M2654S-512 010P +.Pp +To edit mode page 1 on /dev/rsd2c, and store it permanently on the +drive: +.Bd -literal -offset +root# scsi -f /dev/rsd2c -m 1 -e -P 3 .Ed .Pp .Sh ENVIRONMENT @@ -206,6 +220,8 @@ it back to zero at program exit. .Pp The SU_DEBUG_TRUNCATE variable can be set to an integer to limit the amount of data phase output sent to the debugging file. +.Pp +The EDITOR variable determines the editor to use for the mode editor. .Sh SEE ALSO .Xr scsi 4 , .Xr scsi 3 diff --git a/sbin/scsi/scsi.c b/sbin/scsi/scsi.c index b96a6ab..3303197 100644 --- a/sbin/scsi/scsi.c +++ b/sbin/scsi/scsi.c @@ -39,7 +39,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: scsi.c,v 1.5 1995/05/01 12:35:05 dufault Exp $ + * $Id: scsi.c,v 1.6 1995/05/01 12:54:32 dufault Exp $ */ #include <stdio.h> @@ -450,6 +450,29 @@ void mode_sense(int fd, u_char *data, int len, int pc, int page) free(scsireq); } +void mode_select(int fd, u_char *data, int len, int perm) +{ + scsireq_t *scsireq; + + scsireq = scsireq_new(); + + if (scsireq_enter(fd, scsireq_build(scsireq, + len, data, SCCMD_WRITE, + "15 0:7 v:1 {SP} 0 0 v:i1 {Allocation Length} 0", perm, len)) == -1) /* Mode select */ + { + scsi_debug(stderr, -1, scsireq); + exit(errno); + } + + if (SCSIREQ_ERROR(scsireq)) + { + scsi_debug(stderr, 0, scsireq); + exit(-1); + } + + free(scsireq); +} + #define START_ENTRY '{' #define END_ENTRY '}' @@ -541,15 +564,152 @@ static char *mode_lookup(int page) return (found) ? fmt : 0; } -static void mode_edit(int fd, int page, int edit, int argc, char *argv[]) +/* -------- edit: Mode Select Editor --------- + */ +struct editinfo +{ + int can_edit; + int default_value; +} editinfo[64]; /* XXX Bogus fixed size */ + +static int editind; +static FILE *edit_file; +static char edit_name[L_tmpnam]; + +static inline void +edit_rewind(void) +{ + editind = 0; +} + +static void +edit_init(void) +{ + edit_rewind(); + if (tmpnam(edit_name) == 0) { + perror("tmpnam failed"); + exit(errno); + } + if ( (edit_file = fopen(edit_name, "w")) == 0) { + perror(edit_name); + exit(errno); + } +} + +static void +edit_check(void *hook, int letter, void *arg, int count, char *name) +{ + if (letter != 'i' && letter != 'b') { + fprintf(stderr, "Can't edit format %c.\n", letter); + exit(-1); + } + + if (editind >= sizeof(editinfo) / sizeof(editinfo[0])) { + fprintf(stderr, "edit table overflow\n"); + exit(ENOMEM); + } + editinfo[editind].can_edit = ((int)arg != 0); + editind++; +} + +static void +edit_defaults(void *hook, int letter, void *arg, int count, char *name) +{ + if (letter != 'i' && letter != 'b') { + fprintf(stderr, "Can't edit format %c.\n", letter); + exit(-1); + } + + editinfo[editind].default_value = ((int)arg); + 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') { + fprintf(stderr, "Can't report format %c.\n", letter); + exit(-1); + } + + fprintf(edit_file, "%s: %d\n", name, (int)arg); + } + + editind++; +} + +static int +edit_get(void *hook, char *name) +{ + struct get_hook *h = (struct get_hook *)hook; + int arg = editinfo[editind].default_value; + + if (editinfo[editind].can_edit) { + char line[80]; + if (fgets(line, sizeof(line), edit_file) == 0) { + perror("fgets"); + exit(errno); + } + + line[strlen(line) - 1] = 0; + + if (strncmp(name, line, strlen(name)) != 0) { + fprintf(stderr, "Expected \"%s\" and read \"%s\"\n", + name, line); + exit(-1); + } + + 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) { + perror(edit_name); + exit(errno); + } +} + +static void +mode_edit(int fd, int page, int edit, int argc, char *argv[]) { int i; u_char data[255]; - int mode_data_length; - int block_descriptor_length; - u_char *mode_data; - u_char *mode_parameters; - int page_length; + 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) { @@ -558,29 +718,97 @@ static void mode_edit(int fd, int page, int edit, int argc, char *argv[]) mode_db, page, (edit ? "edit" : "display")); } - if (edit) - fprintf(stderr, "Sorry; can't edit yet.\n"); + if (edit) { + if (!fmt) { + fprintf(stderr, "Sorry: can't edit without a format.\n"); + exit(-1); + } + + if (pagectl != 0 && pagectl != 3) { + fprintf(stderr, +"It only makes sense to edit page 0 (current) or page 3 (saved values)\n"); + exit(-1); + } + + verbose = 1; + + mode_sense(fd, data, sizeof(data), 1, page); + + mh = (struct mode_header *)data; + mph = (struct mode_page_header *) + (((char *)mh) + sizeof(*mh) + mh->bdl); + + mode_pars = (char *)mph + sizeof(*mph); + + edit_init(); + scsireq_buff_decode_visit(mode_pars, mh->mdl, + fmt, edit_check, 0); + + mode_sense(fd, data, sizeof(data), 0, page); + + edit_rewind(); + scsireq_buff_decode_visit(mode_pars, mh->mdl, + fmt, edit_defaults, 0); + + edit_rewind(); + scsireq_buff_decode_visit(mode_pars, mh->mdl, + fmt, edit_report, 0); + + edit_edit(); + + edit_rewind(); + scsireq_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 = 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(); + scsireq_buff_decode_visit(mode_pars, + mh->mdl, fmt, arg_put, 0); +#endif + + /* Make it permanent if pageselect is three. + */ + + mph->page_code &= ~0xC0; /* Clear PS and RESERVED */ + mh->mdl = 0; /* Reserved for mode select */ + + mode_select(fd, (char *)mh, + sizeof(*mh) + mh->bdl + sizeof(*mph) + mph->page_length, + (pagectl == 3)); + + exit(0); + } mode_sense(fd, data, sizeof(data), pagectl, page); /* Skip over the block descriptors. */ - mode_data_length = data[0]; - block_descriptor_length = data[3]; - mode_data = data + 4 + block_descriptor_length; - page_length = mode_data[1]; - mode_parameters = mode_data + 2; + 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 < mode_data_length; i++) { - printf("%02x%c",mode_parameters[i], + for (i = 0; i < mh->mdl; i++) { + printf("%02x%c",mode_pars[i], (((i + 1) % 8) == 0) ? '\n' : ' '); } putc('\n', stdout); } else { verbose = 1; - scsireq_buff_decode_visit(mode_parameters, - mode_data_length, fmt, arg_put, 0); + scsireq_buff_decode_visit(mode_pars, + mh->mdl, fmt, arg_put, 0); } } |