Files
mt-st/stinit.c
Iustin Pop 0ee3591e51 Rework the dist target and drop LSM file
Short of moving to autotools, this is the best that can be done:

- move the version from hardcoded in the .c files, to a
  dynamically-built `version.h` file so that we only declare the
  version in one place
- build a better dist file (.tar.gz) by explicitly selecting which
  files to copy, instead of unbounded recursion from the source
  directory
- ensure that the files being copied to the archive have a sane
  user/group and mode
- add a distcheck target that simply reuses the archive to build and
  run the programs, and then regenerate the archive from itself

autotools would solve all this by default, but still feels too
heavyweight for just two .c files.

Additionall, drop the .lsm file. It seems mostly useless these days;
I'll be happy to reinstate it however if anyone cares.
2016-02-07 20:38:27 +01:00

967 lines
24 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/sysmacros.h>
#include <linux/major.h>
#include <scsi/sg.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 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 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
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, int buflen, int limiter)
{
int 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) >= DEFMAX) {
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];
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->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'; ) {
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;
}
strcpy(defstr, comptr);
strcat(defstr, cp);
*nextdef = c;
if (verbose > 1)
fprintf(stderr, "Mode %d definition: %s\n", mode + 1, defstr);
if ((t = find_string(defstr, "disab", line, LINEMAX)) != NULL &&
strtol(t, NULL, 0) != 0) {
defs->modedefs[mode].defined = FALSE;
continue;
}
if ((t = find_string(defstr, "drive-", line, LINEMAX)) != NULL)
defs->drive_buffering = num_arg(t);
if ((t = find_string(defstr, "timeout", line, LINEMAX)) != NULL)
defs->timeout = num_arg(t);
if ((t = find_string(defstr, "long-time", line, LINEMAX)) != NULL)
defs->long_timeout = num_arg(t);
if ((t = find_string(defstr, "clean", line, LINEMAX)) != NULL)
defs->cleaning = num_arg(t);
if ((t = find_string(defstr, "no-w", line, LINEMAX)) != NULL)
defs->nowait = num_arg(t);
if ((t = find_string(defstr, "sili", line, LINEMAX)) != NULL)
defs->sili = num_arg(t);
defs->modedefs[mode].defined = TRUE;
if ((t = find_string(defstr, "block", line, LINEMAX)) != NULL)
defs->modedefs[mode].blocksize = num_arg(t);
if ((t = find_string(defstr, "dens", line, LINEMAX)) != NULL)
defs->modedefs[mode].density = num_arg(t);
if ((t = find_string(defstr, "buff", line, LINEMAX)) != NULL)
defs->modedefs[mode].buffer_writes = num_arg(t);
if ((t = find_string(defstr, "async", line, LINEMAX)) != NULL)
defs->modedefs[mode].async_writes = num_arg(t);
if ((t = find_string(defstr, "read", line, LINEMAX)) != NULL)
defs->modedefs[mode].read_ahead = num_arg(t);
if ((t = find_string(defstr, "two", line, LINEMAX)) != NULL)
defs->modedefs[mode].two_fm = num_arg(t);
if ((t = find_string(defstr, "comp", line, LINEMAX)) != NULL)
defs->modedefs[mode].compression = num_arg(t);
if ((t = find_string(defstr, "auto", line, LINEMAX)) != NULL)
defs->modedefs[mode].auto_lock = num_arg(t);
if ((t = find_string(defstr, "fast", line, LINEMAX)) != NULL)
defs->modedefs[mode].fast_eod = num_arg(t);
if ((t = find_string(defstr, "can-b", line, LINEMAX)) != NULL)
defs->modedefs[mode].can_bsr = num_arg(t);
if ((t = find_string(defstr, "noblk", line, LINEMAX)) != NULL)
defs->modedefs[mode].no_blklimits = num_arg(t);
if ((t = find_string(defstr, "can-p", line, LINEMAX)) != NULL)
defs->modedefs[mode].can_partitions = num_arg(t);
if ((t = find_string(defstr, "scsi2", line, LINEMAX)) != NULL)
defs->modedefs[mode].scsi2logical = num_arg(t);
if ((t = find_string(defstr, "sysv", line, LINEMAX)) != NULL)
defs->modedefs[mode].sysv = num_arg(t);
if ((t = find_string(defstr, "defs-for-w", line, LINEMAX)) != NULL)
defs->modedefs[mode].defs_for_writes = num_arg(t);
for (t=defstr; *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, defstr);
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;
int clear_set[2];
struct mtop op;
for (i=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;
ioctl(tape, MTIOCTOP, &op); /* Don't worry about result */
}
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) {
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) {
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) {
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) {
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->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) {
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) {
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) {
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) {
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) {
fprintf(stderr, "Can't set compression %d for mode %d.\n",
defs->modedefs[i].compression, i);
}
}
close(tape);
}
return TRUE;
}
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;
int tapeno, parse_only = FALSE;
char *dbname = NULL;
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);
return 1; /* Never executed but makes gcc happy */
}
else if (isdigit(*argv[argn]))
tapeno = strtol(argv[argn], NULL, 0);
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]);
}
}
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 0;
}