summaryrefslogtreecommitdiffstats
path: root/sbin
diff options
context:
space:
mode:
authordufault <dufault@FreeBSD.org>1995-05-05 20:42:00 +0000
committerdufault <dufault@FreeBSD.org>1995-05-05 20:42:00 +0000
commit3f2591aedf14f1c6ff03a8b6a756b40d10002414 (patch)
treec0fff714fbc2ae639d35519522226afda6766544 /sbin
parente667a82b93eca984232265aee558968b7d0e327a (diff)
downloadFreeBSD-src-3f2591aedf14f1c6ff03a8b6a756b40d10002414.zip
FreeBSD-src-3f2591aedf14f1c6ff03a8b6a756b40d10002414.tar.gz
Add support for editing mode pages.
Diffstat (limited to 'sbin')
-rw-r--r--sbin/scsi/scsi.824
-rw-r--r--sbin/scsi/scsi.c264
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);
}
}
OpenPOWER on IntegriCloud