GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/scsi/scsi.c Lines: 0 329 0.0 %
Date: 2016-12-06 Branches: 0 234 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: scsi.c,v 1.30 2016/06/07 01:29:38 tedu Exp $	*/
2
/*	$FreeBSD: scsi.c,v 1.11 1996/04/06 11:00:28 joerg Exp $	*/
3
4
/*
5
 * Written By Julian ELischer
6
 * Copyright julian Elischer 1993.
7
 * Permission is granted to use or redistribute this file in any way as long
8
 * as this notice remains. Julian Elischer does not guarantee that this file
9
 * is totally correct for any given task and users of this file must
10
 * accept responsibility for any damage that occurs from the application of this
11
 * file.
12
 *
13
 * (julian@tfs.com julian@dialix.oz.au)
14
 *
15
 * User SCSI hooks added by Peter Dufault:
16
 *
17
 * Copyright (c) 1994 HD Associates
18
 * (contact: dufault@hda.com)
19
 * All rights reserved.
20
 *
21
 * Redistribution and use in source and binary forms, with or without
22
 * modification, are permitted provided that the following conditions
23
 * are met:
24
 * 1. Redistributions of source code must retain the above copyright
25
 *    notice, this list of conditions and the following disclaimer.
26
 * 2. Redistributions in binary form must reproduce the above copyright
27
 *    notice, this list of conditions and the following disclaimer in the
28
 *    documentation and/or other materials provided with the distribution.
29
 * 3. The name of HD Associates
30
 *    may not be used to endorse or promote products derived from this software
31
 *    without specific prior written permission.
32
 *
33
 * THIS SOFTWARE IS PROVIDED BY HD ASSOCIATES ``AS IS'' AND
34
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
35
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36
 * ARE DISCLAIMED.  IN NO EVENT SHALL HD ASSOCIATES BE LIABLE
37
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
38
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
39
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
41
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
42
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43
 * SUCH DAMAGE.
44
 */
45
46
#include <sys/types.h>
47
#include <sys/wait.h>
48
49
#include <fcntl.h>
50
#include <stdio.h>
51
#include <string.h>
52
#include <stdlib.h>
53
#include <unistd.h>
54
#include <errno.h>
55
#include <sys/scsiio.h>
56
#include <ctype.h>
57
#include <signal.h>
58
#include <err.h>
59
#include <paths.h>
60
61
#include "libscsi.h"
62
63
int	fd;
64
int	debuglevel;
65
int	debugflag;
66
int commandflag;
67
int verbose = 0;
68
69
int modeflag;
70
int editflag;
71
int modepage = 0; /* Read this mode page */
72
int pagectl = 0;  /* Mode sense page control */
73
int seconds = 2;
74
75
void	procargs(int *argc_p, char ***argv_p);
76
int	iget(void *hook, char *name);
77
char	*cget(void *hook, char *name);
78
void	arg_put(void *hook, int letter, void *arg, int count, char *name);
79
void	mode_sense(int fd, u_char *data, int len, int pc, int page);
80
void	mode_select(int fd, u_char *data, int len, int perm);
81
int	editit(const char *pathname);
82
83
static void
84
usage(void)
85
{
86
	fprintf(stderr,
87
"Usage:\n"
88
"\n"
89
"  scsi -f device -d debug_level                    # To set debug level\n"
90
"  scsi -f device -m page [-P pc]                   # To read mode pages\n"
91
"  scsi -f device [-v] [-s seconds] -c cmd_fmt [arg0 ... argn] # A command...\n"
92
"                 -o count out_fmt [arg0 ... argn]  #   EITHER (data out)\n"
93
"                 -i count in_fmt                   #   OR     (data in)\n"
94
"\n"
95
"\"out_fmt\" can be \"-\" to read output data from stdin;\n"
96
"\"in_fmt\" can be \"-\" to write input data to stdout;\n"
97
"\n"
98
"If debugging is not compiled in the kernel, \"-d\" will have no effect\n"
99
100
);
101
102
	exit (1);
103
}
104
105
void
106
procargs(int *argc_p, char ***argv_p)
107
{
108
	int argc = *argc_p;
109
	char **argv = *argv_p;
110
	int fflag, ch;
111
112
	fflag = 0;
113
	commandflag = 0;
114
	debugflag = 0;
115
	while ((ch = getopt(argc, argv, "cef:d:m:P:s:v")) != -1) {
116
		switch (ch) {
117
		case 'c':
118
			commandflag = 1;
119
			break;
120
		case 'e':
121
			editflag = 1;
122
			break;
123
		case 'f':
124
			if ((fd = scsi_open(optarg, O_RDWR)) < 0)
125
				err(1, "unable to open device %s", optarg);
126
			fflag = 1;
127
			break;
128
		case 'd':
129
			debuglevel = strtol(optarg, 0, 0);
130
			debugflag = 1;
131
			break;
132
		case 'm':
133
			modeflag = 1;
134
			modepage = strtol(optarg, 0, 0);
135
			break;
136
		case 'P':
137
			pagectl = strtol(optarg, 0, 0);
138
			break;
139
		case 's':
140
			seconds = strtol(optarg, 0, 0);
141
			break;
142
		case 'v':
143
			verbose = 1;
144
			break;
145
		case '?':
146
		default:
147
			usage();
148
		}
149
	}
150
	*argc_p = argc - optind;
151
	*argv_p = argv + optind;
152
153
	if (!fflag) usage();
154
}
155
156
/* get_hook: Structure for evaluating args in a callback.
157
 */
158
struct get_hook
159
{
160
	int argc;
161
	char **argv;
162
	int got;
163
};
164
165
/* iget: Integer argument callback
166
 */
167
int
168
iget(void *hook, char *name)
169
{
170
	struct get_hook *h = (struct get_hook *)hook;
171
	int arg;
172
173
	if (h->got >= h->argc)
174
	{
175
		fprintf(stderr, "Expecting an integer argument.\n");
176
		usage();
177
	}
178
	arg = strtol(h->argv[h->got], 0, 0);
179
	h->got++;
180
181
	if (verbose && name && *name)
182
		printf("%s: %d\n", name, arg);
183
184
	return arg;
185
}
186
187
/* cget: char * argument callback
188
 */
189
char *
190
cget(void *hook, char *name)
191
{
192
	struct get_hook *h = (struct get_hook *)hook;
193
	char *arg;
194
195
	if (h->got >= h->argc)
196
	{
197
		fprintf(stderr, "Expecting a character pointer argument.\n");
198
		usage();
199
	}
200
	arg = h->argv[h->got];
201
	h->got++;
202
203
	if (verbose && name)
204
		printf("cget: %s: %s", name, arg);
205
206
	return arg;
207
}
208
209
/* arg_put: "put argument" callback
210
 */
211
void arg_put(void *hook, int letter, void *arg, int count, char *name)
212
{
213
	if (verbose && name && *name)
214
		printf("%s:  ", name);
215
216
	switch(letter)
217
	{
218
		case 'i':
219
		case 'b':
220
		printf("%ld ", (long)arg);
221
		break;
222
223
		case 'c':
224
		case 'z':
225
		{
226
			char *p = malloc(count + 1);
227
			if (p == NULL)
228
				err(1, NULL);
229
230
			p[count] = 0;
231
			strncpy(p, (char *)arg, count);
232
			if (letter == 'z')
233
			{
234
				int i;
235
				for (i = count - 1; i >= 0; i--)
236
					if (p[i] == ' ')
237
						p[i] = 0;
238
					else
239
						break;
240
			}
241
			printf("%s ", p);
242
			free(p);
243
		}
244
245
		break;
246
247
		default:
248
		printf("Unknown format letter: '%c'\n", letter);
249
	}
250
	if (verbose)
251
		putchar('\n');
252
}
253
254
/* data_phase: SCSI bus data phase: DATA IN, DATA OUT, or no data transfer.
255
 */
256
enum data_phase {none = 0, in, out};
257
258
/* do_cmd: Send a command to a SCSI device
259
 */
260
static void
261
do_cmd(int fd, char *fmt, int argc, char **argv)
262
{
263
	struct get_hook h;
264
	scsireq_t *scsireq = scsireq_new();
265
	enum data_phase data_phase;
266
	int count, amount;
267
	char *data_fmt, *bp;
268
269
	h.argc = argc;
270
	h.argv = argv;
271
	h.got = 0;
272
273
	scsireq_reset(scsireq);
274
275
	scsireq_build_visit(scsireq, 0, 0, 0, fmt, iget, (void *)&h);
276
277
	/* Three choices here:
278
	 * 1. We've used up all the args and have no data phase.
279
	 * 2. We have input data ("-i")
280
	 * 3. We have output data ("-o")
281
	 */
282
283
	if (h.got >= h.argc)
284
	{
285
		data_phase = none;
286
		count = scsireq->datalen = 0;
287
	}
288
	else
289
	{
290
		char *flag = cget(&h, 0);
291
292
		if (strcmp(flag, "-o") == 0)
293
		{
294
			data_phase = out;
295
			scsireq->flags = SCCMD_WRITE;
296
		}
297
		else if (strcmp(flag, "-i") == 0)
298
		{
299
			data_phase = in;
300
			scsireq->flags = SCCMD_READ;
301
		}
302
		else
303
		{
304
			fprintf(stderr,
305
			"Need either \"-i\" or \"-o\" for data phase; not \"%s\".\n", flag);
306
			usage();
307
		}
308
309
		count = scsireq->datalen = iget(&h, 0);
310
		if (count) {
311
			data_fmt = cget(&h, 0);
312
313
			scsireq->databuf = malloc(count);
314
			if (scsireq->databuf == NULL)
315
				err(1, NULL);
316
317
			if (data_phase == out) {
318
				if (strcmp(data_fmt, "-") == 0)	{
319
					bp = (char *)scsireq->databuf;
320
					while (count > 0 &&
321
					    (amount = read(STDIN_FILENO,
322
					    bp, count)) > 0) {
323
						count -= amount;
324
						bp += amount;
325
					}
326
					if (amount == -1)
327
						err(1, "read");
328
					else if (amount == 0) {
329
						/* early EOF */
330
						fprintf(stderr,
331
							"Warning: only read %lu bytes out of %lu.\n",
332
							scsireq->datalen - (u_long)count,
333
							scsireq->datalen);
334
						scsireq->datalen -= (u_long)count;
335
					}
336
				}
337
				else
338
				{
339
					bzero(scsireq->databuf, count);
340
					scsireq_encode_visit(scsireq, data_fmt, iget, (void *)&h);
341
				}
342
			}
343
		}
344
	}
345
346
347
	scsireq->timeout = seconds * 1000;
348
349
	if (scsireq_enter(fd, scsireq) == -1)
350
	{
351
		scsi_debug(stderr, -1, scsireq);
352
		exit(1);
353
	}
354
355
	if (SCSIREQ_ERROR(scsireq))
356
		scsi_debug(stderr, 0, scsireq);
357
358
	if (count && data_phase == in)
359
	{
360
		if (strcmp(data_fmt, "-") == 0)	/* stdout */
361
		{
362
			bp = (char *)scsireq->databuf;
363
			while (count > 0 && (amount = write(STDOUT_FILENO, bp, count)) > 0)
364
			{
365
				count -= amount;
366
				bp += amount;
367
			}
368
			if (amount < 0)
369
				err(1, "write");
370
			else if (amount == 0)
371
				fprintf(stderr, "Warning: wrote only %lu bytes out of %lu.\n",
372
					scsireq->datalen - count,
373
					scsireq->datalen);
374
375
		}
376
		else
377
		{
378
			scsireq_decode_visit(scsireq, data_fmt, arg_put, 0);
379
			putchar('\n');
380
		}
381
	}
382
}
383
384
void mode_sense(int fd, u_char *data, int len, int pc, int page)
385
{
386
	scsireq_t *scsireq;
387
388
	bzero(data, len);
389
390
	scsireq = scsireq_new();
391
392
	if (scsireq_enter(fd, scsireq_build(scsireq,
393
	 len, data, SCCMD_READ,
394
	 "1A 0 v:2 {Page Control} v:6 {Page Code} 0 v:i1 {Allocation Length} 0",
395
	 pc, page, len)) == -1)	/* Mode sense */
396
	{
397
		scsi_debug(stderr, -1, scsireq);
398
		exit(1);
399
	}
400
401
	if (SCSIREQ_ERROR(scsireq))
402
	{
403
		scsi_debug(stderr, 0, scsireq);
404
		exit(1);
405
	}
406
407
	free(scsireq);
408
}
409
410
void mode_select(int fd, u_char *data, int len, int perm)
411
{
412
	scsireq_t *scsireq;
413
414
	scsireq = scsireq_new();
415
416
	if (scsireq_enter(fd, scsireq_build(scsireq,
417
	 len, data, SCCMD_WRITE,
418
	 "15 0:7 v:1 {SP} 0 0 v:i1 {Allocation Length} 0", perm, len)) == -1)	/* Mode select */
419
	{
420
		scsi_debug(stderr, -1, scsireq);
421
		exit(1);
422
	}
423
424
	if (SCSIREQ_ERROR(scsireq))
425
	{
426
		scsi_debug(stderr, 0, scsireq);
427
		exit(1);
428
	}
429
430
	free(scsireq);
431
}
432
433
434
#define START_ENTRY '{'
435
#define END_ENTRY '}'
436
437
static void
438
skipwhite(FILE *f)
439
{
440
	int c;
441
442
skip_again:
443
444
	while (isspace(c = getc(f)))
445
		continue;
446
447
	if (c == '#') {
448
		while ((c = getc(f)) != '\n' && c != EOF)
449
			continue;
450
		goto skip_again;
451
	}
452
453
	ungetc(c, f);
454
}
455
456
/* mode_lookup: Lookup a format description for a given page.
457
 */
458
char *mode_db = "/usr/share/misc/scsi_modes";
459
static char *mode_lookup(int page)
460
{
461
	char *new_db;
462
	FILE *modes;
463
	int match, next, found, c;
464
	static char fmt[1024];	/* XXX This should be with strealloc */
465
	int page_desc;
466
	new_db = getenv("SCSI_MODES");
467
468
	if (new_db)
469
		mode_db = new_db;
470
471
	modes = fopen(mode_db, "r");
472
	if (modes == NULL)
473
		return 0;
474
475
	next = 0;
476
	found = 0;
477
478
	while (!found) {
479
480
		skipwhite(modes);
481
482
		if (fscanf(modes, "%i", &page_desc) != 1)
483
			break;
484
485
		if (page_desc == page)
486
			found = 1;
487
488
		skipwhite(modes);
489
		if (getc(modes) != START_ENTRY) {
490
			errx(1, "Expected %c", START_ENTRY);
491
		}
492
493
		match = 1;
494
		while (match != 0) {
495
			c = getc(modes);
496
			if (c == EOF)
497
				fprintf(stderr, "Expected %c.\n", END_ENTRY);
498
499
			if (c == START_ENTRY) {
500
				match++;
501
			}
502
			if (c == END_ENTRY) {
503
				match--;
504
				if (match == 0)
505
					break;
506
			}
507
			if (found && c != '\n') {
508
				if (next >= sizeof(fmt)) {
509
					errx(1, "Stupid program: Buffer overflow.\n");
510
				}
511
512
				fmt[next++] = (u_char)c;
513
			}
514
		}
515
	}
516
	fclose(modes);
517
	fmt[next] = 0;
518
519
	return (found) ? fmt : 0;
520
}
521
522
/* -------- edit: Mode Select Editor ---------
523
 */
524
struct editinfo
525
{
526
	long can_edit;
527
	long default_value;
528
} editinfo[64];	/* XXX Bogus fixed size */
529
530
static int editind;
531
volatile int edit_opened;
532
static FILE *edit_file;
533
static char edit_name[L_tmpnam];
534
535
static void
536
edit_rewind(void)
537
{
538
	editind = 0;
539
}
540
541
static void
542
edit_done(void)
543
{
544
	int opened;
545
546
	sigset_t all, prev;
547
	sigfillset(&all);
548
549
	(void)sigprocmask(SIG_SETMASK, &all, &prev);
550
551
	opened = (int)edit_opened;
552
	edit_opened = 0;
553
554
	(void)sigprocmask(SIG_SETMASK, &prev, 0);
555
556
	if (opened)
557
	{
558
		if (fclose(edit_file))
559
			perror(edit_name);
560
		if (unlink(edit_name))
561
			perror(edit_name);
562
	}
563
}
564
565
static void
566
edit_init(void)
567
{
568
	int fd;
569
570
	edit_rewind();
571
	strlcpy(edit_name, "/var/tmp/scXXXXXXXX", sizeof edit_name);
572
	if ((fd = mkstemp(edit_name)) == -1)
573
		err(1, "mkstemp");
574
	if ( (edit_file = fdopen(fd, "w+")) == 0)
575
		err(1, "fdopen");
576
	edit_opened = 1;
577
578
	atexit(edit_done);
579
}
580
581
static void
582
edit_check(void *hook, int letter, void *arg, int count, char *name)
583
{
584
	if (letter != 'i' && letter != 'b') {
585
		errx(1, "Can't edit format %c.\n", letter);
586
	}
587
588
	if (editind >= sizeof(editinfo) / sizeof(editinfo[0])) {
589
		errx(1, "edit table overflow");
590
	}
591
	editinfo[editind].can_edit = ((long)arg != 0);
592
	editind++;
593
}
594
595
static void
596
edit_defaults(void *hook, int letter, void *arg, int count, char *name)
597
{
598
	if (letter != 'i' && letter != 'b') {
599
		errx(1, "Can't edit format %c.\n", letter);
600
	}
601
602
	editinfo[editind].default_value = ((long)arg);
603
	editind++;
604
}
605
606
static void
607
edit_report(void *hook, int letter, void *arg, int count, char *name)
608
{
609
	if (editinfo[editind].can_edit) {
610
		if (letter != 'i' && letter != 'b') {
611
			errx(1, "Can't report format %c.\n", letter);
612
		}
613
614
		fprintf(edit_file, "%s:  %ld\n", name, (long)arg);
615
	}
616
617
	editind++;
618
}
619
620
static int
621
edit_get(void *hook, char *name)
622
{
623
	int arg = editinfo[editind].default_value;
624
625
	if (editinfo[editind].can_edit) {
626
		char line[80];
627
		size_t len;
628
		if (fgets(line, sizeof(line), edit_file) == NULL)
629
			err(1, "fgets");
630
631
		len = strlen(line);
632
		if (len && line[len - 1] == '\n')
633
			line[len - 1] = '\0';
634
635
		if (strncmp(name, line, strlen(name)) != 0) {
636
			errx(1, "Expected \"%s\" and read \"%s\"\n",
637
			    name, line);
638
		}
639
640
		arg = strtoul(line + strlen(name) + 2, 0, 0);
641
	}
642
643
	editind++;
644
	return arg;
645
}
646
647
int
648
editit(const char *pathname)
649
{
650
	char *argp[] = {"sh", "-c", NULL, NULL}, *ed, *p;
651
	sig_t sighup, sigint, sigquit;
652
	pid_t pid;
653
	int st;
654
655
	ed = getenv("VISUAL");
656
	if (ed == NULL || ed[0] == '\0')
657
		ed = getenv("EDITOR");
658
	if (ed == NULL || ed[0] == '\0')
659
		ed = _PATH_VI;
660
	if (asprintf(&p, "%s %s", ed, pathname) == -1)
661
		return (-1);
662
	argp[2] = p;
663
664
 top:
665
	sighup = signal(SIGHUP, SIG_IGN);
666
	sigint = signal(SIGINT, SIG_IGN);
667
	sigquit = signal(SIGQUIT, SIG_IGN);
668
	if ((pid = fork()) == -1) {
669
		int saved_errno = errno;
670
671
		(void)signal(SIGHUP, sighup);
672
		(void)signal(SIGINT, sigint);
673
		(void)signal(SIGQUIT, sigquit);
674
		if (saved_errno == EAGAIN) {
675
			sleep(1);
676
			goto top;
677
		}
678
		free(p);
679
		errno = saved_errno;
680
		return (-1);
681
	}
682
	if (pid == 0) {
683
		execv(_PATH_BSHELL, argp);
684
		_exit(127);
685
	}
686
	free(p);
687
	for (;;) {
688
		if (waitpid(pid, &st, 0) == -1) {
689
			if (errno != EINTR)
690
				return (-1);
691
		} else
692
			break;
693
	}
694
	(void)signal(SIGHUP, sighup);
695
	(void)signal(SIGINT, sigint);
696
	(void)signal(SIGQUIT, sigquit);
697
	if (!WIFEXITED(st) || WEXITSTATUS(st) != 0) {
698
		errno = ECHILD;
699
		return (-1);
700
	}
701
	return (0);
702
}
703
704
static void
705
mode_edit(int fd, int page, int edit, int argc, char *argv[])
706
{
707
	int i;
708
	u_char data[255];
709
	u_char *mode_pars;
710
	struct mode_header
711
	{
712
		u_char mdl;	/* Mode data length */
713
		u_char medium_type;
714
		u_char dev_spec_par;
715
		u_char bdl;	/* Block descriptor length */
716
	};
717
718
	struct mode_page_header
719
	{
720
		u_char page_code;
721
		u_char page_length;
722
	};
723
724
	struct mode_header *mh;
725
	struct mode_page_header *mph;
726
727
	char *fmt = mode_lookup(page);
728
	if (!fmt && verbose) {
729
		fprintf(stderr,
730
		"No mode data base entry in \"%s\" for page %d;  binary %s only.\n",
731
		mode_db, page, (edit ? "edit" : "display"));
732
	}
733
734
	if (edit) {
735
		if (!fmt) {
736
			errx(1, "Sorry: can't edit without a format.\n");
737
		}
738
739
		if (pagectl != 0 && pagectl != 3) {
740
			errx(1,
741
"It only makes sense to edit page 0 (current) or page 3 (saved values)\n");
742
		}
743
744
		verbose = 1;
745
746
		mode_sense(fd, data, sizeof(data), 1, page);
747
748
		mh = (struct mode_header *)data;
749
		mph = (struct mode_page_header *)
750
		(((char *)mh) + sizeof(*mh) + mh->bdl);
751
752
		mode_pars = (char *)mph + sizeof(*mph);
753
754
		edit_init();
755
		scsireq_buff_decode_visit(mode_pars, mh->mdl,
756
		fmt, edit_check, 0);
757
758
		mode_sense(fd, data, sizeof(data), 0, page);
759
760
		edit_rewind();
761
		scsireq_buff_decode_visit(mode_pars, mh->mdl,
762
		fmt, edit_defaults, 0);
763
764
		edit_rewind();
765
		scsireq_buff_decode_visit(mode_pars, mh->mdl,
766
		fmt, edit_report, 0);
767
768
		fclose(edit_file);
769
		if (editit(edit_name) == -1 && errno != ECHILD)
770
			err(1, "edit %s", edit_name);
771
		if ((edit_file = fopen(edit_name, "r")) == NULL)
772
			err(1, "open %s", edit_name);
773
774
		edit_rewind();
775
		scsireq_buff_encode_visit(mode_pars, mh->mdl,
776
		fmt, edit_get, 0);
777
778
		/* Eliminate block descriptors:
779
		 */
780
		bcopy((char *)mph, ((char *)mh) + sizeof(*mh),
781
		sizeof(*mph) + mph->page_length);
782
783
		mh->bdl = 0;
784
		mph = (struct mode_page_header *) (((char *)mh) + sizeof(*mh));
785
		mode_pars = ((char *)mph) + 2;
786
787
#if 0
788
		/* Turn this on to see what you're sending to the
789
		 * device:
790
		 */
791
		edit_rewind();
792
		scsireq_buff_decode_visit(mode_pars,
793
		mh->mdl, fmt, arg_put, 0);
794
#endif
795
796
		edit_done();
797
798
		/* Make it permanent if pageselect is three.
799
		 */
800
801
		mph->page_code &= ~0xC0;	/* Clear PS and RESERVED */
802
		mh->mdl = 0;				/* Reserved for mode select */
803
804
		mode_select(fd, (char *)mh,
805
		sizeof(*mh) + mh->bdl + sizeof(*mph) + mph->page_length,
806
		(pagectl == 3));
807
808
		exit(0);
809
	}
810
811
	mode_sense(fd, data, sizeof(data), pagectl, page);
812
813
	/* Skip over the block descriptors.
814
	 */
815
	mh = (struct mode_header *)data;
816
	mph = (struct mode_page_header *)(((char *)mh) + sizeof(*mh) + mh->bdl);
817
	mode_pars = (char *)mph + sizeof(*mph);
818
819
	if (!fmt) {
820
		for (i = 0; i < mh->mdl; i++) {
821
			printf("%02x%c",mode_pars[i],
822
			(((i + 1) % 8) == 0) ? '\n' : ' ');
823
		}
824
		putc('\n', stdout);
825
	} else {
826
			verbose = 1;
827
			scsireq_buff_decode_visit(mode_pars,
828
			mh->mdl, fmt, arg_put, 0);
829
	}
830
}
831
832
int
833
main(int argc, char **argv)
834
{
835
	procargs(&argc,&argv);
836
837
	/* XXX This has grown to the point that it should be cleaned up.
838
	 */
839
	if (debugflag) {
840
		if (ioctl(fd,SCIOCDEBUG,&debuglevel) == -1)
841
			err(1, "SCIOCDEBUG");
842
	} else if (commandflag) {
843
		char *fmt;
844
845
		if (argc < 1) {
846
			fprintf(stderr, "Need the command format string.\n");
847
			usage();
848
		}
849
850
851
		fmt = argv[0];
852
853
		argc -= 1;
854
		argv += 1;
855
856
		do_cmd(fd, fmt, argc, argv);
857
	} else if (modeflag)
858
		mode_edit(fd, modepage, editflag, argc, argv);
859
860
	exit(0);
861
}