cdrtools/scgskeleton/skel.c

537 lines
12 KiB
C
Raw Normal View History

2025-06-15 04:19:58 +08:00
/* @(#)skel.c 1.23 16/01/24 Copyright 1987, 1995-2016 J. Schilling */
#include <schily/mconfig.h>
#ifndef lint
static UConst char sccsid[] =
"@(#)skel.c 1.23 16/01/24 Copyright 1987, 1995-2016 J. Schilling";
#endif
/*
* Skeleton for the use of the scg genearal SCSI - driver
*
* Copyright (c) 1987, 1995-2016 J. Schilling
*/
/*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* See the file CDDL.Schily.txt in this distribution for details.
* A copy of the CDDL is also available via the Internet at
* http://www.opensource.org/licenses/cddl1.txt
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file CDDL.Schily.txt from this distribution.
*/
#define SKEL_MAIN
#include <schily/mconfig.h>
#include <schily/stdio.h>
#include <schily/standard.h>
#include <schily/unistd.h>
#include <schily/stdlib.h>
#include <schily/string.h>
#include <schily/fcntl.h>
#include <schily/time.h>
#include <schily/errno.h>
#include <schily/signal.h>
#include <schily/schily.h>
#include <schily/nlsdefs.h>
#include <schily/priv.h>
#include <schily/io.h> /* for setmode() prototype */
#include <scg/scgcmd.h>
#include <scg/scsireg.h>
#include <scg/scsitransp.h>
#include "scsi_scan.h"
#include "cdrecord.h"
#include "cdrdeflt.h"
#include "iodefs.h"
char skel_version[] = "1.2";
struct exargs {
SCSI *scgp;
int old_secsize;
int flags;
int exflags;
char oerr[3];
} exargs;
#ifndef NO_DOIT
#define NEED_PRSTATS
#endif
LOCAL void usage __PR((int ret));
EXPORT int main __PR((int ac, char **av));
LOCAL void intr __PR((int sig));
LOCAL void exscsi __PR((int excode, void *arg));
#ifdef __needed__
LOCAL void excdr __PR((int excode, void *arg));
#endif
#ifdef NEED_PRSTATS
LOCAL int prstats __PR((void));
#endif
#ifdef __needed__
LOCAL int prstats_silent __PR((void));
#endif
#ifndef NO_DOIT
#include "doit.c"
#endif
#ifndef DOIT_MAIN
LOCAL void doit __PR((SCSI *scgp));
#endif
LOCAL void dofile __PR((SCSI *scgp, char *filename));
struct timeval starttime;
struct timeval stoptime;
int didintr;
int exsig;
char *Sbuf;
long Sbufsize = -1L;
int help;
int xdebug;
int lverbose;
int quiet;
BOOL is_suid;
LOCAL void
usage(ret)
int ret;
{
error(_("Usage:\tscgskeleton [options]\n"));
error(_("Options:\n"));
error(_("\t-version print version information and exit\n"));
error(_("\tdev=target SCSI target to use\n"));
error(_("\tscgopts=spec SCSI options for libscg\n"));
error(_("\tf=filename Name of file to read/write\n"));
error(_("\tts=# set maximum transfer size for a single SCSI command\n"));
error(_("\ttimeout=# set the default SCSI command timeout to #.\n"));
error(_("\tdebug=#,-d Set to # or increment misc debug level\n"));
error(_("\tkdebug=#,kd=# do Kernel debugging\n"));
error(_("\t-quiet,-q be more quiet in error retry mode\n"));
error(_("\t-verbose,-v increment general verbose level by one\n"));
error(_("\t-Verbose,-V increment SCSI command transport verbose level by one\n"));
error(_("\t-silent,-s do not print status of failed SCSI commands\n"));
error(_("\t-scanbus scan the SCSI bus and exit\n"));
exit(ret);
}
/* CSTYLED */
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*";
EXPORT int
main(ac, av)
int ac;
char *av[];
{
char *dev = NULL;
char *scgopts = NULL;
int fcount;
int cac;
char * const *cav;
#if defined(USE_NLS)
char *dir;
#endif
int scsibus = -1;
int target = -1;
int lun = -1;
int silent = 0;
int verbose = 0;
int kdebug = 0;
int debug = 0;
int deftimeout = 40;
int pversion = 0;
int scanbus = 0;
SCSI *scgp;
char *filename = NULL;
int err;
save_args(ac, av);
#if defined(USE_NLS)
(void) setlocale(LC_ALL, "");
#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
#define TEXT_DOMAIN "scgskeleton" /* Use this only if it weren't */
#endif
dir = searchfileinpath("share/locale", F_OK,
SIP_ANY_FILE|SIP_NO_PATH, NULL);
if (dir)
(void) bindtextdomain(TEXT_DOMAIN, dir);
else
#if defined(PROTOTYPES) && defined(INS_BASE)
(void) bindtextdomain(TEXT_DOMAIN, INS_BASE "/share/locale");
#else
(void) bindtextdomain(TEXT_DOMAIN, "/usr/share/locale");
#endif
(void) textdomain(TEXT_DOMAIN);
#endif
cac = --ac;
cav = ++av;
if (getallargs(&cac, &cav, opts,
&debug, &debug,
&kdebug, &kdebug,
&deftimeout,
&quiet, &quiet,
&lverbose, &lverbose,
&verbose, &verbose,
&xdebug, &xdebug,
&silent, &silent,
&help, &help, &pversion,
&scanbus,
&dev, &scgopts,
getnum, &Sbufsize,
&filename) < 0) {
errmsgno(EX_BAD, _("Bad flag: %s.\n"), cav[0]);
usage(EX_BAD);
}
if (help)
usage(0);
if (pversion) {
printf(_("scgskeleton %s (%s-%s-%s) Copyright (C) 1987, 1995-2016 %s\n"),
skel_version,
HOST_CPU, HOST_VENDOR, HOST_OS,
_("Joerg Schilling"));
exit(0);
}
fcount = 0;
cac = ac;
cav = av;
while (getfiles(&cac, &cav, opts) > 0) {
fcount++;
if (fcount == 1) {
if (*astoi(cav[0], &target) != '\0') {
errmsgno(EX_BAD,
_("Target '%s' is not a Number.\n"),
cav[0]);
usage(EX_BAD);
/* NOTREACHED */
}
}
if (fcount == 2) {
if (*astoi(cav[0], &lun) != '\0') {
errmsgno(EX_BAD,
_("Lun is '%s' not a Number.\n"),
cav[0]);
usage(EX_BAD);
/* NOTREACHED */
}
}
if (fcount == 3) {
if (*astoi(cav[0], &scsibus) != '\0') {
errmsgno(EX_BAD,
_("Scsibus is '%s' not a Number.\n"),
cav[0]);
usage(EX_BAD);
/* NOTREACHED */
}
}
cac--;
cav++;
}
/*error("dev: '%s'\n", dev);*/
cdr_defaults(&dev, NULL, NULL, &Sbufsize, NULL);
if (debug) {
printf(_("dev: '%s'\n"), dev);
}
if (!scanbus && dev == NULL &&
scsibus == -1 && (target == -1 || lun == -1)) {
errmsgno(EX_BAD, _("No SCSI device specified.\n"));
usage(EX_BAD);
}
if (dev || scanbus) {
char errstr[80];
/*
* Call scg_remote() to force loading the remote SCSI transport
* library code that is located in librscg instead of the dummy
* remote routines that are located inside libscg.
*/
scg_remote();
if (dev != NULL &&
((strncmp(dev, "HELP", 4) == 0) ||
(strncmp(dev, "help", 4) == 0))) {
scg_help(stderr);
exit(0);
}
if ((scgp = scg_open(dev, errstr, sizeof (errstr), debug, lverbose)) == (SCSI *)0) {
err = geterrno();
errmsgno(err, _("%s%sCannot open SCSI driver.\n"), errstr, errstr[0]?". ":"");
errmsgno(EX_BAD, _("For possible targets try 'scgskeleton -scanbus'. Make sure you are root.\n"));
errmsgno(EX_BAD, _("For possible transport specifiers try 'scgskeleton dev=help'.\n"));
exit(err);
}
} else {
if (scsibus == -1 && target >= 0 && lun >= 0)
scsibus = 0;
scgp = scg_smalloc();
scgp->debug = debug;
scgp->kdebug = kdebug;
scg_settarget(scgp, scsibus, target, lun);
if (scg__open(scgp, NULL) <= 0)
comerr(_("Cannot open SCSI driver.\n"));
}
if (scgopts) {
int i = scg_opts(scgp, scgopts);
if (i <= 0)
exit(i < 0 ? EX_BAD : 0);
}
scgp->silent = silent;
scgp->verbose = verbose;
scgp->debug = debug;
scgp->kdebug = kdebug;
scg_settimeout(scgp, deftimeout);
if (Sbufsize < 0)
Sbufsize = 256*1024L;
Sbufsize = scg_bufsize(scgp, Sbufsize);
if ((Sbuf = scg_getbuf(scgp, Sbufsize)) == NULL)
comerr(_("Cannot get SCSI I/O buffer.\n"));
#ifdef HAVE_PRIV_SET
/*
* Give up privs we do not need anymore.
* We no longer need:
* file_dac_read,net_privaddr
* We still need:
* sys_devices
*/
priv_set(PRIV_OFF, PRIV_EFFECTIVE,
PRIV_FILE_DAC_READ, PRIV_NET_PRIVADDR, NULL);
priv_set(PRIV_OFF, PRIV_PERMITTED,
PRIV_FILE_DAC_READ, PRIV_NET_PRIVADDR, NULL);
priv_set(PRIV_OFF, PRIV_INHERITABLE,
PRIV_FILE_DAC_READ, PRIV_NET_PRIVADDR, PRIV_SYS_DEVICES, NULL);
#endif
/*
* This is only for OS that do not support fine grained privs.
*/
is_suid = geteuid() != getuid();
/*
* We don't need root privilleges anymore.
*/
#ifdef HAVE_SETREUID
if (setreuid(-1, getuid()) < 0)
#else
#ifdef HAVE_SETEUID
if (seteuid(getuid()) < 0)
#else
if (setuid(getuid()) < 0)
#endif
#endif
comerr(_("Panic cannot set back effective uid.\n"));
/* code to use SCG */
if (scanbus) {
if (select_target(scgp, stdout) < 0)
exit(EX_BAD);
exit(0);
}
seterrno(0);
do_inquiry(scgp, FALSE);
err = geterrno();
if (err == EPERM || err == EACCES)
exit(EX_BAD);
allow_atapi(scgp, TRUE); /* Try to switch to 10 byte mode cmds */
exargs.scgp = scgp;
exargs.old_secsize = -1;
/* exargs.flags = flags;*/
exargs.oerr[2] = 0;
/*
* Install exit handler before we change the drive status.
*/
on_comerr(exscsi, &exargs);
signal(SIGINT, intr);
signal(SIGTERM, intr);
if (filename)
dofile(scgp, filename);
else
doit(scgp);
comexit(0);
return (0);
}
/*
* XXX Leider kann man vim Signalhandler keine SCSI Kommandos verschicken
* XXX da meistens das letzte SCSI Kommando noch laeuft.
* XXX Eine Loesung waere ein Abort Callback in SCSI *.
*/
LOCAL void
intr(sig)
int sig;
{
didintr++;
exsig = sig;
/* comexit(sig);*/
}
/* ARGSUSED */
LOCAL void
exscsi(excode, arg)
int excode;
void *arg;
{
struct exargs *exp = (struct exargs *)arg;
int i;
/*
* Try to restore the old sector size.
*/
if (exp != NULL && exp->exflags == 0) {
for (i = 0; i < 10*100; i++) {
if (!exp->scgp->running)
break;
if (i == 10) {
errmsgno(EX_BAD,
_("Waiting for current SCSI command to finish.\n"));
}
usleep(100000);
}
#ifdef ___NEEDED___
/*
* Try to set drive back to original state.
*/
if (!exp->scgp->running) {
if (exp->oerr[2] != 0) {
domode(exp->scgp, exp->oerr[0], exp->oerr[1]);
}
if (exp->old_secsize > 0 && exp->old_secsize != 2048)
select_secsize(exp->scgp, exp->old_secsize);
}
#endif
exp->exflags++; /* Make sure that it only get called once */
}
}
#ifdef __needed__
LOCAL void
excdr(excode, arg)
int excode;
void *arg;
{
exscsi(excode, arg);
#ifdef needed
/* Do several other restores/statistics here (see cdrecord.c) */
#endif
}
#endif
#ifdef NEED_PRSTATS
/*
* Return milliseconds since start time.
*/
LOCAL int
prstats()
{
int sec;
int usec;
int tmsec;
if (gettimeofday(&stoptime, (struct timezone *)0) < 0)
comerr(_("Cannot get time\n"));
sec = stoptime.tv_sec - starttime.tv_sec;
usec = stoptime.tv_usec - starttime.tv_usec;
tmsec = sec*1000 + usec/1000;
#ifdef lint
tmsec = tmsec; /* Bisz spaeter */
#endif
if (usec < 0) {
sec--;
usec += 1000000;
}
error(_("Time total: %d.%03dsec\n"), sec, usec/1000);
return (1000*sec + (usec / 1000));
}
#endif
#ifdef __needed__
/*
* Return milliseconds since start time, but be silent this time.
*/
LOCAL int
prstats_silent()
{
int sec;
int usec;
int tmsec;
if (gettimeofday(&stoptime, (struct timezone *)0) < 0)
comerr(_("Cannot get time\n"));
sec = stoptime.tv_sec - starttime.tv_sec;
usec = stoptime.tv_usec - starttime.tv_usec;
tmsec = sec*1000 + usec/1000;
#ifdef lint
tmsec = tmsec; /* Bisz spaeter */
#endif
if (usec < 0) {
sec--;
usec += 1000000;
}
return (1000*sec + (usec / 1000));
}
#endif
#ifndef DOIT_MAIN
LOCAL void
doit(scgp)
SCSI *scgp;
{
int i = 0;
for (;;) {
if (!wait_unit_ready(scgp, 60))
comerrno(EX_BAD, _("Device not ready.\n"));
printf(_("0:read\n"));
/* printf("7:wne 8:floppy 9:verify 10:checkcmds 11:read disk 12:write disk\n");*/
getint(_("Enter selection:"), &i, 0, 20);
if (didintr)
return;
switch (i) {
/* case 1: read_disk(scgp, 0); break;*/
default: error(_("Unimplemented selection %d\n"), i);
}
}
}
#endif /* DOIT_MAIN */
LOCAL void
dofile(scgp, filename)
SCSI *scgp;
char *filename;
{
}
/*
* Add your own code below....
*/