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