160
161#define START_ENTRY '{'
162#define END_ENTRY '}'
163
164static void
165skipwhite(FILE *f)
166{
167 int c;
168
169skip_again:
170
171 while (isspace(c = getc(f)))
172 ;
173
174 if (c == '#') {
175 while ((c = getc(f)) != '\n' && c != EOF)
176 ;
177 goto skip_again;
178 }
179
180 ungetc(c, f);
181}
182
183/* mode_lookup: Lookup a format description for a given page.
184 */
185char *mode_db = "/usr/share/misc/scsi_modes";
186static char *
187mode_lookup(int page)
188{
189 char *new_db;
190 FILE *modes;
191 int match, next, found, c;
192 static char fmt[4096]; /* XXX This should be with strealloc */
193 int page_desc;
194 new_db = getenv("SCSI_MODES");
195
196 if (new_db)
197 mode_db = new_db;
198
199 modes = fopen(mode_db, "r");
200 if (modes == 0)
201 return 0;
202
203 next = 0;
204 found = 0;
205
206 while (!found) {
207
208 skipwhite(modes);
209
210 if (fscanf(modes, "%i", &page_desc) != 1)
211 break;
212
213 if (page_desc == page)
214 found = 1;
215
216 skipwhite(modes);
217 if (getc(modes) != START_ENTRY)
218 errx(1, "expected %c", START_ENTRY);
219
220 match = 1;
221 while (match != 0) {
222 c = getc(modes);
223 if (c == EOF) {
224 warnx("expected %c", END_ENTRY);
225 }
226
227 if (c == START_ENTRY) {
228 match++;
229 }
230 if (c == END_ENTRY) {
231 match--;
232 if (match == 0)
233 break;
234 }
235 if (found && c != '\n') {
236 if (next >= sizeof(fmt))
237 errx(1, "buffer overflow");
238
239 fmt[next++] = (u_char)c;
240 }
241 }
242 }
243 fmt[next] = 0;
244
245 return (found) ? fmt : 0;
246}
247
248/* -------- edit: Mode Select Editor ---------
249 */
250struct editinfo
251{
252 int can_edit;
253 int default_value;
254} editinfo[64]; /* XXX Bogus fixed size */
255
256static int editind;
257volatile int edit_opened;
258static FILE *edit_file;
259static char edit_name[L_tmpnam];
260
261static inline void
262edit_rewind(void)
263{
264 editind = 0;
265}
266
267static void
268edit_done(void)
269{
270 int opened;
271
272 sigset_t all, prev;
273 sigfillset(&all);
274
275 (void)sigprocmask(SIG_SETMASK, &all, &prev);
276
277 opened = (int)edit_opened;
278 edit_opened = 0;
279
280 (void)sigprocmask(SIG_SETMASK, &prev, 0);
281
282 if (opened)
283 {
284 if (fclose(edit_file))
285 warn("%s", edit_name);
286 if (unlink(edit_name))
287 warn("%s", edit_name);
288 }
289}
290
291static void
292edit_init(void)
293{
294 int fd;
295
296 edit_rewind();
297 strlcpy(edit_name, "/tmp/camXXXXXX", sizeof(edit_name));
298 if ((fd = mkstemp(edit_name)) == -1)
299 errx(1, "mkstemp failed");
300 if ((edit_file = fdopen(fd, "w")) == 0)
301 err(1, "%s", edit_name);
302 edit_opened = 1;
303
304 atexit(edit_done);
305}
306
307static void
308edit_check(void *hook, int letter, void *arg, int count, char *name)
309{
310 if (letter != 'i' && letter != 'b')
311 errx(1, "can't edit format %c", letter);
312
313 if (editind >= sizeof(editinfo) / sizeof(editinfo[0]))
314 errx(1, "edit table overflow");
315
316 editinfo[editind].can_edit = (arg != NULL);
317 editind++;
318}
319
320static void
321edit_defaults(void *hook, int letter, void *arg, int count, char *name)
322{
323 if (letter != 'i' && letter != 'b')
324 errx(1, "can't edit format %c", letter);
325
326 editinfo[editind].default_value = (intptr_t)arg; /* truncated */
327 editind++;
328}
329
330static void
331edit_report(void *hook, int letter, void *arg, int count, char *name)
332{
333 if (editinfo[editind].can_edit) {
334 if (letter != 'i' && letter != 'b')
335 errx(1, "can't report format %c", letter);
336
337 fprintf(edit_file, "%s: %d\n", name, (intptr_t)arg);
338 }
339
340 editind++;
341}
342
343static int
344edit_get(void *hook, char *name)
345{
346 int arg = editinfo[editind].default_value;
347
348 if (editinfo[editind].can_edit) {
349 char line[80];
350 if (fgets(line, sizeof(line), edit_file) == 0)
351 err(1, "fgets");
352
353 line[strlen(line) - 1] = 0;
354
355 if (strncmp(name, line, strlen(name)) != 0)
356 errx(1, "expected \"%s\" and read \"%s\"", name, line);
357
358 arg = strtoul(line + strlen(name) + 2, 0, 0);
359 }
360
361 editind++;
362 return arg;
363}
364
365static void
366edit_edit(void)
367{
368 char *system_line;
369 char *editor = getenv("EDITOR");
370 if (!editor)
371 editor = "vi";
372
373 fclose(edit_file);
374
375 system_line = malloc(strlen(editor) + strlen(edit_name) + 6);
376 sprintf(system_line, "%s %s", editor, edit_name);
377 system(system_line);
378 free(system_line);
379
380 if ((edit_file = fopen(edit_name, "r")) == 0)
381 err(1, "%s", edit_name);
382}
383
384void
385mode_edit(struct cam_device *device, int page, int page_control, int dbd,
386 int edit, int retry_count, int timeout)
387{
388 int i;
389 u_char data[255];
390 u_char *mode_pars;
391 struct mode_header
392 {
393 u_char mdl; /* Mode data length */
394 u_char medium_type;
395 u_char dev_spec_par;
396 u_char bdl; /* Block descriptor length */
397 };
398
399 struct mode_page_header
400 {
401 u_char page_code;
402 u_char page_length;
403 };
404
405 struct mode_header *mh;
406 struct mode_page_header *mph;
407
408 char *fmt = mode_lookup(page);
409 if (!fmt && verbose) {
410 fprintf(stderr,
411 "No mode data base entry in \"%s\" for page %d; "
412 " binary %s only.\n",
413 mode_db, page, (edit ? "edit" : "display"));
414 }
415
416 if (edit) {
417 if (!fmt)
418 errx(1, "can't edit without a format");
419
420 if (page_control != 0 && page_control != 3)
421 errx(1, "it only makes sense to edit page 0 "
422 "(current) or page 3 (saved values)");
423
424 verbose = 1;
425
426 mode_sense(device, page, 1, dbd, retry_count, timeout,
427 data, sizeof(data));
428
429 mh = (struct mode_header *)data;
430 mph = (struct mode_page_header *)
431 (((char *)mh) + sizeof(*mh) + mh->bdl);
432
433 mode_pars = (char *)mph + sizeof(*mph);
434
435 edit_init();
436 buff_decode_visit(mode_pars, mh->mdl, fmt, edit_check, 0);
437
438 mode_sense(device, page, 0, dbd, retry_count, timeout,
439 data, sizeof(data));
440
441 edit_rewind();
442 buff_decode_visit(mode_pars, mh->mdl, fmt, edit_defaults, 0);
443
444 edit_rewind();
445 buff_decode_visit(mode_pars, mh->mdl, fmt, edit_report, 0);
446
447 edit_edit();
448
449 edit_rewind();
450 buff_encode_visit(mode_pars, mh->mdl, fmt, edit_get, 0);
451
452 /* Eliminate block descriptors:
453 */
454 bcopy((char *)mph, ((char *)mh) + sizeof(*mh),
455 sizeof(*mph) + mph->page_length);
456
457 mh->bdl = mh->dev_spec_par = 0;
458 mph = (struct mode_page_header *) (((char *)mh) + sizeof(*mh));
459 mode_pars = ((char *)mph) + 2;
460
461#if 0
462 /* Turn this on to see what you're sending to the
463 * device:
464 */
465 edit_rewind();
466 buff_decode_visit(mode_pars, mh->mdl, fmt, arg_put, 0);
467#endif
468
469 edit_done();
470
471 /* Make it permanent if pageselect is three.
472 */
473
474 mph->page_code &= ~0xC0; /* Clear PS and RESERVED */
475 mh->mdl = 0; /* Reserved for mode select */
476
477 mode_select(device, (page_control == 3), retry_count,
478 timeout, (u_int8_t *)mh, sizeof(*mh) + mh->bdl +
479 sizeof(*mph) + mph->page_length);
480
481 return;
482 }
483
484 mode_sense(device, page, page_control, dbd, retry_count, timeout,
485 data, sizeof(data));
486
487 /* Skip over the block descriptors.
488 */
489 mh = (struct mode_header *)data;
490 mph = (struct mode_page_header *)(((char *)mh) + sizeof(*mh) + mh->bdl);
491 mode_pars = (char *)mph + sizeof(*mph);
492
493 if (!fmt) {
494 for (i = 0; i < mh->mdl; i++) {
495 printf("%02x%c",mode_pars[i],
496 (((i + 1) % 8) == 0) ? '\n' : ' ');
497 }
498 putc('\n', stdout);
499 } else {
500 verbose = 1;
501 buff_decode_visit(mode_pars, mh->mdl, fmt, arg_put, NULL);
502 }
503}
|