Files
mt-st/stinit.c
Kai Mäkisara 42dd44bb90 stinit: Change stinit to return one if setting one or more options fails
Previously, stinit returned zero even if it fails to set the options.
This patch changes the return value to one if one or more of the options
can't be set for a device if the tape numbers are given on command line.
If no numbers are given, stinit returns zero (as before this patch).
After this change, scripts (udev rules) can more easily detect when
stinit fails.

Signed-off-by: Kai Mäkisara <Kai.Makisara@kolumbus.fi>
2025-01-05 16:26:21 +01:00

966 lines
30 KiB
C

/* This program initializes Linux SCSI tape drives using the
inquiry data from the devices and a text database.
Maintained by Iustin Pop (iustin@k1024.org).
Copyright 1996-2008 by Kai Mäkisara (Kai.Makisara@kolumbus.fi).
Distribution of this program is allowed according to the
GNU Public Licence.
*/
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <linux/major.h>
#include <scsi/sg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
#include <unistd.h>
#include "mtio.h"
#include "version.h"
#ifndef FALSE
#define TRUE 1
#define FALSE 0
#endif
#define SKIP_WHITE(p) for (; *p == ' ' || *p == '\t'; p++)
typedef struct _modepar_tr {
int defined;
int blocksize;
int density;
int buffer_writes;
int async_writes;
int read_ahead;
int two_fm;
int compression;
int auto_lock;
int fast_eod;
int can_bsr;
int no_blklimits;
int can_partitions;
int scsi2logical;
int sysv;
int defs_for_writes;
} modepar_tr;
typedef struct _devdef_tr {
int do_rewind;
int drive_buffering;
int timeout;
int long_timeout;
int cleaning;
int nowait;
int weof_nowait;
int sili;
modepar_tr modedefs[4];
} devdef_tr;
#define DEFMAX 2048
#define LINEMAX 256
#define MAX_TAPES 32
#define NBR_MODES 4
static int verbose = 0;
/* The device directories being searched */
typedef struct {
char dir[PATH_MAX];
int selective_scan;
} devdir;
static devdir devdirs[] = { { "/dev/scsi", 0 }, { "/dev", 1 }, { "", 0 } };
#define DEVFS_PATH "/dev/tapes"
#define DEVFS_TAPEFMT DEVFS_PATH "/tape%d"
/* The partial names of the tape devices being included in the
search in selective scan */
static char *tape_name_bases[] = { "st", "nst", "rmt", "nrmt", "tape", NULL };
/* The list of standard definition files being searched */
static char *std_databases[] = { "/etc/stinit.def", NULL };
static char usage(int retval) __attribute__((noreturn));
static FILE *open_database(char *base)
{
int i;
FILE *f;
if (base != NULL) {
if ((f = fopen(base, "r")) == NULL)
fprintf(stderr, "stinit: Can't find SCSI tape database '%s'.\n", base);
return f;
}
for (i = 0; std_databases[i] != NULL; i++) {
if (verbose > 1)
fprintf(stderr, "Trying to open database '%s'.\n", std_databases[i]);
if ((f = fopen(std_databases[i], "r")) != NULL) {
if (verbose > 1)
fprintf(stderr, "Open succeeded.\n");
return f;
}
}
fprintf(stderr, "Can't find the tape characteristics database.\n");
return NULL;
}
static char *find_string(char *s, char *target, char *buf, int buflen)
{
int have_arg;
char *cp, *cp2, c, *argp;
if (buf != NULL && buflen > 0)
*buf = '\0';
for (; *s != '\0';) {
SKIP_WHITE(s);
if (isalpha(*s)) {
for (cp = s; isalnum(*cp) || *cp == '-'; cp++)
;
cp2 = cp;
SKIP_WHITE(cp);
if (*cp == '=') {
cp++;
SKIP_WHITE(cp);
if (*cp == '"') {
cp++;
for (cp2 = cp; *cp2 != '"' && *cp2 != '\0'; cp2++)
;
} else {
if (*cp == '\0')
return NULL;
else
for (cp2 = cp + 1; isalnum(*cp2) || *cp2 == '-'; cp2++)
;
}
if (*cp2 == '\0')
return NULL;
have_arg = TRUE;
argp = cp;
} else {
have_arg = FALSE;
argp = "1";
}
if (!strncmp(target, s, strlen(target))) {
c = *cp2;
*cp2 = '\0';
if (buf == NULL)
buf = strdup(argp);
else {
if (strlen(argp) < (unsigned int)buflen)
strcpy(buf, argp);
else {
strncpy(buf, argp, buflen);
buf[buflen - 1] = '\0';
}
}
if (have_arg && c == '"')
cp2++;
else
*cp2 = c;
if (*cp2 != '\0')
memmove(s, cp2, strlen(cp2) + 1);
else
*s = '\0';
return buf;
}
s = cp2;
} else
for (; *s != '\0' && *s != ' ' && *s != '\t'; s++)
;
}
return NULL;
}
static int num_arg(char *t)
{
int nbr;
char *tt;
nbr = strtol(t, &tt, 0);
if (t != tt) {
if (*tt == 'k')
nbr *= 1024;
else if (*tt == 'M')
nbr *= 1024 * 1024;
}
return nbr;
}
static int next_block(FILE *dbf, char *buf, size_t buflen, int limiter)
{
size_t len;
char *cp, *bp;
static char lbuf[LINEMAX];
if (limiter == 0) { /* Restart */
rewind(dbf);
lbuf[0] = '\0';
return TRUE;
}
for (len = 0;;) {
bp = buf + len;
if ((cp = strchr(lbuf, limiter)) != NULL) {
*cp = '\0';
strcpy(bp, lbuf);
cp++;
SKIP_WHITE(cp);
memmove(lbuf, cp, strlen(cp) + 1);
return TRUE;
}
if (len + strlen(lbuf) >= buflen) {
fprintf(stderr, "Too long definition: '%s'\n", buf);
return FALSE;
}
cp = lbuf;
SKIP_WHITE(cp);
strcpy(bp, cp);
strcat(bp, " ");
len += strlen(cp) + 1;
if (fgets(lbuf, LINEMAX, dbf) == NULL)
return FALSE;
if ((cp = strchr(lbuf, '#')) != NULL)
*cp = '\0';
else
lbuf[strlen(lbuf) - 1] = '\0';
}
}
static int
find_pars(FILE *dbf, char *company, char *product, char *rev, devdef_tr *defs, int parse_only)
{
int i, mode, modes_defined, errors;
char line[LINEMAX], defstr[DEFMAX], comdef[DEFMAX], modebuf[DEFMAX];
char tmpcomp[LINEMAX], tmpprod[LINEMAX], tmprev[LINEMAX], *cp, c, *t;
char *nextdef, *curdef, *comptr;
static int call_nbr = 0;
call_nbr++;
defs->drive_buffering = (-1);
defs->timeout = (-1);
defs->long_timeout = (-1);
defs->cleaning = (-1);
defs->nowait = (-1);
defs->weof_nowait = (-1);
defs->sili = (-1);
for (i = 0; i < NBR_MODES; i++) {
defs->modedefs[i].defined = FALSE;
defs->modedefs[i].blocksize = (-1);
defs->modedefs[i].density = (-1);
defs->modedefs[i].buffer_writes = (-1);
defs->modedefs[i].async_writes = (-1);
defs->modedefs[i].read_ahead = (-1);
defs->modedefs[i].two_fm = (-1);
defs->modedefs[i].compression = (-1);
defs->modedefs[i].auto_lock = (-1);
defs->modedefs[i].fast_eod = (-1);
defs->modedefs[i].can_bsr = (-1);
defs->modedefs[i].no_blklimits = (-1);
defs->modedefs[i].can_partitions = (-1);
defs->modedefs[i].scsi2logical = (-1);
defs->modedefs[i].sysv = (-1);
defs->modedefs[i].defs_for_writes = (-1);
}
next_block(dbf, NULL, 0, 0);
/* Find matching inquiry block */
for (errors = 0;;) {
if (!next_block(dbf, defstr, DEFMAX, '{'))
break;
find_string(defstr, "manuf", tmpcomp, LINEMAX);
find_string(defstr, "model", tmpprod, LINEMAX);
find_string(defstr, "rev", tmprev, LINEMAX);
if (!next_block(dbf, defstr, DEFMAX, '}')) {
fprintf(stderr,
"End of definition block not found for ('%s', "
"'%s', '%s').\n",
tmpcomp, tmpprod, tmprev);
return FALSE;
}
if (!parse_only) {
if (tmpcomp[0] != '\0' && strncmp(company, tmpcomp, strlen(tmpcomp)))
continue;
if (tmpprod[0] != '\0' && strncmp(product, tmpprod, strlen(tmpprod)))
continue;
if (tmprev[0] != '\0' && strncmp(rev, tmprev, strlen(tmprev)))
continue;
} else if (verbose > 0)
printf("\nParsing modes for ('%s', '%s', '%s').\n", tmpcomp, tmpprod, tmprev);
/* Block found, get the characteristics */
for (nextdef = defstr;
*nextdef != '\0' && (*nextdef != 'm' || strncmp(nextdef, "mode", 2)); nextdef++)
;
c = *nextdef;
*nextdef = '\0';
strcpy(comdef, defstr);
*nextdef = c;
comptr = comdef;
SKIP_WHITE(comptr);
for (; *nextdef != '\0';) {
int tmpsize;
curdef = nextdef;
SKIP_WHITE(curdef);
for (nextdef++;
*nextdef != '\0' && (*nextdef != 'm' || strncmp(nextdef, "mode", 2));
nextdef++)
;
c = *nextdef;
*nextdef = '\0';
mode = strtol(curdef + 4, &cp, 0) - 1;
if (mode < 0 || mode >= NBR_MODES) {
fprintf(stderr, "Illegal mode for ('%s', '%s', '%s'):\n'%s'\n",
tmpcomp, tmpprod, tmprev, curdef);
*nextdef = c;
errors++;
continue;
}
if ((tmpsize = snprintf(modebuf, DEFMAX, "%s%s", comptr, cp)) >= DEFMAX) {
fprintf(stderr, "Definition too large for ('%s', '%s', '%s'): size %d, maximum is %d\n",
tmpcomp, tmpprod, tmprev, tmpsize, DEFMAX);
*nextdef = c;
errors++;
continue;
}
*nextdef = c;
if (verbose > 1)
fprintf(stderr, "Mode %d definition: %s\n", mode + 1, modebuf);
if ((t = find_string(modebuf, "disab", line, LINEMAX)) != NULL &&
strtol(t, NULL, 0) != 0) {
defs->modedefs[mode].defined = FALSE;
continue;
}
if ((t = find_string(modebuf, "drive-", line, LINEMAX)) != NULL)
defs->drive_buffering = num_arg(t);
if ((t = find_string(modebuf, "timeout", line, LINEMAX)) != NULL)
defs->timeout = num_arg(t);
if ((t = find_string(modebuf, "long-time", line, LINEMAX)) != NULL)
defs->long_timeout = num_arg(t);
if ((t = find_string(modebuf, "clean", line, LINEMAX)) != NULL)
defs->cleaning = num_arg(t);
if ((t = find_string(modebuf, "no-w", line, LINEMAX)) != NULL)
defs->nowait = num_arg(t);
if ((t = find_string(modebuf, "weof-n", line, LINEMAX)) != NULL)
defs->weof_nowait = num_arg(t);
if ((t = find_string(modebuf, "sili", line, LINEMAX)) != NULL)
defs->sili = num_arg(t);
defs->modedefs[mode].defined = TRUE;
if ((t = find_string(modebuf, "block", line, LINEMAX)) != NULL)
defs->modedefs[mode].blocksize = num_arg(t);
if ((t = find_string(modebuf, "dens", line, LINEMAX)) != NULL)
defs->modedefs[mode].density = num_arg(t);
if ((t = find_string(modebuf, "buff", line, LINEMAX)) != NULL)
defs->modedefs[mode].buffer_writes = num_arg(t);
if ((t = find_string(modebuf, "async", line, LINEMAX)) != NULL)
defs->modedefs[mode].async_writes = num_arg(t);
if ((t = find_string(modebuf, "read", line, LINEMAX)) != NULL)
defs->modedefs[mode].read_ahead = num_arg(t);
if ((t = find_string(modebuf, "two", line, LINEMAX)) != NULL)
defs->modedefs[mode].two_fm = num_arg(t);
if ((t = find_string(modebuf, "comp", line, LINEMAX)) != NULL)
defs->modedefs[mode].compression = num_arg(t);
if ((t = find_string(modebuf, "auto", line, LINEMAX)) != NULL)
defs->modedefs[mode].auto_lock = num_arg(t);
if ((t = find_string(modebuf, "fast", line, LINEMAX)) != NULL)
defs->modedefs[mode].fast_eod = num_arg(t);
if ((t = find_string(modebuf, "can-b", line, LINEMAX)) != NULL)
defs->modedefs[mode].can_bsr = num_arg(t);
if ((t = find_string(modebuf, "noblk", line, LINEMAX)) != NULL)
defs->modedefs[mode].no_blklimits = num_arg(t);
if ((t = find_string(modebuf, "can-p", line, LINEMAX)) != NULL)
defs->modedefs[mode].can_partitions = num_arg(t);
if ((t = find_string(modebuf, "scsi2", line, LINEMAX)) != NULL)
defs->modedefs[mode].scsi2logical = num_arg(t);
if ((t = find_string(modebuf, "sysv", line, LINEMAX)) != NULL)
defs->modedefs[mode].sysv = num_arg(t);
if ((t = find_string(modebuf, "defs-for-w", line, LINEMAX)) != NULL)
defs->modedefs[mode].defs_for_writes = num_arg(t);
for (t = modebuf; *t == ' ' || *t == '\t'; t++)
;
if (*t != '\0' && call_nbr <= 1) {
fprintf(stderr,
"Warning: errors in definition for ('%s', "
"'%s', '%s'):\n%s\n",
tmpcomp, tmpprod, tmprev, modebuf);
errors++;
}
}
}
if (parse_only) {
if (verbose > 0)
printf("\n");
printf("Definition parse completed. ");
if (errors) {
printf("Errors found!\n");
return FALSE;
} else {
printf("No errors found.\n");
return TRUE;
}
} else {
for (i = modes_defined = 0; i < NBR_MODES; i++)
if (defs->modedefs[i].defined)
modes_defined++;
if (modes_defined == 0) {
fprintf(stderr, "Warning: No modes in definition for ('%s', '%s', '%s').\n",
tmpcomp, tmpprod, tmprev);
errors++;
}
}
if (modes_defined)
return TRUE;
return FALSE;
}
static int sg_io_errcheck(struct sg_io_hdr *hdp)
{
if ((hdp->status & 0x7e) == 0 || hdp->host_status == 0 || hdp->driver_status == 0)
return 0;
return EIO;
}
#define INQUIRY 0x12
#define INQUIRY_CMDLEN 6
#define SENSE_BUFF_LEN 32
#define DEF_TIMEOUT 60000
#ifndef SCSI_IOCTL_SEND_COMMAND
#define SCSI_IOCTL_SEND_COMMAND 1
#endif
#define IOCTL_HEADER_LENGTH 8
static int do_inquiry(char *tname, char *company, char *product, char *rev, int print_non_found)
{
int fn;
int result, *ip, i;
#define BUFLEN 256
unsigned char buffer[BUFLEN], *cmd, *inqptr;
struct sg_io_hdr io_hdr;
unsigned char inqCmdBlk[INQUIRY_CMDLEN] = { INQUIRY, 0, 0, 0, 200, 0 };
unsigned char sense_b[SENSE_BUFF_LEN];
if ((fn = open(tname, O_RDONLY | O_NONBLOCK)) < 0) {
if (print_non_found || verbose > 0) {
if (errno == ENXIO)
fprintf(stderr, "Device '%s' not found by kernel.\n", tname);
else
fprintf(stderr, "Can't open tape device '%s' (errno %d).\n", tname, errno);
}
return FALSE;
}
/* Try SG_IO first, if it is not supported, use SCSI_IOCTL_SEND_COMMAND */
memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
io_hdr.interface_id = 'S';
io_hdr.cmd_len = sizeof(inqCmdBlk);
io_hdr.mx_sb_len = sizeof(sense_b);
io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
io_hdr.dxfer_len = 200;
io_hdr.dxferp = buffer;
io_hdr.cmdp = inqCmdBlk;
io_hdr.sbp = sense_b;
io_hdr.timeout = DEF_TIMEOUT;
inqptr = buffer;
result = ioctl(fn, SG_IO, &io_hdr);
if (!result)
result = sg_io_errcheck(&io_hdr);
if (result) {
if (errno == ENOTTY || errno == EINVAL) {
memset(buffer, 0, BUFLEN);
ip = (int *)&(buffer[0]);
*ip = 0;
*(ip + 1) = BUFLEN - 13;
cmd = &(buffer[8]);
cmd[0] = INQUIRY;
cmd[4] = 200;
result = ioctl(fn, SCSI_IOCTL_SEND_COMMAND, buffer);
inqptr = buffer + IOCTL_HEADER_LENGTH;
}
if (result) {
close(fn);
sprintf((char *)buffer,
"The SCSI INQUIRY for device '%s' failed (power off?)", tname);
perror((char *)buffer);
return FALSE;
}
}
memcpy(company, inqptr + 8, 8);
for (i = 8; i > 0 && company[i - 1] == ' '; i--)
;
company[i] = '\0';
memcpy(product, inqptr + 16, 16);
for (i = 16; i > 0 && product[i - 1] == ' '; i--)
;
product[i] = '\0';
memcpy(rev, inqptr + 32, 4);
for (i = 4; i > 0 && rev[i - 1] == ' '; i--)
;
rev[i] = '\0';
close(fn);
return TRUE;
}
static int tapenum(char *name)
{
int dev;
struct dirent *dent;
DIR *dirp;
char tmpname[PATH_MAX];
const char *dn;
const devdir *dvd;
struct stat statbuf;
if (strchr(name, '/') != NULL) { /* Complete name */
if (stat(name, &statbuf) != 0) {
fprintf(stderr, "Can't stat '%s'.\n", name);
return (-1);
}
if (!S_ISCHR(statbuf.st_mode) || major(statbuf.st_rdev) != SCSI_TAPE_MAJOR)
return (-1);
dev = minor(statbuf.st_rdev) & 31;
return dev;
} else { /* Search from the device directories */
for (dvd = devdirs; dvd->dir[0] != 0; dvd++) {
dn = dvd->dir;
if ((dirp = opendir(dn)) == NULL)
continue;
for (; (dent = readdir(dirp)) != NULL;)
if (!strcmp(dent->d_name, name)) {
strcpy(tmpname, dn);
strcat(tmpname, "/");
strcat(tmpname, dent->d_name);
if (stat(tmpname, &statbuf) != 0) {
fprintf(stderr, "Can't stat '%s'.\n", tmpname);
continue;
}
if (!S_ISCHR(statbuf.st_mode) || major(statbuf.st_rdev) != SCSI_TAPE_MAJOR)
continue;
dev = minor(statbuf.st_rdev) & 31;
closedir(dirp);
return dev;
}
closedir(dirp);
}
}
return (-1);
}
static int accept_tape_name(char *name)
{
char **npp;
for (npp = tape_name_bases; *npp; npp++)
if (!strncmp(name, *npp, strlen(*npp)))
return TRUE;
return FALSE;
}
static int find_devfiles(int tapeno, char **names)
{
int dev, mode, found;
int non_rew[NBR_MODES];
struct dirent *dent;
DIR *dirp;
char tmpname[PATH_MAX];
const char *dn;
static const devdir *dvd;
const devdir *dvp;
int tmpdevdirsindex = 0;
static devdir tmpdevdirs[MAX_TAPES + 1];
struct stat statbuf;
for (found = 0; found < NBR_MODES; found++) {
*names[found] = '\0';
non_rew[found] = FALSE;
}
if (dvd == NULL && !stat(DEVFS_PATH, &statbuf)) {
if (S_ISDIR(statbuf.st_mode) && (dirp = opendir(DEVFS_PATH)) != NULL) {
/* Assume devfs, one directory for each tape */
for (; (dent = readdir(dirp)) != NULL;) {
if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
continue;
snprintf(tmpdevdirs[tmpdevdirsindex].dir,
sizeof(tmpdevdirs[tmpdevdirsindex].dir), "%s/%s",
DEVFS_PATH, dent->d_name);
tmpdevdirs[tmpdevdirsindex].selective_scan = FALSE;
if (++tmpdevdirsindex == MAX_TAPES)
break;
}
tmpdevdirs[tmpdevdirsindex].dir[0] = 0;
closedir(dirp);
dvd = &tmpdevdirs[0];
}
}
if (dvd == NULL)
dvd = devdirs;
for (found = 0, dvp = dvd; found < NBR_MODES && dvp->dir[0] != 0; dvp++) {
dn = dvp->dir;
if ((dirp = opendir(dn)) == NULL)
continue;
for (; (dent = readdir(dirp)) != NULL;) {
if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
continue;
/* Ignore non-tape devices to avoid loading all the modules */
if (dvp->selective_scan && !accept_tape_name(dent->d_name))
continue;
strcpy(tmpname, dn);
strcat(tmpname, "/");
strcat(tmpname, dent->d_name);
if (stat(tmpname, &statbuf) != 0) {
fprintf(stderr, "Can't stat '%s'.\n", tmpname);
continue;
}
if (!S_ISCHR(statbuf.st_mode) || major(statbuf.st_rdev) != SCSI_TAPE_MAJOR)
continue;
dev = minor(statbuf.st_rdev);
if ((dev & 31) != tapeno)
continue;
mode = (dev & 127) >> 5;
if (non_rew[mode])
continue;
if (*names[mode] == '\0')
found++;
strcpy(names[mode], tmpname);
non_rew[mode] = (dev & 128) != 0;
}
closedir(dirp);
}
return (found > 0);
}
static int set_defs(devdef_tr *defs, char **fnames)
{
int i, tape, fails;
int clear_set[2];
struct mtop op;
for (i = fails = 0; i < NBR_MODES; i++) {
if (*fnames[i] == '\0' || !defs->modedefs[i].defined)
continue;
if ((tape = open(fnames[i], O_RDONLY | O_NONBLOCK)) < 0) {
fprintf(stderr, "Can't open the tape device '%s' for mode %d.\n",
fnames[i], i);
return FALSE;
}
if (i == 0) {
if (defs->do_rewind) {
op.mt_op = MTREW;
op.mt_count = 1;
if (ioctl(tape, MTIOCTOP, &op) != 0) {
fails++;
fprintf(stderr, "Rewind of %s fails.\n", fnames[i]);
}
}
if (defs->drive_buffering >= 0) {
op.mt_op = MTSETDRVBUFFER;
op.mt_count = MT_ST_DEF_DRVBUFFER | defs->drive_buffering;
if (ioctl(tape, MTIOCTOP, &op) != 0) {
fails++;
fprintf(stderr, "Can't set drive buffering to %d.\n",
defs->drive_buffering);
}
}
if (defs->timeout >= 0) {
op.mt_op = MTSETDRVBUFFER;
op.mt_count = MT_ST_SET_TIMEOUT | defs->timeout;
if (ioctl(tape, MTIOCTOP, &op) != 0) {
fails++;
fprintf(stderr, "Can't set device timeout %d s.\n",
defs->timeout);
}
}
if (defs->long_timeout >= 0) {
op.mt_op = MTSETDRVBUFFER;
op.mt_count = MT_ST_SET_LONG_TIMEOUT | defs->long_timeout;
if (ioctl(tape, MTIOCTOP, &op) != 0) {
fails++;
fprintf(stderr, "Can't set device long timeout %d s.\n",
defs->long_timeout);
}
}
if (defs->cleaning >= 0) {
op.mt_op = MTSETDRVBUFFER;
op.mt_count = MT_ST_SET_CLN | defs->cleaning;
if (ioctl(tape, MTIOCTOP, &op) != 0) {
fails++;
fprintf(stderr, "Can't set cleaning request parameter to %x\n",
defs->cleaning);
}
}
}
op.mt_op = MTSETDRVBUFFER;
clear_set[0] = clear_set[1] = 0;
if (defs->nowait >= 0)
clear_set[defs->nowait != 0] |= MT_ST_NOWAIT;
if (defs->weof_nowait >= 0)
clear_set[defs->weof_nowait != 0] |= MT_ST_NOWAIT_EOF;
if (defs->sili >= 0)
clear_set[defs->sili != 0] |= MT_ST_SILI;
if (defs->modedefs[i].buffer_writes >= 0)
clear_set[defs->modedefs[i].buffer_writes != 0] |= MT_ST_BUFFER_WRITES;
if (defs->modedefs[i].async_writes >= 0)
clear_set[defs->modedefs[i].async_writes != 0] |= MT_ST_ASYNC_WRITES;
if (defs->modedefs[i].read_ahead >= 0)
clear_set[defs->modedefs[i].read_ahead != 0] |= MT_ST_READ_AHEAD;
if (defs->modedefs[i].two_fm >= 0)
clear_set[defs->modedefs[i].two_fm != 0] |= MT_ST_TWO_FM;
if (defs->modedefs[i].fast_eod >= 0)
clear_set[defs->modedefs[i].fast_eod != 0] |= MT_ST_FAST_MTEOM;
if (defs->modedefs[i].auto_lock >= 0)
clear_set[defs->modedefs[i].auto_lock != 0] |= MT_ST_AUTO_LOCK;
if (defs->modedefs[i].can_bsr >= 0)
clear_set[defs->modedefs[i].can_bsr != 0] |= MT_ST_CAN_BSR;
if (defs->modedefs[i].no_blklimits >= 0)
clear_set[defs->modedefs[i].no_blklimits != 0] |= MT_ST_NO_BLKLIMS;
if (defs->modedefs[i].can_partitions >= 0)
clear_set[defs->modedefs[i].can_partitions != 0] |= MT_ST_CAN_PARTITIONS;
if (defs->modedefs[i].scsi2logical >= 0)
clear_set[defs->modedefs[i].scsi2logical != 0] |= MT_ST_SCSI2LOGICAL;
if (defs->modedefs[i].sysv >= 0)
clear_set[defs->modedefs[i].sysv != 0] |= MT_ST_SYSV;
if (defs->modedefs[i].defs_for_writes >= 0)
clear_set[defs->modedefs[i].defs_for_writes != 0] |= MT_ST_DEF_WRITES;
if (clear_set[0] != 0) {
op.mt_count = MT_ST_CLEARBOOLEANS | clear_set[0];
if (ioctl(tape, MTIOCTOP, &op) != 0) {
fails++;
fprintf(stderr, "Can't clear the tape options (bits 0x%x, mode %d).\n",
clear_set[0], i);
}
}
if (clear_set[1] != 0) {
op.mt_count = MT_ST_SETBOOLEANS | clear_set[1];
if (ioctl(tape, MTIOCTOP, &op) != 0) {
fails++;
fprintf(stderr, "Can't set the tape options (bits 0x%x, mode %d).\n",
clear_set[1], i);
}
}
if (defs->modedefs[i].blocksize >= 0) {
op.mt_count = MT_ST_DEF_BLKSIZE | defs->modedefs[i].blocksize;
if (ioctl(tape, MTIOCTOP, &op) != 0) {
fails++;
fprintf(stderr, "Can't set blocksize %d for mode %d.\n",
defs->modedefs[i].blocksize, i);
}
}
if (defs->modedefs[i].density >= 0) {
op.mt_count = MT_ST_DEF_DENSITY | defs->modedefs[i].density;
if (ioctl(tape, MTIOCTOP, &op) != 0) {
fails++;
fprintf(stderr, "Can't set density %x for mode %d.\n",
defs->modedefs[i].density, i);
}
}
if (defs->modedefs[i].compression >= 0) {
op.mt_count = MT_ST_DEF_COMPRESSION | defs->modedefs[i].compression;
if (ioctl(tape, MTIOCTOP, &op) != 0) {
fails++;
fprintf(stderr, "Can't set compression %d for mode %d.\n",
defs->modedefs[i].compression, i);
}
}
close(tape);
}
return (fails == 0);
}
static int define_tape(int tapeno, FILE *dbf, devdef_tr *defptr, int print_non_found)
{
int i;
char company[10], product[20], rev[5], *tname, *fnames[NBR_MODES];
if (verbose > 0)
printf("\nstinit, processing tape %d\n", tapeno);
if ((fnames[0] = calloc(NBR_MODES, PATH_MAX)) == NULL) {
fprintf(stderr, "Can't allocate name buffers.\n");
return FALSE;
}
for (i = 1; i < NBR_MODES; i++)
fnames[i] = fnames[i - 1] + PATH_MAX;
if (!find_devfiles(tapeno, fnames) || *fnames[0] == '\0') {
if (print_non_found)
fprintf(stderr, "Can't find any device files for tape %d.\n", tapeno);
free(fnames[0]);
return FALSE;
}
if (verbose > 1)
for (i = 0; i < NBR_MODES; i++)
printf("Mode %d, name '%s'\n", i + 1, fnames[i]);
tname = fnames[0];
if (!do_inquiry(tname, company, product, rev, print_non_found)) {
free(fnames[0]);
return FALSE;
}
if (verbose > 0)
printf("The manufacturer is '%s', product is '%s', and revision "
"'%s'.\n",
company, product, rev);
if (!find_pars(dbf, company, product, rev, defptr, FALSE)) {
fprintf(stderr, "Can't find defaults for tape number %d.\n", tapeno);
free(fnames[0]);
return FALSE;
}
if (!set_defs(defptr, fnames)) {
free(fnames[0]);
return FALSE;
}
free(fnames[0]);
return TRUE;
}
static char usage(int retval)
{
fprintf(stderr, "Usage: stinit [-h] [-v] [--version] [-f dbname] [-p] [-r] "
"[drivename_or_number ...]\n");
exit(retval);
}
int main(int argc, char **argv)
{
FILE *dbf = NULL;
int argn, retval = 0;
int tapeno, parse_only = FALSE;
char *dbname = NULL;
char *convp;
devdef_tr defs;
defs.do_rewind = FALSE;
for (argn = 1; argn < argc && *argv[argn] == '-'; argn++) {
if (*(argv[argn] + 1) == 'v')
verbose++;
else if (*(argv[argn] + 1) == 'p')
parse_only = TRUE;
else if (*(argv[argn] + 1) == 'h')
usage(0);
else if (*(argv[argn] + 1) == 'r')
defs.do_rewind = TRUE;
else if (*(argv[argn] + 1) == 'f') {
argn += 1;
if (argn >= argc)
usage(1);
dbname = argv[argn];
} else if (*(argv[argn] + 1) == '-' && *(argv[argn] + 2) == 'v') {
printf("stinit v. %s\n", VERSION);
exit(0);
break;
} else
usage(1);
}
if ((dbf = open_database(dbname)) == NULL)
return 1;
if (parse_only) {
if (argc > argn)
fprintf(stderr, "Extra arguments on command line ignored.\n");
if (!find_pars(dbf, "xyz", "xyz", "xyz", &defs, TRUE))
return 1;
return 0;
}
if (argc > argn) { /* Initialize specific drives */
for (; argn < argc; argn++) {
if (*argv[argn] == '-') {
usage(1);
} else if (isdigit(*argv[argn])) {
tapeno = strtol(argv[argn], &convp, 0);
if (*argv[argn] != '\0' && *convp != '\0') {
fprintf(stderr,
"Invalid tape device index '%s': don't "
"know how to parse '%s'\n",
argv[argn], convp);
continue;
}
} else if ((tapeno = tapenum(argv[argn])) < 0) {
fprintf(stderr, "Can't find tape number for name '%s'.\n", argv[argn]);
continue;
}
if (!define_tape(tapeno, dbf, &defs, TRUE)) {
fprintf(stderr, "Definition for '%s' failed.\n", argv[argn]);
retval = 1;
}
}
} else { /* Initialize all SCSI tapes */
for (tapeno = 0; tapeno < MAX_TAPES; tapeno++)
if (!define_tape(tapeno, dbf, &defs, FALSE)) {
fprintf(stderr, "Initialized %d tape device%s.\n", tapeno,
(tapeno != 1 ? "s" : ""));
return 0; /* Process tapes until failure */
}
}
return retval;
}