xref: /freebsd/sbin/camcontrol/modeedit.c (revision c60e19a83b862d27963ab1c3f037191d12ff6502)
1525689f1SJustin T. Gibbs /*
2525689f1SJustin T. Gibbs  * Written By Julian ELischer
3525689f1SJustin T. Gibbs  * Copyright julian Elischer 1993.
4525689f1SJustin T. Gibbs  * Permission is granted to use or redistribute this file in any way as long
5525689f1SJustin T. Gibbs  * as this notice remains. Julian Elischer does not guarantee that this file
6525689f1SJustin T. Gibbs  * is totally correct for any given task and users of this file must
7525689f1SJustin T. Gibbs  * accept responsibility for any damage that occurs from the application of this
8525689f1SJustin T. Gibbs  * file.
9525689f1SJustin T. Gibbs  *
10525689f1SJustin T. Gibbs  * (julian@tfs.com julian@dialix.oz.au)
11525689f1SJustin T. Gibbs  *
12525689f1SJustin T. Gibbs  * User SCSI hooks added by Peter Dufault:
13525689f1SJustin T. Gibbs  *
14525689f1SJustin T. Gibbs  * Copyright (c) 1994 HD Associates
15525689f1SJustin T. Gibbs  * (contact: dufault@hda.com)
16525689f1SJustin T. Gibbs  * All rights reserved.
17525689f1SJustin T. Gibbs  *
18525689f1SJustin T. Gibbs  * Redistribution and use in source and binary forms, with or without
19525689f1SJustin T. Gibbs  * modification, are permitted provided that the following conditions
20525689f1SJustin T. Gibbs  * are met:
21525689f1SJustin T. Gibbs  * 1. Redistributions of source code must retain the above copyright
22525689f1SJustin T. Gibbs  *    notice, this list of conditions and the following disclaimer.
23525689f1SJustin T. Gibbs  * 2. Redistributions in binary form must reproduce the above copyright
24525689f1SJustin T. Gibbs  *    notice, this list of conditions and the following disclaimer in the
25525689f1SJustin T. Gibbs  *    documentation and/or other materials provided with the distribution.
26525689f1SJustin T. Gibbs  * 3. The name of HD Associates
27525689f1SJustin T. Gibbs  *    may not be used to endorse or promote products derived from this software
28525689f1SJustin T. Gibbs  *    without specific prior written permission.
29525689f1SJustin T. Gibbs  *
30525689f1SJustin T. Gibbs  * THIS SOFTWARE IS PROVIDED BY HD ASSOCIATES ``AS IS'' AND
31525689f1SJustin T. Gibbs  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32525689f1SJustin T. Gibbs  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33525689f1SJustin T. Gibbs  * ARE DISCLAIMED.  IN NO EVENT SHALL HD ASSOCIATES BE LIABLE
34525689f1SJustin T. Gibbs  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35525689f1SJustin T. Gibbs  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36525689f1SJustin T. Gibbs  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37525689f1SJustin T. Gibbs  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38525689f1SJustin T. Gibbs  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39525689f1SJustin T. Gibbs  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40525689f1SJustin T. Gibbs  * SUCH DAMAGE.
41525689f1SJustin T. Gibbs  */
42525689f1SJustin T. Gibbs /*
43525689f1SJustin T. Gibbs  * Taken from the original scsi(8) program.
44525689f1SJustin T. Gibbs  * from: scsi.c,v 1.17 1998/01/12 07:57:57 charnier Exp $";
45525689f1SJustin T. Gibbs  */
46525689f1SJustin T. Gibbs #ifndef lint
47525689f1SJustin T. Gibbs static const char rcsid[] =
48c60e19a8SKenneth D. Merry 	"$Id: modeedit.c,v 1.1 1998/09/15 06:43:02 gibbs Exp $";
49525689f1SJustin T. Gibbs #endif /* not lint */
50525689f1SJustin T. Gibbs 
51525689f1SJustin T. Gibbs #include <ctype.h>
52525689f1SJustin T. Gibbs #include <err.h>
53525689f1SJustin T. Gibbs #include <errno.h>
54525689f1SJustin T. Gibbs #include <string.h>
55525689f1SJustin T. Gibbs #include <stdlib.h>
56525689f1SJustin T. Gibbs #include <stdio.h>
57525689f1SJustin T. Gibbs #include <sys/file.h>
58525689f1SJustin T. Gibbs #include <signal.h>
59525689f1SJustin T. Gibbs #include <unistd.h>
60525689f1SJustin T. Gibbs 
61525689f1SJustin T. Gibbs #include <cam/cam.h>
62525689f1SJustin T. Gibbs #include <cam/cam_ccb.h>
63525689f1SJustin T. Gibbs #include <camlib.h>
64525689f1SJustin T. Gibbs #include "camcontrol.h"
65525689f1SJustin T. Gibbs 
66525689f1SJustin T. Gibbs int verbose = 0;
67525689f1SJustin T. Gibbs 
68525689f1SJustin T. Gibbs /* iget: Integer argument callback
69525689f1SJustin T. Gibbs  */
70525689f1SJustin T. Gibbs int
71525689f1SJustin T. Gibbs iget(void *hook, char *name)
72525689f1SJustin T. Gibbs {
73525689f1SJustin T. Gibbs 	struct get_hook *h = (struct get_hook *)hook;
74525689f1SJustin T. Gibbs 	int arg;
75525689f1SJustin T. Gibbs 
76525689f1SJustin T. Gibbs 	if (h->got >= h->argc)
77525689f1SJustin T. Gibbs 	{
78525689f1SJustin T. Gibbs 		fprintf(stderr, "Expecting an integer argument.\n");
79c60e19a8SKenneth D. Merry 		usage(0);
80525689f1SJustin T. Gibbs 		exit(1);
81525689f1SJustin T. Gibbs 	}
82525689f1SJustin T. Gibbs 	arg = strtol(h->argv[h->got], 0, 0);
83525689f1SJustin T. Gibbs 	h->got++;
84525689f1SJustin T. Gibbs 
85525689f1SJustin T. Gibbs 	if (verbose && name && *name)
86525689f1SJustin T. Gibbs 		printf("%s: %d\n", name, arg);
87525689f1SJustin T. Gibbs 
88525689f1SJustin T. Gibbs 	return arg;
89525689f1SJustin T. Gibbs }
90525689f1SJustin T. Gibbs 
91525689f1SJustin T. Gibbs /* cget: char * argument callback
92525689f1SJustin T. Gibbs  */
93525689f1SJustin T. Gibbs char *
94525689f1SJustin T. Gibbs cget(void *hook, char *name)
95525689f1SJustin T. Gibbs {
96525689f1SJustin T. Gibbs 	struct get_hook *h = (struct get_hook *)hook;
97525689f1SJustin T. Gibbs 	char *arg;
98525689f1SJustin T. Gibbs 
99525689f1SJustin T. Gibbs 	if (h->got >= h->argc)
100525689f1SJustin T. Gibbs 	{
101525689f1SJustin T. Gibbs 		fprintf(stderr, "Expecting a character pointer argument.\n");
102c60e19a8SKenneth D. Merry 		usage(0);
103525689f1SJustin T. Gibbs 		exit(1);
104525689f1SJustin T. Gibbs 	}
105525689f1SJustin T. Gibbs 	arg = h->argv[h->got];
106525689f1SJustin T. Gibbs 	h->got++;
107525689f1SJustin T. Gibbs 
108525689f1SJustin T. Gibbs 	if (verbose && name)
109525689f1SJustin T. Gibbs 		printf("cget: %s: %s", name, arg);
110525689f1SJustin T. Gibbs 
111525689f1SJustin T. Gibbs 	return arg;
112525689f1SJustin T. Gibbs }
113525689f1SJustin T. Gibbs 
114525689f1SJustin T. Gibbs /* arg_put: "put argument" callback
115525689f1SJustin T. Gibbs  */
116525689f1SJustin T. Gibbs void
117525689f1SJustin T. Gibbs arg_put(void *hook, int letter, void *arg, int count, char *name)
118525689f1SJustin T. Gibbs {
119525689f1SJustin T. Gibbs 	if (verbose && name && *name)
120525689f1SJustin T. Gibbs 		printf("%s:  ", name);
121525689f1SJustin T. Gibbs 
122525689f1SJustin T. Gibbs 	switch(letter)
123525689f1SJustin T. Gibbs 	{
124525689f1SJustin T. Gibbs 		case 'i':
125525689f1SJustin T. Gibbs 		case 'b':
126525689f1SJustin T. Gibbs 		printf("%d ", (int)arg);
127525689f1SJustin T. Gibbs 		break;
128525689f1SJustin T. Gibbs 
129525689f1SJustin T. Gibbs 		case 'c':
130525689f1SJustin T. Gibbs 		case 'z':
131525689f1SJustin T. Gibbs 		{
132525689f1SJustin T. Gibbs 			char *p;
133525689f1SJustin T. Gibbs 
134525689f1SJustin T. Gibbs 			p = malloc(count + 1);
135525689f1SJustin T. Gibbs 
136525689f1SJustin T. Gibbs 			bzero(p, count +1);
137525689f1SJustin T. Gibbs 			strncpy(p, (char *)arg, count);
138525689f1SJustin T. Gibbs 			if (letter == 'z')
139525689f1SJustin T. Gibbs 			{
140525689f1SJustin T. Gibbs 				int i;
141525689f1SJustin T. Gibbs 				for (i = count - 1; i >= 0; i--)
142525689f1SJustin T. Gibbs 					if (p[i] == ' ')
143525689f1SJustin T. Gibbs 						p[i] = 0;
144525689f1SJustin T. Gibbs 					else
145525689f1SJustin T. Gibbs 						break;
146525689f1SJustin T. Gibbs 			}
147525689f1SJustin T. Gibbs 			printf("%s ", p);
148525689f1SJustin T. Gibbs 
149525689f1SJustin T. Gibbs 			free(p);
150525689f1SJustin T. Gibbs 		}
151525689f1SJustin T. Gibbs 
152525689f1SJustin T. Gibbs 		break;
153525689f1SJustin T. Gibbs 
154525689f1SJustin T. Gibbs 		default:
155525689f1SJustin T. Gibbs 		printf("Unknown format letter: '%c'\n", letter);
156525689f1SJustin T. Gibbs 	}
157525689f1SJustin T. Gibbs 	if (verbose)
158525689f1SJustin T. Gibbs 		putchar('\n');
159525689f1SJustin T. Gibbs }
160525689f1SJustin T. Gibbs 
161525689f1SJustin T. Gibbs #define START_ENTRY '{'
162525689f1SJustin T. Gibbs #define END_ENTRY '}'
163525689f1SJustin T. Gibbs 
164525689f1SJustin T. Gibbs static void
165525689f1SJustin T. Gibbs skipwhite(FILE *f)
166525689f1SJustin T. Gibbs {
167525689f1SJustin T. Gibbs 	int c;
168525689f1SJustin T. Gibbs 
169525689f1SJustin T. Gibbs skip_again:
170525689f1SJustin T. Gibbs 
171525689f1SJustin T. Gibbs 	while (isspace(c = getc(f)))
172525689f1SJustin T. Gibbs 		;
173525689f1SJustin T. Gibbs 
174525689f1SJustin T. Gibbs 	if (c == '#') {
175525689f1SJustin T. Gibbs 		while ((c = getc(f)) != '\n' && c != EOF)
176525689f1SJustin T. Gibbs 			;
177525689f1SJustin T. Gibbs 		goto skip_again;
178525689f1SJustin T. Gibbs 	}
179525689f1SJustin T. Gibbs 
180525689f1SJustin T. Gibbs 	ungetc(c, f);
181525689f1SJustin T. Gibbs }
182525689f1SJustin T. Gibbs 
183525689f1SJustin T. Gibbs /* mode_lookup: Lookup a format description for a given page.
184525689f1SJustin T. Gibbs  */
185525689f1SJustin T. Gibbs char *mode_db = "/usr/share/misc/scsi_modes";
186525689f1SJustin T. Gibbs static char *
187525689f1SJustin T. Gibbs mode_lookup(int page)
188525689f1SJustin T. Gibbs {
189525689f1SJustin T. Gibbs 	char *new_db;
190525689f1SJustin T. Gibbs 	FILE *modes;
191525689f1SJustin T. Gibbs 	int match, next, found, c;
192525689f1SJustin T. Gibbs 	static char fmt[4096];	/* XXX This should be with strealloc */
193525689f1SJustin T. Gibbs 	int page_desc;
194525689f1SJustin T. Gibbs 	new_db = getenv("SCSI_MODES");
195525689f1SJustin T. Gibbs 
196525689f1SJustin T. Gibbs 	if (new_db)
197525689f1SJustin T. Gibbs 		mode_db = new_db;
198525689f1SJustin T. Gibbs 
199525689f1SJustin T. Gibbs 	modes = fopen(mode_db, "r");
200525689f1SJustin T. Gibbs 	if (modes == 0)
201525689f1SJustin T. Gibbs 		return 0;
202525689f1SJustin T. Gibbs 
203525689f1SJustin T. Gibbs 	next = 0;
204525689f1SJustin T. Gibbs 	found = 0;
205525689f1SJustin T. Gibbs 
206525689f1SJustin T. Gibbs 	while (!found) {
207525689f1SJustin T. Gibbs 
208525689f1SJustin T. Gibbs 		skipwhite(modes);
209525689f1SJustin T. Gibbs 
210525689f1SJustin T. Gibbs 		if (fscanf(modes, "%i", &page_desc) != 1)
211525689f1SJustin T. Gibbs 			break;
212525689f1SJustin T. Gibbs 
213525689f1SJustin T. Gibbs 		if (page_desc == page)
214525689f1SJustin T. Gibbs 			found = 1;
215525689f1SJustin T. Gibbs 
216525689f1SJustin T. Gibbs 		skipwhite(modes);
217525689f1SJustin T. Gibbs 		if (getc(modes) != START_ENTRY)
218525689f1SJustin T. Gibbs 			errx(1, "expected %c", START_ENTRY);
219525689f1SJustin T. Gibbs 
220525689f1SJustin T. Gibbs 		match = 1;
221525689f1SJustin T. Gibbs 		while (match != 0) {
222525689f1SJustin T. Gibbs 			c = getc(modes);
223525689f1SJustin T. Gibbs 			if (c == EOF) {
224525689f1SJustin T. Gibbs 				warnx("expected %c", END_ENTRY);
225525689f1SJustin T. Gibbs 			}
226525689f1SJustin T. Gibbs 
227525689f1SJustin T. Gibbs 			if (c == START_ENTRY) {
228525689f1SJustin T. Gibbs 				match++;
229525689f1SJustin T. Gibbs 			}
230525689f1SJustin T. Gibbs 			if (c == END_ENTRY) {
231525689f1SJustin T. Gibbs 				match--;
232525689f1SJustin T. Gibbs 				if (match == 0)
233525689f1SJustin T. Gibbs 					break;
234525689f1SJustin T. Gibbs 			}
235525689f1SJustin T. Gibbs 			if (found && c != '\n') {
236525689f1SJustin T. Gibbs 				if (next >= sizeof(fmt))
237525689f1SJustin T. Gibbs 					errx(1, "buffer overflow");
238525689f1SJustin T. Gibbs 
239525689f1SJustin T. Gibbs 				fmt[next++] = (u_char)c;
240525689f1SJustin T. Gibbs 			}
241525689f1SJustin T. Gibbs 		}
242525689f1SJustin T. Gibbs 	}
243525689f1SJustin T. Gibbs 	fmt[next] = 0;
244525689f1SJustin T. Gibbs 
245525689f1SJustin T. Gibbs 	return (found) ? fmt : 0;
246525689f1SJustin T. Gibbs }
247525689f1SJustin T. Gibbs 
248525689f1SJustin T. Gibbs /* -------- edit: Mode Select Editor ---------
249525689f1SJustin T. Gibbs  */
250525689f1SJustin T. Gibbs struct editinfo
251525689f1SJustin T. Gibbs {
252525689f1SJustin T. Gibbs 	int can_edit;
253525689f1SJustin T. Gibbs 	int default_value;
254525689f1SJustin T. Gibbs } editinfo[64];	/* XXX Bogus fixed size */
255525689f1SJustin T. Gibbs 
256525689f1SJustin T. Gibbs static int editind;
257525689f1SJustin T. Gibbs volatile int edit_opened;
258525689f1SJustin T. Gibbs static FILE *edit_file;
259525689f1SJustin T. Gibbs static char edit_name[L_tmpnam];
260525689f1SJustin T. Gibbs 
261525689f1SJustin T. Gibbs static inline void
262525689f1SJustin T. Gibbs edit_rewind(void)
263525689f1SJustin T. Gibbs {
264525689f1SJustin T. Gibbs 	editind = 0;
265525689f1SJustin T. Gibbs }
266525689f1SJustin T. Gibbs 
267525689f1SJustin T. Gibbs static void
268525689f1SJustin T. Gibbs edit_done(void)
269525689f1SJustin T. Gibbs {
270525689f1SJustin T. Gibbs 	int opened;
271525689f1SJustin T. Gibbs 
272525689f1SJustin T. Gibbs 	sigset_t all, prev;
273525689f1SJustin T. Gibbs 	sigfillset(&all);
274525689f1SJustin T. Gibbs 
275525689f1SJustin T. Gibbs 	(void)sigprocmask(SIG_SETMASK, &all, &prev);
276525689f1SJustin T. Gibbs 
277525689f1SJustin T. Gibbs 	opened = (int)edit_opened;
278525689f1SJustin T. Gibbs 	edit_opened = 0;
279525689f1SJustin T. Gibbs 
280525689f1SJustin T. Gibbs 	(void)sigprocmask(SIG_SETMASK, &prev, 0);
281525689f1SJustin T. Gibbs 
282525689f1SJustin T. Gibbs 	if (opened)
283525689f1SJustin T. Gibbs 	{
284525689f1SJustin T. Gibbs 		if (fclose(edit_file))
285525689f1SJustin T. Gibbs 			warn("%s", edit_name);
286525689f1SJustin T. Gibbs 		if (unlink(edit_name))
287525689f1SJustin T. Gibbs 			warn("%s", edit_name);
288525689f1SJustin T. Gibbs 	}
289525689f1SJustin T. Gibbs }
290525689f1SJustin T. Gibbs 
291525689f1SJustin T. Gibbs static void
292525689f1SJustin T. Gibbs edit_init(void)
293525689f1SJustin T. Gibbs {
294525689f1SJustin T. Gibbs 	edit_rewind();
295525689f1SJustin T. Gibbs 	if (tmpnam(edit_name) == 0)
296525689f1SJustin T. Gibbs 		errx(1, "tmpnam failed");
297525689f1SJustin T. Gibbs 	if ((edit_file = fopen(edit_name, "w")) == 0)
298525689f1SJustin T. Gibbs 		err(1, "%s", edit_name);
299525689f1SJustin T. Gibbs 	edit_opened = 1;
300525689f1SJustin T. Gibbs 
301525689f1SJustin T. Gibbs 	atexit(edit_done);
302525689f1SJustin T. Gibbs }
303525689f1SJustin T. Gibbs 
304525689f1SJustin T. Gibbs static void
305525689f1SJustin T. Gibbs edit_check(void *hook, int letter, void *arg, int count, char *name)
306525689f1SJustin T. Gibbs {
307525689f1SJustin T. Gibbs 	if (letter != 'i' && letter != 'b')
308525689f1SJustin T. Gibbs 		errx(1, "can't edit format %c", letter);
309525689f1SJustin T. Gibbs 
310525689f1SJustin T. Gibbs 	if (editind >= sizeof(editinfo) / sizeof(editinfo[0]))
311525689f1SJustin T. Gibbs 		errx(1, "edit table overflow");
312525689f1SJustin T. Gibbs 
313525689f1SJustin T. Gibbs 	editinfo[editind].can_edit = ((int)arg != 0);
314525689f1SJustin T. Gibbs 	editind++;
315525689f1SJustin T. Gibbs }
316525689f1SJustin T. Gibbs 
317525689f1SJustin T. Gibbs static void
318525689f1SJustin T. Gibbs edit_defaults(void *hook, int letter, void *arg, int count, char *name)
319525689f1SJustin T. Gibbs {
320525689f1SJustin T. Gibbs 	if (letter != 'i' && letter != 'b')
321525689f1SJustin T. Gibbs 		errx(1, "can't edit format %c", letter);
322525689f1SJustin T. Gibbs 
323525689f1SJustin T. Gibbs 	editinfo[editind].default_value = ((int)arg);
324525689f1SJustin T. Gibbs 	editind++;
325525689f1SJustin T. Gibbs }
326525689f1SJustin T. Gibbs 
327525689f1SJustin T. Gibbs static void
328525689f1SJustin T. Gibbs edit_report(void *hook, int letter, void *arg, int count, char *name)
329525689f1SJustin T. Gibbs {
330525689f1SJustin T. Gibbs 	if (editinfo[editind].can_edit) {
331525689f1SJustin T. Gibbs 		if (letter != 'i' && letter != 'b')
332525689f1SJustin T. Gibbs 			errx(1, "can't report format %c", letter);
333525689f1SJustin T. Gibbs 
334525689f1SJustin T. Gibbs 		fprintf(edit_file, "%s:  %d\n", name, (int)arg);
335525689f1SJustin T. Gibbs 	}
336525689f1SJustin T. Gibbs 
337525689f1SJustin T. Gibbs 	editind++;
338525689f1SJustin T. Gibbs }
339525689f1SJustin T. Gibbs 
340525689f1SJustin T. Gibbs static int
341525689f1SJustin T. Gibbs edit_get(void *hook, char *name)
342525689f1SJustin T. Gibbs {
343525689f1SJustin T. Gibbs 	int arg = editinfo[editind].default_value;
344525689f1SJustin T. Gibbs 
345525689f1SJustin T. Gibbs 	if (editinfo[editind].can_edit) {
346525689f1SJustin T. Gibbs 		char line[80];
347525689f1SJustin T. Gibbs 		if (fgets(line, sizeof(line), edit_file) == 0)
348525689f1SJustin T. Gibbs 			err(1, "fgets");
349525689f1SJustin T. Gibbs 
350525689f1SJustin T. Gibbs 		line[strlen(line) - 1] = 0;
351525689f1SJustin T. Gibbs 
352525689f1SJustin T. Gibbs 		if (strncmp(name, line, strlen(name)) != 0)
353525689f1SJustin T. Gibbs 			errx(1, "expected \"%s\" and read \"%s\"", name, line);
354525689f1SJustin T. Gibbs 
355525689f1SJustin T. Gibbs 		arg = strtoul(line + strlen(name) + 2, 0, 0);
356525689f1SJustin T. Gibbs 	}
357525689f1SJustin T. Gibbs 
358525689f1SJustin T. Gibbs 	editind++;
359525689f1SJustin T. Gibbs 	return arg;
360525689f1SJustin T. Gibbs }
361525689f1SJustin T. Gibbs 
362525689f1SJustin T. Gibbs static void
363525689f1SJustin T. Gibbs edit_edit(void)
364525689f1SJustin T. Gibbs {
365525689f1SJustin T. Gibbs 	char *system_line;
366525689f1SJustin T. Gibbs 	char *editor = getenv("EDITOR");
367525689f1SJustin T. Gibbs 	if (!editor)
368525689f1SJustin T. Gibbs 		editor = "vi";
369525689f1SJustin T. Gibbs 
370525689f1SJustin T. Gibbs 	fclose(edit_file);
371525689f1SJustin T. Gibbs 
372525689f1SJustin T. Gibbs 	system_line = malloc(strlen(editor) + strlen(edit_name) + 6);
373525689f1SJustin T. Gibbs 	sprintf(system_line, "%s %s", editor, edit_name);
374525689f1SJustin T. Gibbs 	system(system_line);
375525689f1SJustin T. Gibbs 	free(system_line);
376525689f1SJustin T. Gibbs 
377525689f1SJustin T. Gibbs 	if ((edit_file = fopen(edit_name, "r")) == 0)
378525689f1SJustin T. Gibbs 		err(1, "%s", edit_name);
379525689f1SJustin T. Gibbs }
380525689f1SJustin T. Gibbs 
381525689f1SJustin T. Gibbs void
382525689f1SJustin T. Gibbs mode_edit(struct cam_device *device, int page, int page_control, int dbd,
383525689f1SJustin T. Gibbs 	  int edit, int retry_count, int timeout)
384525689f1SJustin T. Gibbs {
385525689f1SJustin T. Gibbs 	int i;
386525689f1SJustin T. Gibbs 	u_char data[255];
387525689f1SJustin T. Gibbs 	u_char *mode_pars;
388525689f1SJustin T. Gibbs 	struct mode_header
389525689f1SJustin T. Gibbs 	{
390525689f1SJustin T. Gibbs 		u_char mdl;	/* Mode data length */
391525689f1SJustin T. Gibbs 		u_char medium_type;
392525689f1SJustin T. Gibbs 		u_char dev_spec_par;
393525689f1SJustin T. Gibbs 		u_char bdl;	/* Block descriptor length */
394525689f1SJustin T. Gibbs 	};
395525689f1SJustin T. Gibbs 
396525689f1SJustin T. Gibbs 	struct mode_page_header
397525689f1SJustin T. Gibbs 	{
398525689f1SJustin T. Gibbs 		u_char page_code;
399525689f1SJustin T. Gibbs 		u_char page_length;
400525689f1SJustin T. Gibbs 	};
401525689f1SJustin T. Gibbs 
402525689f1SJustin T. Gibbs 	struct mode_header *mh;
403525689f1SJustin T. Gibbs 	struct mode_page_header *mph;
404525689f1SJustin T. Gibbs 
405525689f1SJustin T. Gibbs 	char *fmt = mode_lookup(page);
406525689f1SJustin T. Gibbs 	if (!fmt && verbose) {
407525689f1SJustin T. Gibbs 		fprintf(stderr,
408525689f1SJustin T. Gibbs 		"No mode data base entry in \"%s\" for page %d; "
409525689f1SJustin T. Gibbs 		" binary %s only.\n",
410525689f1SJustin T. Gibbs 		mode_db, page, (edit ? "edit" : "display"));
411525689f1SJustin T. Gibbs 	}
412525689f1SJustin T. Gibbs 
413525689f1SJustin T. Gibbs 	if (edit) {
414525689f1SJustin T. Gibbs 		if (!fmt)
415525689f1SJustin T. Gibbs 			errx(1, "can't edit without a format");
416525689f1SJustin T. Gibbs 
417525689f1SJustin T. Gibbs 		if (page_control != 0 && page_control != 3)
418525689f1SJustin T. Gibbs 			errx(1, "it only makes sense to edit page 0 "
419525689f1SJustin T. Gibbs 			     "(current) or page 3 (saved values)");
420525689f1SJustin T. Gibbs 
421525689f1SJustin T. Gibbs 		verbose = 1;
422525689f1SJustin T. Gibbs 
423525689f1SJustin T. Gibbs 		mode_sense(device, page, 1, dbd, retry_count, timeout,
424525689f1SJustin T. Gibbs 			   data, sizeof(data));
425525689f1SJustin T. Gibbs 
426525689f1SJustin T. Gibbs 		mh = (struct mode_header *)data;
427525689f1SJustin T. Gibbs 		mph = (struct mode_page_header *)
428525689f1SJustin T. Gibbs 		(((char *)mh) + sizeof(*mh) + mh->bdl);
429525689f1SJustin T. Gibbs 
430525689f1SJustin T. Gibbs 		mode_pars = (char *)mph + sizeof(*mph);
431525689f1SJustin T. Gibbs 
432525689f1SJustin T. Gibbs 		edit_init();
433525689f1SJustin T. Gibbs 		buff_decode_visit(mode_pars, mh->mdl, fmt, edit_check, 0);
434525689f1SJustin T. Gibbs 
435525689f1SJustin T. Gibbs 		mode_sense(device, page, 0, dbd, retry_count, timeout,
436525689f1SJustin T. Gibbs 			   data, sizeof(data));
437525689f1SJustin T. Gibbs 
438525689f1SJustin T. Gibbs 		edit_rewind();
439525689f1SJustin T. Gibbs 		buff_decode_visit(mode_pars, mh->mdl, fmt, edit_defaults, 0);
440525689f1SJustin T. Gibbs 
441525689f1SJustin T. Gibbs 		edit_rewind();
442525689f1SJustin T. Gibbs 		buff_decode_visit(mode_pars, mh->mdl, fmt, edit_report, 0);
443525689f1SJustin T. Gibbs 
444525689f1SJustin T. Gibbs 		edit_edit();
445525689f1SJustin T. Gibbs 
446525689f1SJustin T. Gibbs 		edit_rewind();
447525689f1SJustin T. Gibbs 		buff_encode_visit(mode_pars, mh->mdl, fmt, edit_get, 0);
448525689f1SJustin T. Gibbs 
449525689f1SJustin T. Gibbs 		/* Eliminate block descriptors:
450525689f1SJustin T. Gibbs 		 */
451525689f1SJustin T. Gibbs 		bcopy((char *)mph, ((char *)mh) + sizeof(*mh),
452525689f1SJustin T. Gibbs 		sizeof(*mph) + mph->page_length);
453525689f1SJustin T. Gibbs 
454525689f1SJustin T. Gibbs 		mh->bdl = mh->dev_spec_par = 0;
455525689f1SJustin T. Gibbs 		mph = (struct mode_page_header *) (((char *)mh) + sizeof(*mh));
456525689f1SJustin T. Gibbs 		mode_pars = ((char *)mph) + 2;
457525689f1SJustin T. Gibbs 
458525689f1SJustin T. Gibbs #if 0
459525689f1SJustin T. Gibbs 		/* Turn this on to see what you're sending to the
460525689f1SJustin T. Gibbs 		 * device:
461525689f1SJustin T. Gibbs 		 */
462525689f1SJustin T. Gibbs 		edit_rewind();
463525689f1SJustin T. Gibbs 		buff_decode_visit(mode_pars, mh->mdl, fmt, arg_put, 0);
464525689f1SJustin T. Gibbs #endif
465525689f1SJustin T. Gibbs 
466525689f1SJustin T. Gibbs 		edit_done();
467525689f1SJustin T. Gibbs 
468525689f1SJustin T. Gibbs 		/* Make it permanent if pageselect is three.
469525689f1SJustin T. Gibbs 		 */
470525689f1SJustin T. Gibbs 
471525689f1SJustin T. Gibbs 		mph->page_code &= ~0xC0;	/* Clear PS and RESERVED */
472525689f1SJustin T. Gibbs 		mh->mdl = 0;			/* Reserved for mode select */
473525689f1SJustin T. Gibbs 
474525689f1SJustin T. Gibbs 		mode_select(device, (page_control == 3), retry_count,
475525689f1SJustin T. Gibbs 			    timeout, (u_int8_t *)mh, sizeof(*mh) + mh->bdl +
476525689f1SJustin T. Gibbs 			    sizeof(*mph) + mph->page_length);
477525689f1SJustin T. Gibbs 
478525689f1SJustin T. Gibbs 		return;
479525689f1SJustin T. Gibbs 	}
480525689f1SJustin T. Gibbs 
481525689f1SJustin T. Gibbs 	mode_sense(device, page, page_control, dbd, retry_count, timeout,
482525689f1SJustin T. Gibbs 		   data, sizeof(data));
483525689f1SJustin T. Gibbs 
484525689f1SJustin T. Gibbs 	/* Skip over the block descriptors.
485525689f1SJustin T. Gibbs 	 */
486525689f1SJustin T. Gibbs 	mh = (struct mode_header *)data;
487525689f1SJustin T. Gibbs 	mph = (struct mode_page_header *)(((char *)mh) + sizeof(*mh) + mh->bdl);
488525689f1SJustin T. Gibbs 	mode_pars = (char *)mph + sizeof(*mph);
489525689f1SJustin T. Gibbs 
490525689f1SJustin T. Gibbs 	if (!fmt) {
491525689f1SJustin T. Gibbs 		for (i = 0; i < mh->mdl; i++) {
492525689f1SJustin T. Gibbs 			printf("%02x%c",mode_pars[i],
493525689f1SJustin T. Gibbs 			       (((i + 1) % 8) == 0) ? '\n' : ' ');
494525689f1SJustin T. Gibbs 		}
495525689f1SJustin T. Gibbs 		putc('\n', stdout);
496525689f1SJustin T. Gibbs 	} else {
497525689f1SJustin T. Gibbs 		verbose = 1;
498525689f1SJustin T. Gibbs 		buff_decode_visit(mode_pars, mh->mdl, fmt, arg_put, NULL);
499525689f1SJustin T. Gibbs 	}
500525689f1SJustin T. Gibbs }
501