1 /* @(#)skel.c 1.26 16/01/24 Copyright 1987, 1995-2016 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static UConst char sccsid[] =
5 "@(#)skel.c 1.26 16/01/24 Copyright 1987, 1995-2016 J. Schilling";
6 #endif
7 /*
8 * Skeleton for the use of the scg genearal SCSI - driver
9 *
10 * Copyright (c) 1987, 1995-2016 J. Schilling
11 */
12 /*
13 * The contents of this file are subject to the terms of the
14 * Common Development and Distribution License, Version 1.0 only
15 * (the "License"). You may not use this file except in compliance
16 * with the License.
17 *
18 * See the file CDDL.Schily.txt in this distribution for details.
19 * A copy of the CDDL is also available via the Internet at
20 * http://www.opensource.org/licenses/cddl1.txt
21 *
22 * When distributing Covered Code, include this CDDL HEADER in each
23 * file and include the License file CDDL.Schily.txt from this distribution.
24 */
25
26 #include <schily/stdio.h>
27 #include <schily/standard.h>
28 #include <schily/unistd.h>
29 #include <schily/stdlib.h>
30 #include <schily/string.h>
31 #include <schily/fcntl.h>
32 #include <schily/time.h>
33 #include <schily/errno.h>
34 #include <schily/signal.h>
35 #include <schily/schily.h>
36 #include <schily/nlsdefs.h>
37 #include <schily/priv.h>
38 #include <schily/io.h> /* for setmode() prototype */
39
40 #include <scg/scgcmd.h>
41 #include <scg/scsireg.h>
42 #include <scg/scsitransp.h>
43
44 #include "scsi_scan.h"
45 #include "cdrecord.h"
46 #include "cdrdeflt.h"
47
48 char skel_version[] = "1.1";
49
50 extern BOOL getlong __PR((char *, long *, long, long));
51 extern BOOL getint __PR((char *, int *, int, int));
52
53 struct exargs {
54 SCSI *scgp;
55 int old_secsize;
56 int flags;
57 int exflags;
58 char oerr[3];
59 } exargs;
60
61 LOCAL void usage __PR((int ret));
62 EXPORT int main __PR((int ac, char **av));
63 LOCAL void intr __PR((int sig));
64 LOCAL void exscsi __PR((int excode, void *arg));
65 #ifdef __needed__
66 LOCAL void excdr __PR((int excode, void *arg));
67 LOCAL int prstats __PR((void));
68 LOCAL int prstats_silent __PR((void));
69 #endif
70 LOCAL void doit __PR((SCSI *scgp));
71 LOCAL void dofile __PR((SCSI *scgp, char *filename));
72
73 struct timeval starttime;
74 struct timeval stoptime;
75 int didintr;
76 int exsig;
77
78 char *Sbuf;
79 long Sbufsize = -1L;
80
81 int help;
82 int xdebug;
83 int lverbose;
84 int quiet;
85 BOOL is_suid;
86
87 LOCAL void
usage(ret)88 usage(ret)
89 int ret;
90 {
91 error(_("Usage:\tbtcflash [options] f=firmwarefile\n"));
92 error(_("Options:\n"));
93 error(_("\t-version print version information and exit\n"));
94 error(_("\tdev=target SCSI target to use\n"));
95 error(_("\tscgopts=spec SCSI options for libscg\n"));
96 error(_("\tf=filename Name of firmware file to read from\n"));
97 error(_("\tts=# set maximum transfer size for a single SCSI command\n"));
98 error(_("\ttimeout=# set the default SCSI command timeout to #.\n"));
99 error(_("\tdebug=#,-d Set to # or increment misc debug level\n"));
100 error(_("\tkdebug=#,kd=# do Kernel debugging\n"));
101 error(_("\t-quiet,-q be more quiet in error retry mode\n"));
102 error(_("\t-verbose,-v increment general verbose level by one\n"));
103 error(_("\t-Verbose,-V increment SCSI command transport verbose level by one\n"));
104 error(_("\t-silent,-s do not print status of failed SCSI commands\n"));
105 error(_("\t-scanbus scan the SCSI bus and exit\n"));
106 exit(ret);
107 }
108
109 /* CSTYLED */
110 char opts[] = "debug#,d+,kdebug#,kd#,timeout#,quiet,q,verbose+,v+,Verbose+,V+,x+,xd#,silent,s,help,h,version,scanbus,dev*,scgopts*,ts&,f*";
111
112 EXPORT int
main(ac,av)113 main(ac, av)
114 int ac;
115 char *av[];
116 {
117 char *dev = NULL;
118 char *scgopts = NULL;
119 int fcount;
120 int cac;
121 char * const *cav;
122 #if defined(USE_NLS)
123 char *dir;
124 #endif
125 int scsibus = -1;
126 int target = -1;
127 int lun = -1;
128 int silent = 0;
129 int verbose = 0;
130 int kdebug = 0;
131 int debug = 0;
132 int deftimeout = 40;
133 int pversion = 0;
134 int scanbus = 0;
135 SCSI *scgp;
136 char *filename = NULL;
137 int err;
138
139 save_args(ac, av);
140
141 #if defined(USE_NLS)
142 (void) setlocale(LC_ALL, "");
143 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
144 #define TEXT_DOMAIN "btcflash" /* Use this only if it weren't */
145 #endif
146 dir = searchfileinpath("share/locale", F_OK,
147 SIP_ANY_FILE|SIP_NO_PATH, NULL);
148 if (dir)
149 (void) bindtextdomain(TEXT_DOMAIN, dir);
150 else
151 #if defined(PROTOTYPES) && defined(INS_BASE)
152 (void) bindtextdomain(TEXT_DOMAIN, INS_BASE "/share/locale");
153 #else
154 (void) bindtextdomain(TEXT_DOMAIN, "/usr/share/locale");
155 #endif
156 (void) textdomain(TEXT_DOMAIN);
157 #endif
158
159 cac = --ac;
160 cav = ++av;
161
162 if (getallargs(&cac, &cav, opts,
163 &debug, &debug,
164 &kdebug, &kdebug,
165 &deftimeout,
166 &quiet, &quiet,
167 &lverbose, &lverbose,
168 &verbose, &verbose,
169 &xdebug, &xdebug,
170 &silent, &silent,
171 &help, &help, &pversion,
172 &scanbus,
173 &dev, &scgopts,
174 getnum, &Sbufsize,
175 &filename) < 0) {
176 errmsgno(EX_BAD, _("Bad flag: %s.\n"), cav[0]);
177 usage(EX_BAD);
178 }
179 if (help)
180 usage(0);
181 if (pversion) {
182 printf(_("btcflash %s (%s-%s-%s) Copyright (C) 1987, 1995-2016 %s (C) 2004 David Huang\n"),
183 skel_version,
184 HOST_CPU, HOST_VENDOR, HOST_OS,
185 _("Joerg Schilling"));
186 exit(0);
187 }
188
189 fcount = 0;
190 cac = ac;
191 cav = av;
192
193 while (getfiles(&cac, &cav, opts) > 0) {
194 fcount++;
195 if (fcount == 1) {
196 if (*astoi(cav[0], &target) != '\0') {
197 errmsgno(EX_BAD,
198 _("Target '%s' is not a Number.\n"),
199 cav[0]);
200 usage(EX_BAD);
201 /* NOTREACHED */
202 }
203 }
204 if (fcount == 2) {
205 if (*astoi(cav[0], &lun) != '\0') {
206 errmsgno(EX_BAD,
207 _("Lun is '%s' not a Number.\n"),
208 cav[0]);
209 usage(EX_BAD);
210 /* NOTREACHED */
211 }
212 }
213 if (fcount == 3) {
214 if (*astoi(cav[0], &scsibus) != '\0') {
215 errmsgno(EX_BAD,
216 _("Scsibus is '%s' not a Number.\n"),
217 cav[0]);
218 usage(EX_BAD);
219 /* NOTREACHED */
220 }
221 } else {
222 scsibus = 0;
223 }
224 cac--;
225 cav++;
226 }
227 /*error("dev: '%s'\n", dev);*/
228
229 cdr_defaults(&dev, NULL, NULL, &Sbufsize, NULL);
230 if (debug) {
231 printf(_("dev: '%s'\n"), dev);
232 }
233 if (!scanbus && dev == NULL &&
234 scsibus == -1 && (target == -1 || lun == -1)) {
235 errmsgno(EX_BAD, _("No SCSI device specified.\n"));
236 usage(EX_BAD);
237 }
238 if (dev || scanbus) {
239 char errstr[80];
240
241 /*
242 * Call scg_remote() to force loading the remote SCSI transport
243 * library code that is located in librscg instead of the dummy
244 * remote routines that are located inside libscg.
245 */
246 scg_remote();
247 if (dev != NULL &&
248 ((strncmp(dev, "HELP", 4) == 0) ||
249 (strncmp(dev, "help", 4) == 0))) {
250 scg_help(stderr);
251 exit(0);
252 }
253 if ((scgp = scg_open(dev, errstr, sizeof (errstr), debug, lverbose)) == (SCSI *)0) {
254 err = geterrno();
255
256 errmsgno(err, _("%s%sCannot open SCSI driver.\n"), errstr, errstr[0]?". ":"");
257 errmsgno(EX_BAD, _("For possible targets try 'btcflash -scanbus'. Make sure you are root.\n"));
258 errmsgno(EX_BAD, _("For possible transport specifiers try 'btcflash dev=help'.\n"));
259 exit(err);
260 }
261 } else {
262 if (scsibus == -1 && target >= 0 && lun >= 0)
263 scsibus = 0;
264
265 scgp = scg_smalloc();
266 scgp->debug = debug;
267 scgp->kdebug = kdebug;
268
269 scg_settarget(scgp, scsibus, target, lun);
270 if (scg__open(scgp, NULL) <= 0)
271 comerr(_("Cannot open SCSI driver.\n"));
272 }
273 if (scgopts) {
274 int i = scg_opts(scgp, scgopts);
275 if (i <= 0)
276 exit(i < 0 ? EX_BAD : 0);
277 }
278 scgp->silent = silent;
279 scgp->verbose = verbose;
280 scgp->debug = debug;
281 scgp->kdebug = kdebug;
282 scg_settimeout(scgp, deftimeout);
283
284 if (Sbufsize < 0)
285 Sbufsize = 256*1024L;
286 Sbufsize = scg_bufsize(scgp, Sbufsize);
287 if ((Sbuf = scg_getbuf(scgp, Sbufsize)) == NULL)
288 comerr(_("Cannot get SCSI I/O buffer.\n"));
289
290 #ifdef HAVE_PRIV_SET
291 /*
292 * Give up privs we do not need anymore.
293 * We no longer need:
294 * file_dac_read,net_privaddr
295 * We still need:
296 * sys_devices
297 */
298 priv_set(PRIV_OFF, PRIV_EFFECTIVE,
299 PRIV_FILE_DAC_READ, PRIV_NET_PRIVADDR, NULL);
300 priv_set(PRIV_OFF, PRIV_PERMITTED,
301 PRIV_FILE_DAC_READ, PRIV_NET_PRIVADDR, NULL);
302 priv_set(PRIV_OFF, PRIV_INHERITABLE,
303 PRIV_FILE_DAC_READ, PRIV_NET_PRIVADDR, PRIV_SYS_DEVICES, NULL);
304 #endif
305 /*
306 * This is only for OS that do not support fine grained privs.
307 */
308 is_suid = geteuid() != getuid();
309 /*
310 * We don't need root privilleges anymore.
311 */
312 #ifdef HAVE_SETREUID
313 if (setreuid(-1, getuid()) < 0)
314 #else
315 #ifdef HAVE_SETEUID
316 if (seteuid(getuid()) < 0)
317 #else
318 if (setuid(getuid()) < 0)
319 #endif
320 #endif
321 comerr(_("Panic cannot set back effective uid.\n"));
322
323 /* code to use SCG */
324
325 if (scanbus) {
326 if (select_target(scgp, stdout) < 0)
327 exit(EX_BAD);
328 exit(0);
329 }
330 seterrno(0);
331 do_inquiry(scgp, FALSE);
332 err = geterrno();
333 if (err == EPERM || err == EACCES)
334 exit(EX_BAD);
335 allow_atapi(scgp, TRUE); /* Try to switch to 10 byte mode cmds */
336
337 exargs.scgp = scgp;
338 exargs.old_secsize = -1;
339 /* exargs.flags = flags;*/
340 exargs.oerr[2] = 0;
341
342 /*
343 * Install exit handler before we change the drive status.
344 */
345 on_comerr(exscsi, &exargs);
346 signal(SIGINT, intr);
347 signal(SIGTERM, intr);
348
349 if (filename) {
350 dofile(scgp, filename);
351 } else {
352 errmsgno(EX_BAD, _("Firmware file missing.\n"));
353 doit(scgp);
354 }
355
356 comexit(0);
357 return (0);
358 }
359
360 /*
361 * XXX Leider kann man vim Signalhandler keine SCSI Kommandos verschicken
362 * XXX da meistens das letzte SCSI Kommando noch laeuft.
363 * XXX Eine Loesung waere ein Abort Callback in SCSI *.
364 */
365 LOCAL void
intr(sig)366 intr(sig)
367 int sig;
368 {
369 didintr++;
370 exsig = sig;
371 /* comexit(sig);*/
372 }
373
374 /* ARGSUSED */
375 LOCAL void
exscsi(excode,arg)376 exscsi(excode, arg)
377 int excode;
378 void *arg;
379 {
380 struct exargs *exp = (struct exargs *)arg;
381 int i;
382
383 /*
384 * Try to restore the old sector size.
385 */
386 if (exp != NULL && exp->exflags == 0) {
387 for (i = 0; i < 10*100; i++) {
388 if (!exp->scgp->running)
389 break;
390 if (i == 10) {
391 errmsgno(EX_BAD,
392 _("Waiting for current SCSI command to finish.\n"));
393 }
394 usleep(100000);
395 }
396
397 #ifdef ___NEEDED___
398 /*
399 * Try to set drive back to original state.
400 */
401 if (!exp->scgp->running) {
402 if (exp->oerr[2] != 0) {
403 domode(exp->scgp, exp->oerr[0], exp->oerr[1]);
404 }
405 if (exp->old_secsize > 0 && exp->old_secsize != 2048)
406 select_secsize(exp->scgp, exp->old_secsize);
407 }
408 #endif
409 exp->exflags++; /* Make sure that it only get called once */
410 }
411 }
412
413 #ifdef __needed__
414 LOCAL void
excdr(excode,arg)415 excdr(excode, arg)
416 int excode;
417 void *arg;
418 {
419 exscsi(excode, arg);
420
421 #ifdef needed
422 /* Do several other restores/statistics here (see cdrecord.c) */
423 #endif
424 }
425 #endif
426
427 #ifdef __needed__
428 /*
429 * Return milliseconds since start time.
430 */
431 LOCAL int
prstats()432 prstats()
433 {
434 int sec;
435 int usec;
436 int tmsec;
437
438 if (gettimeofday(&stoptime, (struct timezone *)0) < 0)
439 comerr(_("Cannot get time\n"));
440
441 sec = stoptime.tv_sec - starttime.tv_sec;
442 usec = stoptime.tv_usec - starttime.tv_usec;
443 tmsec = sec*1000 + usec/1000;
444 #ifdef lint
445 tmsec = tmsec; /* Bisz spaeter */
446 #endif
447 if (usec < 0) {
448 sec--;
449 usec += 1000000;
450 }
451
452 error(_("Time total: %d.%03dsec\n"), sec, usec/1000);
453 return (1000*sec + (usec / 1000));
454 }
455 #endif
456
457 #ifdef __needed__
458 /*
459 * Return milliseconds since start time, but be silent this time.
460 */
461 LOCAL int
prstats_silent()462 prstats_silent()
463 {
464 int sec;
465 int usec;
466 int tmsec;
467
468 if (gettimeofday(&stoptime, (struct timezone *)0) < 0)
469 comerr(_("Cannot get time\n"));
470
471 sec = stoptime.tv_sec - starttime.tv_sec;
472 usec = stoptime.tv_usec - starttime.tv_usec;
473 tmsec = sec*1000 + usec/1000;
474 #ifdef lint
475 tmsec = tmsec; /* Bisz spaeter */
476 #endif
477 if (usec < 0) {
478 sec--;
479 usec += 1000000;
480 }
481
482 return (1000*sec + (usec / 1000));
483 }
484 #endif
485
486 LOCAL void
doit(scgp)487 doit(scgp)
488 SCSI *scgp;
489 {
490 int i = 0;
491
492 for (;;) {
493 if (!wait_unit_ready(scgp, 60))
494 comerrno(EX_BAD, _("Device not ready.\n"));
495
496 printf(_("0:read\n"));
497 /* printf("7:wne 8:floppy 9:verify 10:checkcmds 11:read disk 12:write disk\n");*/
498
499 getint(_("Enter selection:"), &i, 0, 20);
500 if (didintr)
501 return;
502
503 switch (i) {
504
505 /* case 1: read_disk(scgp, 0); break;*/
506
507 default: error(_("Unimplemented selection %d\n"), i);
508 }
509 }
510 }
511
512 LOCAL int btcmain __PR((SCSI *scgp, const char *fwfile));
513
514 LOCAL void
dofile(scgp,filename)515 dofile(scgp, filename)
516 SCSI *scgp;
517 char *filename;
518 {
519 if (btcmain(scgp, filename) != 0)
520 exit(EX_BAD);
521 }
522
523 /*
524 * Add your own code below....
525 */
526
527 #include "btcflash.c"
528