util.c revision 39214
1175383Sjhb/* 2175383Sjhb * Written By Julian ELischer 3175383Sjhb * Copyright julian Elischer 1993. 4175383Sjhb * Permission is granted to use or redistribute this file in any way as long 5175383Sjhb * as this notice remains. Julian Elischer does not guarantee that this file 6175383Sjhb * is totally correct for any given task and users of this file must 7175383Sjhb * accept responsibility for any damage that occurs from the application of this 8175383Sjhb * file. 9175383Sjhb * 10175383Sjhb * (julian@tfs.com julian@dialix.oz.au) 11175383Sjhb * 12175383Sjhb * User SCSI hooks added by Peter Dufault: 13175383Sjhb * 14175383Sjhb * Copyright (c) 1994 HD Associates 15175383Sjhb * (contact: dufault@hda.com) 16175383Sjhb * All rights reserved. 17175383Sjhb * 18175383Sjhb * Redistribution and use in source and binary forms, with or without 19175383Sjhb * modification, are permitted provided that the following conditions 20175383Sjhb * are met: 21175383Sjhb * 1. Redistributions of source code must retain the above copyright 22175383Sjhb * notice, this list of conditions and the following disclaimer. 23175383Sjhb * 2. Redistributions in binary form must reproduce the above copyright 24175383Sjhb * notice, this list of conditions and the following disclaimer in the 25175383Sjhb * documentation and/or other materials provided with the distribution. 26175383Sjhb * 3. The name of HD Associates 27175383Sjhb * may not be used to endorse or promote products derived from this software 28175383Sjhb * without specific prior written permission. 29175383Sjhb * 30175383Sjhb * THIS SOFTWARE IS PROVIDED BY HD ASSOCIATES ``AS IS'' AND 31175383Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 32175383Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 33175383Sjhb * ARE DISCLAIMED. IN NO EVENT SHALL HD ASSOCIATES BE LIABLE 34175383Sjhb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 35175383Sjhb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 36175383Sjhb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 37175383Sjhb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 38175383Sjhb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 39175383Sjhb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 40175383Sjhb * SUCH DAMAGE. 41175383Sjhb */ 42175383Sjhb/* 43175383Sjhb * Taken from the original scsi(8) program. 44175383Sjhb * from: scsi.c,v 1.17 1998/01/12 07:57:57 charnier Exp $"; 45175383Sjhb */ 46175383Sjhb#ifndef lint 47175383Sjhbstatic const char rcsid[] = 48175383Sjhb "$Id$"; 49175383Sjhb#endif /* not lint */ 50175383Sjhb 51175383Sjhb#include <ctype.h> 52175383Sjhb#include <err.h> 53175383Sjhb#include <errno.h> 54175383Sjhb#include <string.h> 55175383Sjhb#include <stdlib.h> 56175383Sjhb#include <stdio.h> 57175383Sjhb#include <sys/file.h> 58175383Sjhb#include <signal.h> 59175383Sjhb#include <unistd.h> 60175383Sjhb 61175383Sjhb#include <cam/cam.h> 62175383Sjhb#include <cam/cam_ccb.h> 63175383Sjhb#include <camlib.h> 64175383Sjhb#include "camcontrol.h" 65175383Sjhb 66175383Sjhbint verbose = 0; 67175383Sjhb 68175383Sjhb/* iget: Integer argument callback 69175383Sjhb */ 70175383Sjhbint 71175383Sjhbiget(void *hook, char *name) 72175383Sjhb{ 73175383Sjhb struct get_hook *h = (struct get_hook *)hook; 74175383Sjhb int arg; 75175383Sjhb 76175383Sjhb if (h->got >= h->argc) 77175383Sjhb { 78175383Sjhb fprintf(stderr, "Expecting an integer argument.\n"); 79175383Sjhb usage(); 80175383Sjhb exit(1); 81175383Sjhb } 82175383Sjhb arg = strtol(h->argv[h->got], 0, 0); 83175383Sjhb h->got++; 84175383Sjhb 85175383Sjhb if (verbose && name && *name) 86175383Sjhb printf("%s: %d\n", name, arg); 87175383Sjhb 88175383Sjhb return arg; 89175383Sjhb} 90175383Sjhb 91175383Sjhb/* cget: char * argument callback 92175383Sjhb */ 93175383Sjhbchar * 94175383Sjhbcget(void *hook, char *name) 95175383Sjhb{ 96175383Sjhb struct get_hook *h = (struct get_hook *)hook; 97175383Sjhb char *arg; 98175383Sjhb 99175383Sjhb if (h->got >= h->argc) 100175383Sjhb { 101175383Sjhb fprintf(stderr, "Expecting a character pointer argument.\n"); 102175383Sjhb usage(); 103175383Sjhb exit(1); 104175383Sjhb } 105175383Sjhb arg = h->argv[h->got]; 106175383Sjhb h->got++; 107175383Sjhb 108175383Sjhb if (verbose && name) 109175383Sjhb printf("cget: %s: %s", name, arg); 110175383Sjhb 111175383Sjhb return arg; 112175383Sjhb} 113175383Sjhb 114175383Sjhb/* arg_put: "put argument" callback 115175383Sjhb */ 116175383Sjhbvoid 117175383Sjhbarg_put(void *hook, int letter, void *arg, int count, char *name) 118180036Sjhb{ 119175383Sjhb if (verbose && name && *name) 120175383Sjhb printf("%s: ", name); 121175383Sjhb 122175383Sjhb switch(letter) 123175383Sjhb { 124175383Sjhb case 'i': 125175383Sjhb case 'b': 126175383Sjhb printf("%d ", (int)arg); 127175383Sjhb break; 128175383Sjhb 129 case 'c': 130 case 'z': 131 { 132 char *p; 133 134 p = malloc(count + 1); 135 136 bzero(p, count +1); 137 strncpy(p, (char *)arg, count); 138 if (letter == 'z') 139 { 140 int i; 141 for (i = count - 1; i >= 0; i--) 142 if (p[i] == ' ') 143 p[i] = 0; 144 else 145 break; 146 } 147 printf("%s ", p); 148 149 free(p); 150 } 151 152 break; 153 154 default: 155 printf("Unknown format letter: '%c'\n", letter); 156 } 157 if (verbose) 158 putchar('\n'); 159} 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 edit_rewind(); 295 if (tmpnam(edit_name) == 0) 296 errx(1, "tmpnam failed"); 297 if ((edit_file = fopen(edit_name, "w")) == 0) 298 err(1, "%s", edit_name); 299 edit_opened = 1; 300 301 atexit(edit_done); 302} 303 304static void 305edit_check(void *hook, int letter, void *arg, int count, char *name) 306{ 307 if (letter != 'i' && letter != 'b') 308 errx(1, "can't edit format %c", letter); 309 310 if (editind >= sizeof(editinfo) / sizeof(editinfo[0])) 311 errx(1, "edit table overflow"); 312 313 editinfo[editind].can_edit = ((int)arg != 0); 314 editind++; 315} 316 317static void 318edit_defaults(void *hook, int letter, void *arg, int count, char *name) 319{ 320 if (letter != 'i' && letter != 'b') 321 errx(1, "can't edit format %c", letter); 322 323 editinfo[editind].default_value = ((int)arg); 324 editind++; 325} 326 327static void 328edit_report(void *hook, int letter, void *arg, int count, char *name) 329{ 330 if (editinfo[editind].can_edit) { 331 if (letter != 'i' && letter != 'b') 332 errx(1, "can't report format %c", letter); 333 334 fprintf(edit_file, "%s: %d\n", name, (int)arg); 335 } 336 337 editind++; 338} 339 340static int 341edit_get(void *hook, char *name) 342{ 343 int arg = editinfo[editind].default_value; 344 345 if (editinfo[editind].can_edit) { 346 char line[80]; 347 if (fgets(line, sizeof(line), edit_file) == 0) 348 err(1, "fgets"); 349 350 line[strlen(line) - 1] = 0; 351 352 if (strncmp(name, line, strlen(name)) != 0) 353 errx(1, "expected \"%s\" and read \"%s\"", name, line); 354 355 arg = strtoul(line + strlen(name) + 2, 0, 0); 356 } 357 358 editind++; 359 return arg; 360} 361 362static void 363edit_edit(void) 364{ 365 char *system_line; 366 char *editor = getenv("EDITOR"); 367 if (!editor) 368 editor = "vi"; 369 370 fclose(edit_file); 371 372 system_line = malloc(strlen(editor) + strlen(edit_name) + 6); 373 sprintf(system_line, "%s %s", editor, edit_name); 374 system(system_line); 375 free(system_line); 376 377 if ((edit_file = fopen(edit_name, "r")) == 0) 378 err(1, "%s", edit_name); 379} 380 381void 382mode_edit(struct cam_device *device, int page, int page_control, int dbd, 383 int edit, int retry_count, int timeout) 384{ 385 int i; 386 u_char data[255]; 387 u_char *mode_pars; 388 struct mode_header 389 { 390 u_char mdl; /* Mode data length */ 391 u_char medium_type; 392 u_char dev_spec_par; 393 u_char bdl; /* Block descriptor length */ 394 }; 395 396 struct mode_page_header 397 { 398 u_char page_code; 399 u_char page_length; 400 }; 401 402 struct mode_header *mh; 403 struct mode_page_header *mph; 404 405 char *fmt = mode_lookup(page); 406 if (!fmt && verbose) { 407 fprintf(stderr, 408 "No mode data base entry in \"%s\" for page %d; " 409 " binary %s only.\n", 410 mode_db, page, (edit ? "edit" : "display")); 411 } 412 413 if (edit) { 414 if (!fmt) 415 errx(1, "can't edit without a format"); 416 417 if (page_control != 0 && page_control != 3) 418 errx(1, "it only makes sense to edit page 0 " 419 "(current) or page 3 (saved values)"); 420 421 verbose = 1; 422 423 mode_sense(device, page, 1, dbd, retry_count, timeout, 424 data, sizeof(data)); 425 426 mh = (struct mode_header *)data; 427 mph = (struct mode_page_header *) 428 (((char *)mh) + sizeof(*mh) + mh->bdl); 429 430 mode_pars = (char *)mph + sizeof(*mph); 431 432 edit_init(); 433 buff_decode_visit(mode_pars, mh->mdl, fmt, edit_check, 0); 434 435 mode_sense(device, page, 0, dbd, retry_count, timeout, 436 data, sizeof(data)); 437 438 edit_rewind(); 439 buff_decode_visit(mode_pars, mh->mdl, fmt, edit_defaults, 0); 440 441 edit_rewind(); 442 buff_decode_visit(mode_pars, mh->mdl, fmt, edit_report, 0); 443 444 edit_edit(); 445 446 edit_rewind(); 447 buff_encode_visit(mode_pars, mh->mdl, fmt, edit_get, 0); 448 449 /* Eliminate block descriptors: 450 */ 451 bcopy((char *)mph, ((char *)mh) + sizeof(*mh), 452 sizeof(*mph) + mph->page_length); 453 454 mh->bdl = mh->dev_spec_par = 0; 455 mph = (struct mode_page_header *) (((char *)mh) + sizeof(*mh)); 456 mode_pars = ((char *)mph) + 2; 457 458#if 0 459 /* Turn this on to see what you're sending to the 460 * device: 461 */ 462 edit_rewind(); 463 buff_decode_visit(mode_pars, mh->mdl, fmt, arg_put, 0); 464#endif 465 466 edit_done(); 467 468 /* Make it permanent if pageselect is three. 469 */ 470 471 mph->page_code &= ~0xC0; /* Clear PS and RESERVED */ 472 mh->mdl = 0; /* Reserved for mode select */ 473 474 mode_select(device, (page_control == 3), retry_count, 475 timeout, (u_int8_t *)mh, sizeof(*mh) + mh->bdl + 476 sizeof(*mph) + mph->page_length); 477 478 return; 479 } 480 481 mode_sense(device, page, page_control, dbd, retry_count, timeout, 482 data, sizeof(data)); 483 484 /* Skip over the block descriptors. 485 */ 486 mh = (struct mode_header *)data; 487 mph = (struct mode_page_header *)(((char *)mh) + sizeof(*mh) + mh->bdl); 488 mode_pars = (char *)mph + sizeof(*mph); 489 490 if (!fmt) { 491 for (i = 0; i < mh->mdl; i++) { 492 printf("%02x%c",mode_pars[i], 493 (((i + 1) % 8) == 0) ? '\n' : ' '); 494 } 495 putc('\n', stdout); 496 } else { 497 verbose = 1; 498 buff_decode_visit(mode_pars, mh->mdl, fmt, arg_put, NULL); 499 } 500} 501