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