util.c revision 56384
192108Sphk/* 292108Sphk * Written By Julian ELischer 392108Sphk * Copyright julian Elischer 1993. 492108Sphk * Permission is granted to use or redistribute this file in any way as long 592108Sphk * as this notice remains. Julian Elischer does not guarantee that this file 692108Sphk * is totally correct for any given task and users of this file must 792108Sphk * accept responsibility for any damage that occurs from the application of this 892108Sphk * file. 992108Sphk * 1092108Sphk * (julian@tfs.com julian@dialix.oz.au) 1192108Sphk * 1292108Sphk * User SCSI hooks added by Peter Dufault: 1392108Sphk * 1492108Sphk * Copyright (c) 1994 HD Associates 1592108Sphk * (contact: dufault@hda.com) 1692108Sphk * All rights reserved. 1792108Sphk * 1892108Sphk * Redistribution and use in source and binary forms, with or without 1992108Sphk * modification, are permitted provided that the following conditions 2092108Sphk * are met: 2192108Sphk * 1. Redistributions of source code must retain the above copyright 2292108Sphk * notice, this list of conditions and the following disclaimer. 2392108Sphk * 2. Redistributions in binary form must reproduce the above copyright 2492108Sphk * notice, this list of conditions and the following disclaimer in the 2592108Sphk * documentation and/or other materials provided with the distribution. 2692108Sphk * 3. The name of HD Associates 2792108Sphk * may not be used to endorse or promote products derived from this software 2892108Sphk * without specific prior written permission. 2992108Sphk * 3092108Sphk * THIS SOFTWARE IS PROVIDED BY HD ASSOCIATES ``AS IS'' AND 3192108Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 3292108Sphk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 3392108Sphk * ARE DISCLAIMED. IN NO EVENT SHALL HD ASSOCIATES BE LIABLE 3492108Sphk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3592108Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 36116196Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 37116196Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 38116196Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 39104519Sphk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 40104519Sphk * SUCH DAMAGE. 4192108Sphk */ 4292108Sphk/* 4392108Sphk * Taken from the original scsi(8) program. 4492108Sphk * from: scsi.c,v 1.17 1998/01/12 07:57:57 charnier Exp $"; 4592108Sphk */ 46196823Spjd#ifndef lint 47110119Sphkstatic const char rcsid[] = 4892108Sphk "$FreeBSD: head/sbin/camcontrol/util.c 56384 2000-01-21 23:19:30Z mjacob $"; 49223921Sae#endif /* not lint */ 50111979Sphk 5192108Sphk#include <ctype.h> 5292108Sphk#include <err.h> 5392108Sphk#include <errno.h> 5492108Sphk#include <string.h> 5592108Sphk#include <stdlib.h> 56112952Sphk#include <stdio.h> 57112476Sphk#include <sys/file.h> 5892108Sphk#include <signal.h> 59219970Smav#include <unistd.h> 60219970Smav 61292348Sken#include <cam/cam.h> 62292348Sken#include <cam/cam_ccb.h> 63219970Smav#include <camlib.h> 64248694Smav#include "camcontrol.h" 65219970Smav 66219970Smavint verbose = 0; 67219970Smav 68219970Smav/* iget: Integer argument callback 69219970Smav */ 70260385Sscottlint 71219970Smaviget(void *hook, char *name) 72219970Smav{ 7392108Sphk struct get_hook *h = (struct get_hook *)hook; 74133314Sphk int arg; 75133314Sphk 76133314Sphk if (h->got >= h->argc) 77237518Sken { 7892108Sphk fprintf(stderr, "Expecting an integer argument.\n"); 79141624Sphk usage(0); 80249507Sivoras exit(1); 81133318Sphk } 82133314Sphk arg = strtol(h->argv[h->got], 0, 0); 83133314Sphk h->got++; 84133314Sphk 85237518Sken if (verbose && name && *name) 86133314Sphk printf("%s: %d\n", name, arg); 8792108Sphk 8892108Sphk return arg; 89219970Smav} 90227309Sed 91227309Sed/* cget: char * argument callback 92219970Smav */ 93115473Sphkchar * 94115473Sphkcget(void *hook, char *name) 95110052Sphk{ 96110052Sphk struct get_hook *h = (struct get_hook *)hook; 97110052Sphk char *arg; 98226736Spjd 99125975Sphk if (h->got >= h->argc) 100125975Sphk { 101110052Sphk fprintf(stderr, "Expecting a character pointer argument.\n"); 102110052Sphk usage(0); 103110052Sphk exit(1); 104110052Sphk } 105110052Sphk arg = h->argv[h->got]; 106226736Spjd h->got++; 107125975Sphk 108125975Sphk if (verbose && name) 109110052Sphk printf("cget: %s: %s", name, arg); 110110052Sphk 11192108Sphk return arg; 11292108Sphk} 11392108Sphk 11492108Sphk/* arg_put: "put argument" callback 115219970Smav */ 11692108Sphkvoid 11792108Sphkarg_put(void *hook, int letter, void *arg, int count, char *name) 11892108Sphk{ 11992108Sphk if (verbose && name && *name) 12092108Sphk printf("%s: ", name); 121248694Smav 122219970Smav switch(letter) 123125539Spjd { 124125539Spjd case 'i': 125125539Spjd case 'b': 126125539Spjd printf("%d ", (intptr_t)arg); 127125539Spjd break; 128125539Spjd 129125975Sphk case 'c': 130125539Spjd case 'z': 13192108Sphk { 13292108Sphk char *p; 13392108Sphk 134110119Sphk p = malloc(count + 1); 13592108Sphk 136111668Sphk bzero(p, count +1); 137110119Sphk strncpy(p, (char *)arg, count); 138111668Sphk if (letter == 'z') 139166861Sn_hibma { 140110119Sphk int i; 141110119Sphk for (i = count - 1; i >= 0; i--) 142110119Sphk if (p[i] == ' ') 143251616Smav p[i] = 0; 144251616Smav else 145110119Sphk break; 146105551Sphk } 147105551Sphk printf("%s ", p); 148110727Sphk 149110727Sphk free(p); 150110727Sphk } 151110727Sphk 152110727Sphk break; 153252657Ssmh 154252657Ssmh default: 155252657Ssmh printf("Unknown format letter: '%c'\n", letter); 156252657Ssmh } 157249940Ssmh if (verbose) 158252657Ssmh putchar('\n'); 159249940Ssmh} 160249940Ssmh 161249940Ssmh#define START_ENTRY '{' 162249940Ssmh#define END_ENTRY '}' 16392108Sphk 164111668Sphkstatic void 165110119Sphkskipwhite(FILE *f) 166111668Sphk{ 167110119Sphk int c; 168110119Sphk 169110119Sphkskip_again: 170110119Sphk 171110119Sphk while (isspace(c = getc(f))) 172219970Smav ; 173219970Smav 174219970Smav if (c == '#') { 175110119Sphk while ((c = getc(f)) != '\n' && c != EOF) 17692108Sphk ; 17792108Sphk goto skip_again; 17892108Sphk } 17992108Sphk 18092108Sphk ungetc(c, f); 18195038Sphk} 182219950Smav 18395038Sphk/* mode_lookup: Lookup a format description for a given page. 184104450Sphk */ 18595038Sphkchar *mode_db = "/usr/share/misc/scsi_modes"; 18695038Sphkstatic char * 187104450Sphkmode_lookup(int page) 188264712Sbdrewery{ 189104450Sphk char *new_db; 190120572Sphk FILE *modes; 191120572Sphk int match, next, found, c; 192120572Sphk static char fmt[4096]; /* XXX This should be with strealloc */ 193120572Sphk int page_desc; 194219950Smav new_db = getenv("SCSI_MODES"); 195219950Smav 196219950Smav if (new_db) 197219950Smav mode_db = new_db; 198219950Smav 199140968Sphk modes = fopen(mode_db, "r"); 200140968Sphk if (modes == 0) 201219950Smav return 0; 202219950Smav 20395038Sphk next = 0; 20495038Sphk found = 0; 20595038Sphk 206219970Smav while (!found) { 207219970Smav 208219970Smav skipwhite(modes); 209219970Smav 210219970Smav if (fscanf(modes, "%i", &page_desc) != 1) 211219970Smav break; 212219970Smav 213219970Smav if (page_desc == page) 214219970Smav found = 1; 215219970Smav 216219970Smav skipwhite(modes); 217219970Smav if (getc(modes) != START_ENTRY) 218219970Smav errx(1, "expected %c", START_ENTRY); 219219970Smav 220219970Smav match = 1; 221219970Smav while (match != 0) { 222219970Smav c = getc(modes); 223219970Smav if (c == EOF) { 224219970Smav warnx("expected %c", END_ENTRY); 225219970Smav } 226219970Smav 227219970Smav if (c == START_ENTRY) { 228219970Smav match++; 229219970Smav } 230219970Smav if (c == END_ENTRY) { 231219970Smav match--; 23292108Sphk if (match == 0) 23392108Sphk break; 234260385Sscottl } 235111979Sphk if (found && c != '\n') { 236219970Smav if (next >= sizeof(fmt)) 23792108Sphk errx(1, "buffer overflow"); 238110720Sphk 239110720Sphk fmt[next++] = (u_char)c; 240248694Smav } 241248694Smav } 24292108Sphk } 243260385Sscottl fmt[next] = 0; 244248694Smav 245111979Sphk return (found) ? fmt : 0; 246111979Sphk} 247111979Sphk 248266608Smav/* -------- edit: Mode Select Editor --------- 249260385Sscottl */ 250111979Sphkstruct editinfo 251111979Sphk{ 252260385Sscottl int can_edit; 253112259Sphk int default_value; 254111979Sphk} editinfo[64]; /* XXX Bogus fixed size */ 255260385Sscottl 256260385Sscottlstatic int editind; 257260385Sscottlvolatile int edit_opened; 258260385Sscottlstatic FILE *edit_file; 259260385Sscottlstatic char edit_name[L_tmpnam]; 260119660Sphk 261138732Sphkstatic inline void 262119660Sphkedit_rewind(void) 263119660Sphk{ 264219970Smav editind = 0; 265119660Sphk} 266119660Sphk 267248694Smavstatic void 268219970Smavedit_done(void) 269119660Sphk{ 270119660Sphk int opened; 271119660Sphk 272119660Sphk sigset_t all, prev; 273138732Sphk sigfillset(&all); 274119660Sphk 275226736Spjd (void)sigprocmask(SIG_SETMASK, &all, &prev); 276119660Sphk 277119660Sphk opened = (int)edit_opened; 278292348Sken edit_opened = 0; 279292348Sken 280292348Sken (void)sigprocmask(SIG_SETMASK, &prev, 0); 281292348Sken 282292348Sken if (opened) 283292348Sken { 284292348Sken if (fclose(edit_file)) 285292348Sken warn("%s", edit_name); 286292348Sken if (unlink(edit_name)) 287292348Sken warn("%s", edit_name); 288292348Sken } 289292348Sken} 290292348Sken 291292348Skenstatic void 29292108Sphkedit_init(void) 293292348Sken{ 294292348Sken int fd; 295292348Sken 296292348Sken edit_rewind(); 297292348Sken strlcpy(edit_name, "/tmp/camXXXXXX", sizeof(edit_name)); 298292348Sken if ((fd = mkstemp(edit_name)) == -1) 299292348Sken errx(1, "mkstemp failed"); 300292348Sken if ((edit_file = fdopen(fd, "w")) == 0) 301292348Sken err(1, "%s", edit_name); 302292348Sken edit_opened = 1; 303292348Sken 304292348Sken atexit(edit_done); 305292348Sken} 306292348Sken 307292348Skenstatic void 308292348Skenedit_check(void *hook, int letter, void *arg, int count, char *name) 309292348Sken{ 310292348Sken if (letter != 'i' && letter != 'b') 311292348Sken errx(1, "can't edit format %c", letter); 312292348Sken 313292348Sken if (editind >= sizeof(editinfo) / sizeof(editinfo[0])) 314292348Sken errx(1, "edit table overflow"); 315292348Sken 316292348Sken editinfo[editind].can_edit = (arg != NULL); 317292348Sken editind++; 318292348Sken} 319292348Sken 320292348Skenstatic void 321292348Skenedit_defaults(void *hook, int letter, void *arg, int count, char *name) 322292348Sken{ 323292348Sken if (letter != 'i' && letter != 'b') 324292348Sken errx(1, "can't edit format %c", letter); 325292348Sken 326292348Sken editinfo[editind].default_value = (intptr_t)arg; /* truncated */ 327292348Sken editind++; 328292348Sken} 329292348Sken 330292348Skenstatic void 331292348Skenedit_report(void *hook, int letter, void *arg, int count, char *name) 332292348Sken{ 333292348Sken if (editinfo[editind].can_edit) { 334292348Sken if (letter != 'i' && letter != 'b') 335292348Sken errx(1, "can't report format %c", letter); 336292348Sken 337292348Sken fprintf(edit_file, "%s: %d\n", name, (intptr_t)arg); 338292348Sken } 339292348Sken 340292348Sken editind++; 341292348Sken} 342292348Sken 343292348Skenstatic int 344292348Skenedit_get(void *hook, char *name) 345292348Sken{ 346292348Sken int arg = editinfo[editind].default_value; 347292348Sken 348292348Sken if (editinfo[editind].can_edit) { 349292348Sken char line[80]; 350292348Sken if (fgets(line, sizeof(line), edit_file) == 0) 351292348Sken err(1, "fgets"); 352292348Sken 353292348Sken line[strlen(line) - 1] = 0; 354292348Sken 355292348Sken if (strncmp(name, line, strlen(name)) != 0) 356292348Sken errx(1, "expected \"%s\" and read \"%s\"", name, line); 357292348Sken 358292348Sken arg = strtoul(line + strlen(name) + 2, 0, 0); 359292348Sken } 360292348Sken 361292348Sken editind++; 362292348Sken return arg; 363292348Sken} 364292348Sken 365292348Skenstatic void 366292348Skenedit_edit(void) 367292348Sken{ 368292348Sken char *system_line; 369292348Sken char *editor = getenv("EDITOR"); 370292348Sken if (!editor) 371292348Sken editor = "vi"; 372292348Sken 373292348Sken fclose(edit_file); 374292348Sken 375292348Sken system_line = malloc(strlen(editor) + strlen(edit_name) + 6); 376292348Sken sprintf(system_line, "%s %s", editor, edit_name); 377292348Sken system(system_line); 378292348Sken free(system_line); 379292348Sken 380292348Sken if ((edit_file = fopen(edit_name, "r")) == 0) 381292348Sken err(1, "%s", edit_name); 382292348Sken} 383292348Sken 384292348Skenvoid 385292348Skenmode_edit(struct cam_device *device, int page, int page_control, int dbd, 386292348Sken int edit, int retry_count, int timeout) 387292348Sken{ 388292348Sken int i; 389292348Sken u_char data[255]; 390292348Sken u_char *mode_pars; 391292348Sken struct mode_header 392292348Sken { 393292348Sken u_char mdl; /* Mode data length */ 394292348Sken u_char medium_type; 395292348Sken u_char dev_spec_par; 396292348Sken u_char bdl; /* Block descriptor length */ 397292348Sken }; 398292348Sken 399292348Sken struct mode_page_header 400292348Sken { 401292348Sken u_char page_code; 402292348Sken u_char page_length; 403292348Sken }; 404292348Sken 405292348Sken struct mode_header *mh; 406292348Sken struct mode_page_header *mph; 407292348Sken 408292348Sken char *fmt = mode_lookup(page); 409292348Sken if (!fmt && verbose) { 410292348Sken fprintf(stderr, 411292348Sken "No mode data base entry in \"%s\" for page %d; " 412292348Sken " binary %s only.\n", 413292348Sken mode_db, page, (edit ? "edit" : "display")); 414292348Sken } 415292348Sken 416292348Sken if (edit) { 417292348Sken if (!fmt) 41892108Sphk errx(1, "can't edit without a format"); 41992108Sphk 420110720Sphk if (page_control != 0 && page_control != 3) 42192108Sphk errx(1, "it only makes sense to edit page 0 " 422219970Smav "(current) or page 3 (saved values)"); 42392403Sphk 424273767Smav verbose = 1; 42592108Sphk 426248694Smav mode_sense(device, page, 1, dbd, retry_count, timeout, 427219970Smav data, sizeof(data)); 428115214Sphk 429143791Sphk mh = (struct mode_header *)data; 430143791Sphk mph = (struct mode_page_header *) 431104609Sphk (((char *)mh) + sizeof(*mh) + mh->bdl); 43292108Sphk 433104609Sphk mode_pars = (char *)mph + sizeof(*mph); 434110119Sphk 435226737Spjd edit_init(); 436104609Sphk buff_decode_visit(mode_pars, mh->mdl, fmt, edit_check, 0); 437104609Sphk 438104609Sphk mode_sense(device, page, 0, dbd, retry_count, timeout, 43992108Sphk data, sizeof(data)); 44092108Sphk 441292348Sken edit_rewind(); 442292348Sken buff_decode_visit(mode_pars, mh->mdl, fmt, edit_defaults, 0); 443292348Sken 444110720Sphk edit_rewind(); 445110720Sphk buff_decode_visit(mode_pars, mh->mdl, fmt, edit_report, 0); 44692108Sphk 447110477Sphk edit_edit(); 448110477Sphk 449110477Sphk edit_rewind(); 450110477Sphk buff_encode_visit(mode_pars, mh->mdl, fmt, edit_get, 0); 451292348Sken 452292348Sken /* Eliminate block descriptors: 453292348Sken */ 454273767Smav bcopy((char *)mph, ((char *)mh) + sizeof(*mh), 455110720Sphk sizeof(*mph) + mph->page_length); 456110720Sphk 457110720Sphk mh->bdl = mh->dev_spec_par = 0; 458110720Sphk mph = (struct mode_page_header *) (((char *)mh) + sizeof(*mh)); 459110720Sphk mode_pars = ((char *)mph) + 2; 460110720Sphk 461110720Sphk#if 0 462110720Sphk /* Turn this on to see what you're sending to the 463110720Sphk * device: 464110720Sphk */ 465110720Sphk edit_rewind(); 466110720Sphk buff_decode_visit(mode_pars, mh->mdl, fmt, arg_put, 0); 467260385Sscottl#endif 468150759Stegge 469260385Sscottl edit_done(); 470110720Sphk 471110720Sphk /* Make it permanent if pageselect is three. 472110720Sphk */ 473292348Sken 474292348Sken mph->page_code &= ~0xC0; /* Clear PS and RESERVED */ 475292348Sken mh->mdl = 0; /* Reserved for mode select */ 476292348Sken 477110720Sphk mode_select(device, (page_control == 3), retry_count, 478110720Sphk timeout, (u_int8_t *)mh, sizeof(*mh) + mh->bdl + 479292348Sken sizeof(*mph) + mph->page_length); 480292348Sken 48192108Sphk return; 48292108Sphk } 483223089Sgibbs 484223089Sgibbs mode_sense(device, page, page_control, dbd, retry_count, timeout, 485223089Sgibbs data, sizeof(data)); 486223089Sgibbs 487223089Sgibbs /* Skip over the block descriptors. 488223089Sgibbs */ 489223089Sgibbs mh = (struct mode_header *)data; 490223089Sgibbs mph = (struct mode_page_header *)(((char *)mh) + sizeof(*mh) + mh->bdl); 491223089Sgibbs mode_pars = (char *)mph + sizeof(*mph); 492216794Skib 493216794Skib if (!fmt) { 49492403Sphk for (i = 0; i < mh->mdl; i++) { 495216794Skib printf("%02x%c",mode_pars[i], 496216794Skib (((i + 1) % 8) == 0) ? '\n' : ' '); 497216794Skib } 498103714Sphk putc('\n', stdout); 49992403Sphk } else { 50098066Sphk verbose = 1; 50194287Sphk buff_decode_visit(mode_pars, mh->mdl, fmt, arg_put, NULL); 502169285Spjd } 503169285Spjd} 504271238Ssmh