mirror of
https://github.com/iustin/mt-st.git
synced 2026-01-10 21:50:13 +00:00
Compare commits
54 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a07846b2e3 | ||
|
|
a684fe5a15 | ||
|
|
70b24634cf | ||
|
|
a76e4ce544 | ||
|
|
26392d9ae4 | ||
|
|
1a074e2c65 | ||
|
|
ba46d54458 | ||
|
|
d4c8e67be0 | ||
|
|
e14e9af952 | ||
|
|
32fba27f78 | ||
|
|
aa6539b4b1 | ||
|
|
0c7307cc7a | ||
|
|
72d53ae798 | ||
|
|
b11887d9b4 | ||
|
|
459ab4775b | ||
|
|
85738cedc1 | ||
|
|
82d569b489 | ||
|
|
547bc649a9 | ||
|
|
5ec6428297 | ||
|
|
7aa498640d | ||
|
|
ba594d1e78 | ||
|
|
e6f79d85ec | ||
|
|
42dd44bb90 | ||
|
|
ff108770be | ||
|
|
9c8f170d4a | ||
|
|
72f9eda87d | ||
|
|
eadc992f2a | ||
|
|
e8e6d543de | ||
|
|
34978b4019 | ||
|
|
8056c1542a | ||
|
|
c36a4a0fa5 | ||
|
|
f9c0570e34 | ||
|
|
aec3bd67f6 | ||
|
|
52a6c218b9 | ||
|
|
4a72962872 | ||
|
|
c49c863a2a | ||
|
|
b6d221c17a | ||
|
|
e96400b602 | ||
|
|
3c537a17e2 | ||
|
|
bd3b8539d1 | ||
|
|
07e9cd2653 | ||
|
|
1dafc02c2e | ||
|
|
d7e60146d2 | ||
|
|
4fdbc29fed | ||
|
|
fbfd923faa | ||
|
|
886ce1f261 | ||
|
|
1743522b8a | ||
|
|
c33c6ad43e | ||
|
|
51b0d3da23 | ||
|
|
3241491f72 | ||
|
|
5a88467b88 | ||
|
|
9759c9c469 | ||
|
|
5dbcde9d0d | ||
|
|
7366f37f69 |
100
.github/workflows/ci.yml
vendored
Normal file
100
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
on:
|
||||
# Trigger the workflow on push or
|
||||
# pull request, but only for the
|
||||
# main branch.
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
# Weekly run to account for
|
||||
# changed dependencies.
|
||||
schedule:
|
||||
- cron: "17 04 * * 0"
|
||||
# Manual trigger
|
||||
workflow_dispatch:
|
||||
|
||||
name: CI
|
||||
jobs:
|
||||
build:
|
||||
name: Build and test
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest]
|
||||
compiler: ["gcc", "clang"]
|
||||
fail-fast: false
|
||||
env:
|
||||
CC: ${{ matrix.compiler }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Build the code
|
||||
run: make
|
||||
|
||||
- name: Install dependencies
|
||||
run: sudo apt-get install -yy shelltestrunner
|
||||
|
||||
- name: Test creating the release archive
|
||||
run: make distcheck
|
||||
|
||||
coverage:
|
||||
name: Check code coverage
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CC: gcc
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install dependencies
|
||||
run: sudo apt-get install -yy shelltestrunner
|
||||
|
||||
- name: Build the code
|
||||
run: make CFLAGS=-coverage
|
||||
|
||||
- name: Run tests under coverage
|
||||
run: make check
|
||||
|
||||
- name: Upload coverage to Codecov
|
||||
uses: codecov/codecov-action@v5
|
||||
with:
|
||||
name: codecov-gcc
|
||||
fail_ci_if_error: true
|
||||
verbose: true
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
sanitizers:
|
||||
name: Test with clang sanitizers
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest]
|
||||
compiler: ["clang"]
|
||||
# These are the various sanitizers from https://github.com/google/sanitizers:
|
||||
cflags:
|
||||
- "-fsanitize=address -O1 -fno-omit-frame-pointer -g"
|
||||
- "-fsanitize=memory -fsanitize-memory-track-origins -fPIE -pie -fno-omit-frame-pointer -g -O2"
|
||||
- "-fsanitize=undefined"
|
||||
|
||||
fail-fast: false
|
||||
env:
|
||||
CC: ${{ matrix.compiler }}
|
||||
CFLAGS: ${{ matrix.cflags }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Build the code
|
||||
run: make
|
||||
|
||||
- name: Install dependencies
|
||||
run: sudo apt-get install -yy shelltestrunner
|
||||
|
||||
- name: Run tests
|
||||
run: make check
|
||||
64
.github/workflows/codeql-analysis.yml
vendored
Normal file
64
.github/workflows/codeql-analysis.yml
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [main]
|
||||
schedule:
|
||||
- cron: "0 5 * * 1"
|
||||
# Manual run:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
# Override automatic language detection by changing the below list
|
||||
# Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
|
||||
language: ["cpp"]
|
||||
# Learn more...
|
||||
# https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
# We must fetch at least the immediate parents so that if this is
|
||||
# a pull request then we can checkout the head.
|
||||
fetch-depth: 2
|
||||
|
||||
# If this run was triggered by a pull request event, then checkout
|
||||
# the head of the pull request instead of the merge commit.
|
||||
- run: git checkout HEAD^2
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -8,4 +8,10 @@
|
||||
/mt
|
||||
/stinit
|
||||
/version.h
|
||||
/mt-st-*.tar.gz
|
||||
/mt-st-*.tar.gz*
|
||||
/out/
|
||||
/mt.gcda
|
||||
/mt.gcno
|
||||
/stinit.gcda
|
||||
/stinit.gcno
|
||||
/lcov.info
|
||||
|
||||
15
.travis.yml
15
.travis.yml
@@ -1,15 +0,0 @@
|
||||
#
|
||||
# travis-ci configuration file
|
||||
#
|
||||
language: c
|
||||
# No tests or configuration steps for now
|
||||
script: make && make distcheck
|
||||
# Build with both gcc and clang
|
||||
compiler:
|
||||
- clang
|
||||
- gcc
|
||||
# Just in case the defaults change, we're only interested in Linux:
|
||||
os:
|
||||
- linux
|
||||
# Use a recent GCC, as otherwise things seem weird
|
||||
dist: bionic
|
||||
4
.vscode/settings.json
vendored
Normal file
4
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"spellright.language": ["en"],
|
||||
"spellright.documentTypes": ["markdown", "latex", "plaintext"]
|
||||
}
|
||||
44
CHANGELOG.md
44
CHANGELOG.md
@@ -1,5 +1,49 @@
|
||||
# Changelog
|
||||
|
||||
## Changes in version 1.8 (Sat, 08 Feb 2025)
|
||||
|
||||
After almost two years, a number of minor fixes and improvements have accumulated:
|
||||
|
||||
- A number of density code updates: LTO-9, 9track Reels, IBM 3480 and 3490E
|
||||
(from Chris Dinneen) and IBM 3592 (Kai Mäkisara)
|
||||
- Fix write protect reporting (Kai Mäkisara)
|
||||
- Implement support for the `MT_ST_NOWAIT_EOF` flag, via the new `weof-no-wait`
|
||||
for stinit (Kai Mäkisara)
|
||||
- While at it, correctly report errors if some options cannot be set, rather
|
||||
than pretending all is good (also Kai Mäkisara)
|
||||
- Improve the bash completion code to handle option completion better (Chris
|
||||
Dinneen)
|
||||
- Very minor build system improvements and coverage extension (Iustin Pop)
|
||||
|
||||
Thanks Kai and Chris for the many improvements!
|
||||
|
||||
## Changes in version 1.7 (Thu, 20 Apr 2023)
|
||||
|
||||
Fixes a single bug in stinit parsing of invalid definitions. This is a
|
||||
trivial bug, and only affects config files manually installed by root,
|
||||
so the impact should be minimal.
|
||||
|
||||
The bug also does not appear on amd64/x86, but (in Debian) was only
|
||||
triggered (as undefined behaviour) on mips64el, arm64 and s390x,
|
||||
likely due to different platform behaviour.
|
||||
|
||||
## Changes in version 1.6 (Wed, 19 Apr 2023)
|
||||
|
||||
This is bugfix release agains 1.5. In between 1.4 and 1.5, the "make
|
||||
check" target was migrated to using
|
||||
[shelltest](https://github.com/simonmichael/shelltestrunner), but the
|
||||
`make dist` and `distcheck` targets were no, so the built archive was
|
||||
actually not. This only fixes that and has no functional code changes
|
||||
from 1.5.
|
||||
|
||||
## Changes in version 1.5 (Wed, 19 Apr 2023)
|
||||
|
||||
Trivial release:
|
||||
|
||||
- add IBM 3590 B/E format to tape densities table (Chris Dinneen).
|
||||
|
||||
Thanks!
|
||||
|
||||
## Changes in version 1.4 (Sun, 30 Aug 2020)
|
||||
|
||||
Small bugfixes and improvements release:
|
||||
|
||||
33
Makefile
33
Makefile
@@ -28,7 +28,10 @@ DISTFILES = \
|
||||
.dir-locals.el \
|
||||
.clang-format
|
||||
|
||||
VERSION=1.4
|
||||
TESTFILES = $(wildcard tests/*.test)
|
||||
TESTDATAFILES = $(wildcard tests/data/*)
|
||||
|
||||
VERSION=1.8
|
||||
RELEASEDIR=mt-st-$(VERSION)
|
||||
TARFILE=mt-st-$(VERSION).tar.gz
|
||||
|
||||
@@ -58,7 +61,10 @@ dist:
|
||||
trap "rm -rf $$BASE" EXIT && \
|
||||
DIST="$$BASE/$(RELEASEDIR)" && \
|
||||
mkdir "$$DIST" && \
|
||||
$(INSTALL) -m 0644 -p -t "$$DIST/" $(DISTFILES) && \
|
||||
mkdir "$$DIST/tests" && mkdir "$$DIST/tests/data" && \
|
||||
$(INSTALL) -m 0644 -p -t "$$DIST/" $(DISTFILES) && \
|
||||
$(INSTALL) -m 0644 -p -t "$$DIST/tests" $(TESTFILES) && \
|
||||
$(INSTALL) -m 0644 -p -t "$$DIST/tests/data" $(TESTDATAFILES) && \
|
||||
tar czvf $(TARFILE) -C "$$BASE" \
|
||||
--owner root --group root \
|
||||
$(RELEASEDIR)
|
||||
@@ -71,12 +77,7 @@ distcheck: dist
|
||||
tar xvf $(TARFILE) -C "$$SRC" && \
|
||||
cd "$$SRC/$(RELEASEDIR)" && \
|
||||
make CFLAGS="-Wall -Wextra -Werror" && \
|
||||
echo Checking version output && \
|
||||
./mt --version && ./stinit --version && \
|
||||
echo Checking parse status && \
|
||||
./stinit -p -f stinit.def.examples && \
|
||||
echo Checking complete stinit parsing && \
|
||||
( ./stinit -v -v -p -f stinit.def.examples 2>&1 | grep -q 'Mode 1 definition: scsi2logical=1 can-bsr=1 auto-lock=0 two-fms=0 drive-buffering=1 buffer-writes read-ahead=1 async-writes=1 can-partitions=0 fast-eom=1 blocksize=0 sili=1 timeout=900 long-timeout=14400 density=0x44 compression=0' ) && \
|
||||
make check && \
|
||||
make dist && \
|
||||
make install DESTDIR="$$DST" && \
|
||||
numfiles=$$( \
|
||||
@@ -86,11 +87,23 @@ distcheck: dist
|
||||
echo "$$numfiles files installed (5 expected)" && \
|
||||
test "$$numfiles" -eq 5
|
||||
|
||||
check: $(PROGS)
|
||||
shelltest -DVERSION=$(VERSION) tests
|
||||
|
||||
# This needs lcov installed, and it's useful for local testing.
|
||||
coverage: clean
|
||||
$(MAKE) CFLAGS=-coverage
|
||||
$(MAKE) check
|
||||
lcov --capture --directory . --no-external --output-file lcov.info
|
||||
genhtml lcov.info --output-directory out
|
||||
|
||||
|
||||
release-tag:
|
||||
git tag -s -m 'Release version $(VERSION).' mt-st-$(VERSION)
|
||||
git tag -s -m 'Release version $(VERSION)' v$(VERSION)
|
||||
|
||||
clean:
|
||||
rm -f *~ \#*\# *.o $(PROGS) version.h
|
||||
rm -f *~ \#*\# *.o *.gcno *.gcda coverage.info $(PROGS) version.h
|
||||
rm -rf out
|
||||
|
||||
reindent:
|
||||
clang-format -i mt.c stinit.c
|
||||
|
||||
@@ -11,8 +11,12 @@ Iustin Pop (<iustin@k1024.org>). For copyright information, see the
|
||||
For more information, bug reports and the source code repository,
|
||||
please see the project homepage at <https://github.com/iustin/mt-st>.
|
||||
|
||||
Build status:
|
||||
[](https://travis-ci.org/iustin/mt-st)
|
||||
[](https://github.com/iustin/mt-st/actions/workflows/ci.yml)
|
||||
[](https://codecov.io/gh/iustin/mt-st)
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
## mt
|
||||
|
||||
|
||||
@@ -6,7 +6,8 @@ _mt () {
|
||||
_init_completion || return
|
||||
|
||||
#possible commands
|
||||
commands="weof wset eof fsf fsfm bsf bsfm fsr bsr fss bss rewind offline rewoffl eject retension eod seod seek tell status erase setblk lock unlock load compression setdensity drvbuffer stwrthreshold stoptions stsetoptions stclearoptions defblksize defdensity defdrvbuffer defcompression stsetcln sttimeout stlongtimeout densities setpartition mkpartition partseek asf stshowopt"
|
||||
commands="weof wset eof fsf fsfm bsf bsfm fsr bsr fss bss rewind offline rewoffl eject retension eod seod seek tell status erase setblk lock unlock load compression setdensity drvbuffer stwrthreshold stoptions stsetoptions stclearoptions defblksize defdensity defdrvbuffer defcompression stsetcln sttimeout stlongtimeout densities setpartition mkpartition partseek asf stshowoptions"
|
||||
stoptions="buffer-writes async-writes read-ahead debug two-fms fast-eod no-wait weof-no-wait auto-lock def-writes can-bsr no-blklimits can-partitions scsi2logical sili sysv"
|
||||
|
||||
COMPREPLY=()
|
||||
|
||||
@@ -22,8 +23,19 @@ _mt () {
|
||||
COMPREPLY=($(compgen -W "$devs" -- "$cur"))
|
||||
return
|
||||
;;
|
||||
stsetoptions)
|
||||
# show list of stoptions
|
||||
COMPREPLY=($(compgen -W "$stoptions" -- "$cur"))
|
||||
return
|
||||
;;
|
||||
esac
|
||||
|
||||
# if "$prev" is a substring of "$stoptions" show more "$stoptions"
|
||||
if [[ "$stoptions" == *"$prev"* ]]; then
|
||||
COMPREPLY=($(compgen -W "$stoptions" -- "$cur"))
|
||||
return
|
||||
fi
|
||||
|
||||
if [[ $cur == -* ]]; then
|
||||
COMPREPLY=($(compgen -W '-f -v' -- "$cur"))
|
||||
return
|
||||
|
||||
2
mt.1
2
mt.1
@@ -187,6 +187,8 @@ write two filemarks when file closed
|
||||
space directly to eod (and lose file number)
|
||||
.IP no-wait
|
||||
don't wait until rewind, etc. complete
|
||||
.IP weof-no-wait
|
||||
don't wait until writing filemarks completes
|
||||
.IP auto-lock
|
||||
automatically lock/unlock drive door
|
||||
.IP def-writes
|
||||
|
||||
44
mt.c
44
mt.c
@@ -135,16 +135,25 @@ static struct densities {
|
||||
char *name;
|
||||
} density_tbl[] = {
|
||||
/* clang-format off */
|
||||
/* Information taken from https://www.t10.org/ftp/x3t9.2/document.93/93-013r0.pdf:
|
||||
* NZRI: Non-Return to Zero, change on ones
|
||||
* GCR: Group Code Recording
|
||||
* PE: Phase Encoding
|
||||
* IMFM: Inverted Modified Frequency Modulation
|
||||
* MFM: Modified Frequency Modulation
|
||||
* DDS: DAT Data Storage
|
||||
* RLL: Run Length Limited
|
||||
*/
|
||||
{ 0x00, "default" },
|
||||
{ 0x01, "NRZI (800 bpi)" },
|
||||
{ 0x02, "PE (1600 bpi)" },
|
||||
{ 0x03, "GCR (6250 bpi)" },
|
||||
{ 0x01, "NRZI (800 bpi) 9 Track Reel" },
|
||||
{ 0x02, "PE (1600 bpi) 9 Track Reel" },
|
||||
{ 0x03, "GCR (6250 bpi) 9 Track Reel" },
|
||||
{ 0x04, "QIC-11" },
|
||||
{ 0x05, "QIC-45/60 (GCR, 8000 bpi)" },
|
||||
{ 0x06, "PE (3200 bpi)" },
|
||||
{ 0x06, "PE (3200 bpi) 9 Track Reel" },
|
||||
{ 0x07, "IMFM (6400 bpi)" },
|
||||
{ 0x08, "GCR (8000 bpi)" },
|
||||
{ 0x09, "GCR (37871 bpi)" },
|
||||
{ 0x09, "3480/3490E, GCR (37871 bpi)" },
|
||||
{ 0x0a, "MFM (6667 bpi)" },
|
||||
{ 0x0b, "PE (1600 bpi)" },
|
||||
{ 0x0c, "GCR (12960 bpi)" },
|
||||
@@ -175,7 +184,8 @@ static struct densities {
|
||||
{ 0x26, "DDS-4 or QIC-4GB" },
|
||||
{ 0x27, "Exabyte Mammoth" },
|
||||
{ 0x28, "Exabyte Mammoth-2" },
|
||||
{ 0x29, "QIC-3080MC" },
|
||||
{ 0x29, "QIC-3080MC, IBM 3590 B" },
|
||||
{ 0x2a, "IBM 3590 E" },
|
||||
{ 0x30, "AIT-1 or MLR3" },
|
||||
{ 0x31, "AIT-2" },
|
||||
{ 0x32, "AIT-3 or SLR7" },
|
||||
@@ -195,20 +205,27 @@ static struct densities {
|
||||
{ 0x4c, "T10000C" },
|
||||
{ 0x4d, "T10000D" },
|
||||
{ 0x51, "IBM 3592 J1A" },
|
||||
{ 0x52, "IBM 3592 E05" },
|
||||
{ 0x53, "IBM 3592 E06" },
|
||||
{ 0x54, "IBM 3592 E07" },
|
||||
{ 0x55, "IBM 3592 E08" },
|
||||
{ 0x52, "IBM 3592 E05 (TS1120)" },
|
||||
{ 0x53, "IBM 3592 E06 (TS1130)" },
|
||||
{ 0x54, "IBM 3592 E07 (TS1140)" },
|
||||
{ 0x55, "IBM 3592 E08 (TS1150)" },
|
||||
{ 0x56, "IBM 3592 55F (TS1155)" },
|
||||
{ 0x57, "IBM 3592 60F (TS1160)" },
|
||||
{ 0x58, "LTO-5" },
|
||||
{ 0x59, "IBM 3592 70F (TS1170)" },
|
||||
{ 0x5a, "LTO-6" },
|
||||
{ 0x5c, "LTO-7" },
|
||||
{ 0x5d, "LTO-7-M8" },
|
||||
{ 0x5e, "LTO-8" },
|
||||
{ 0x60, "LTO-9" },
|
||||
{ 0x71, "IBM 3592 J1A, encrypted" },
|
||||
{ 0x72, "IBM 3592 E05, encrypted" },
|
||||
{ 0x73, "IBM 3592 E06, encrypted" },
|
||||
{ 0x74, "IBM 3592 E07, encrypted" },
|
||||
{ 0x75, "IBM 3592 E08, encrypted" },
|
||||
{ 0x76, "IBM 3592 55F, encrypted" },
|
||||
{ 0x77, "IBM 3592 60F, encrypted" },
|
||||
{ 0x79, "IBM 3592 70F, encrypted" },
|
||||
{ 0x80, "DLT 15GB uncomp. or Ecrix" },
|
||||
{ 0x81, "DLT 15GB compressed" },
|
||||
{ 0x82, "DLT 20GB uncompressed" },
|
||||
@@ -223,7 +240,7 @@ static struct densities {
|
||||
{ 0x90, "SDLT110 uncompr/EXB-8205 compr" },
|
||||
{ 0x91, "SDLT110 compressed" },
|
||||
{ 0x92, "SDLT160 uncompressed" },
|
||||
{ 0x93, "SDLT160 comprssed" }
|
||||
{ 0x93, "SDLT160 compressed" }
|
||||
/* clang-format on */
|
||||
};
|
||||
|
||||
@@ -248,6 +265,7 @@ static struct booleans {
|
||||
{ "can-partitions", MT_ST_CAN_PARTITIONS, "drive can handle partitioned tapes" },
|
||||
{ "scsi2logical", MT_ST_SCSI2LOGICAL, "logical block addresses used with SCSI-2" },
|
||||
{ "no-wait", MT_ST_NOWAIT, "immediate mode for rewind, etc." },
|
||||
{ "weof-no-wait", MT_ST_NOWAIT_EOF, "immediate mode for writing filemarks" },
|
||||
#ifdef MT_ST_SYSV
|
||||
{ "sysv", MT_ST_SYSV, "enable the SystemV semantics" },
|
||||
#endif
|
||||
@@ -686,7 +704,7 @@ static int do_status(int mtfd,
|
||||
#define TAPE_NR(minor) \
|
||||
((((minor) & ~255) >> (ST_NBR_MODE_BITS + 1)) | \
|
||||
((minor) & ((1 << ST_MODE_SHIFT) - 1)))
|
||||
#define TAPE_MODE(minor) (((minor)&ST_MODE_MASK) >> ST_MODE_SHIFT)
|
||||
#define TAPE_MODE(minor) (((minor) & ST_MODE_MASK) >> ST_MODE_SHIFT)
|
||||
static const char *st_formats[] = { "", "r", "k", "s", "l", "t", "o", "u",
|
||||
"m", "v", "p", "x", "a", "y", "q", "z" };
|
||||
|
||||
@@ -774,6 +792,6 @@ static void test_error(int mtfd, cmdef_tr *cmd)
|
||||
if ((cmd->error_tests & ET_ONLINE) && !GMT_ONLINE(status.mt_gstat))
|
||||
fprintf(stderr,
|
||||
"mt: The device is offline (not powered on, no tape ?).\n");
|
||||
if ((cmd->error_tests & ET_WPROT) && !GMT_WR_PROT(status.mt_gstat))
|
||||
if ((cmd->error_tests & ET_WPROT) && GMT_WR_PROT(status.mt_gstat))
|
||||
fprintf(stderr, "mt: The tape is write-protected.\n");
|
||||
}
|
||||
|
||||
2
mtio.h
2
mtio.h
@@ -64,6 +64,7 @@ struct mtop {
|
||||
#define MTCOMPRESSION 32/* control compression with SCSI mode page 15 */
|
||||
#define MTSETPART 33 /* Change the active tape partition */
|
||||
#define MTMKPART 34 /* Format the tape with one or two partitions */
|
||||
#define MTWEOFI 35 /* write an end-of-file record (mark) in immediate mode */
|
||||
|
||||
/* structure for MTIOCGET - mag tape get status command */
|
||||
|
||||
@@ -202,6 +203,7 @@ struct mtpos {
|
||||
#define MT_ST_SYSV 0x1000
|
||||
#define MT_ST_NOWAIT 0x2000
|
||||
#define MT_ST_SILI 0x4000
|
||||
#define MT_ST_NOWAIT_EOF 0x8000
|
||||
|
||||
/* The mode parameters to be controlled. Parameter chosen with bits 20-28 */
|
||||
#define MT_ST_CLEAR_DEFAULT 0xfffff
|
||||
|
||||
11
stinit.8
11
stinit.8
@@ -159,6 +159,10 @@ The cleaning request notifying parameter is set to
|
||||
The immediate mode is used with commands like rewind if
|
||||
.I value
|
||||
is non-zero (i.e., the driver does not wait for the command to finish).
|
||||
.IP weof-n[o-wait]
|
||||
The immediate mode is used when writing filemarks if
|
||||
.I value
|
||||
is non-zero (i.e., the driver does not wait for the command to finish).
|
||||
.IP mode=value
|
||||
This keyword starts definition of tape mode
|
||||
.I value.
|
||||
@@ -259,10 +263,9 @@ The long timeout for the device is set to
|
||||
seconds.
|
||||
.SH RETURN VALUE
|
||||
The program exits with value one if the command line is incorrect, the
|
||||
definition file is not found, or option -p is given and parsing the
|
||||
definition file fails. In all other cases the return value is
|
||||
zero (i.e., failing of initialization is not currently signaled by
|
||||
the return value).
|
||||
definition file is not found, option -p is given and parsing the
|
||||
definition file fails, or defining one or more of the options fails
|
||||
when the tape number(s) are given on command line.
|
||||
.SH RESTRICTIONS
|
||||
With the exception of the -p option, the program can be used only by
|
||||
the superuser. This is because the program uses ioctls allowed only
|
||||
|
||||
44
stinit.c
44
stinit.c
@@ -58,6 +58,7 @@ typedef struct _devdef_tr {
|
||||
int long_timeout;
|
||||
int cleaning;
|
||||
int nowait;
|
||||
int weof_nowait;
|
||||
int sili;
|
||||
modepar_tr modedefs[4];
|
||||
} devdef_tr;
|
||||
@@ -139,9 +140,13 @@ static char *find_string(char *s, char *target, char *buf, int buflen)
|
||||
cp++;
|
||||
for (cp2 = cp; *cp2 != '"' && *cp2 != '\0'; cp2++)
|
||||
;
|
||||
} else
|
||||
for (cp2 = cp + 1; isalnum(*cp2) || *cp2 == '-'; cp2++)
|
||||
;
|
||||
} else {
|
||||
if (*cp == '\0')
|
||||
return NULL;
|
||||
else
|
||||
for (cp2 = cp + 1; isalnum(*cp2) || *cp2 == '-'; cp2++)
|
||||
;
|
||||
}
|
||||
if (*cp2 == '\0')
|
||||
return NULL;
|
||||
have_arg = TRUE;
|
||||
@@ -255,6 +260,7 @@ find_pars(FILE *dbf, char *company, char *product, char *rev, devdef_tr *defs, i
|
||||
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;
|
||||
@@ -364,6 +370,8 @@ find_pars(FILE *dbf, char *company, char *product, char *rev, devdef_tr *defs, i
|
||||
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);
|
||||
|
||||
@@ -673,11 +681,11 @@ static int find_devfiles(int tapeno, char **names)
|
||||
|
||||
static int set_defs(devdef_tr *defs, char **fnames)
|
||||
{
|
||||
int i, tape;
|
||||
int i, tape, fails;
|
||||
int clear_set[2];
|
||||
struct mtop op;
|
||||
|
||||
for (i = 0; i < NBR_MODES; i++) {
|
||||
for (i = fails = 0; i < NBR_MODES; i++) {
|
||||
if (*fnames[i] == '\0' || !defs->modedefs[i].defined)
|
||||
continue;
|
||||
|
||||
@@ -691,13 +699,17 @@ static int set_defs(devdef_tr *defs, char **fnames)
|
||||
if (defs->do_rewind) {
|
||||
op.mt_op = MTREW;
|
||||
op.mt_count = 1;
|
||||
ioctl(tape, MTIOCTOP, &op); /* Don't worry about result */
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -706,6 +718,7 @@ static int set_defs(devdef_tr *defs, char **fnames)
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -714,6 +727,7 @@ static int set_defs(devdef_tr *defs, char **fnames)
|
||||
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);
|
||||
}
|
||||
@@ -723,6 +737,7 @@ static int set_defs(devdef_tr *defs, char **fnames)
|
||||
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);
|
||||
}
|
||||
@@ -734,6 +749,8 @@ static int set_defs(devdef_tr *defs, char **fnames)
|
||||
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)
|
||||
@@ -764,6 +781,7 @@ static int set_defs(devdef_tr *defs, char **fnames)
|
||||
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);
|
||||
}
|
||||
@@ -771,6 +789,7 @@ static int set_defs(devdef_tr *defs, char **fnames)
|
||||
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);
|
||||
}
|
||||
@@ -779,6 +798,7 @@ static int set_defs(devdef_tr *defs, char **fnames)
|
||||
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);
|
||||
}
|
||||
@@ -786,6 +806,7 @@ static int set_defs(devdef_tr *defs, char **fnames)
|
||||
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);
|
||||
}
|
||||
@@ -793,6 +814,7 @@ static int set_defs(devdef_tr *defs, char **fnames)
|
||||
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);
|
||||
}
|
||||
@@ -800,7 +822,7 @@ static int set_defs(devdef_tr *defs, char **fnames)
|
||||
|
||||
close(tape);
|
||||
}
|
||||
return TRUE;
|
||||
return (fails == 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -866,7 +888,7 @@ static char usage(int retval)
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
FILE *dbf = NULL;
|
||||
int argn;
|
||||
int argn, retval = 0;
|
||||
int tapeno, parse_only = FALSE;
|
||||
char *dbname = NULL;
|
||||
char *convp;
|
||||
@@ -923,8 +945,10 @@ int main(int argc, char **argv)
|
||||
fprintf(stderr, "Can't find tape number for name '%s'.\n", argv[argn]);
|
||||
continue;
|
||||
}
|
||||
if (!define_tape(tapeno, dbf, &defs, TRUE))
|
||||
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++)
|
||||
@@ -935,5 +959,5 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return retval;
|
||||
}
|
||||
|
||||
21
tests/basic.test
Normal file
21
tests/basic.test
Normal file
@@ -0,0 +1,21 @@
|
||||
# Check --version works
|
||||
./mt --version
|
||||
>>> /VERSION/
|
||||
>>>= 0
|
||||
|
||||
./mt -v
|
||||
>>> /VERSION/
|
||||
>>>= 0
|
||||
|
||||
./stinit --version
|
||||
>>> /VERSION/
|
||||
>>>= 0
|
||||
|
||||
# Check -h works
|
||||
./mt -h
|
||||
>>>2 /commands: weof, wset, eof/
|
||||
>>>= 0
|
||||
|
||||
./stinit -h
|
||||
>>>2 /Usage: stinit/
|
||||
>>>= 0
|
||||
6
tests/data/bad-definition.data
Normal file
6
tests/data/bad-definition.data
Normal file
@@ -0,0 +1,6 @@
|
||||
# A non-compressing DAT (DDS-1)
|
||||
# The manufacturer, model, and revision strings can be obtained,
|
||||
# from the file /proc/scsi/scsi (cat /proc/scsi/scsi).
|
||||
manufacturer=XYZ model = "UVW1" {
|
||||
mode1 blocksize=
|
||||
}
|
||||
7
tests/data/illegal-mode.data
Normal file
7
tests/data/illegal-mode.data
Normal file
@@ -0,0 +1,7 @@
|
||||
# A non-compressing DAT (DDS-1)
|
||||
# The manufacturer, model, and revision strings can be obtained,
|
||||
# from the file /proc/scsi/scsi (cat /proc/scsi/scsi).
|
||||
manufacturer=XYZ model = "UVW1" {
|
||||
scsi2logical=1 can-bsr can-partitions auto-lock
|
||||
mode1 blocksize=0
|
||||
modeABC blocksize=1024 }
|
||||
4
tests/data/incomplete-block.data
Normal file
4
tests/data/incomplete-block.data
Normal file
@@ -0,0 +1,4 @@
|
||||
# A non-compressing DAT (DDS-1)
|
||||
# The manufacturer, model, and revision strings can be obtained,
|
||||
# from the file /proc/scsi/scsi (cat /proc/scsi/scsi).
|
||||
manufacturer=XYZ model = "UVW1" {
|
||||
7
tests/data/large-units.data
Normal file
7
tests/data/large-units.data
Normal file
@@ -0,0 +1,7 @@
|
||||
# A non-compressing DAT (DDS-1)
|
||||
# The manufacturer, model, and revision strings can be obtained,
|
||||
# from the file /proc/scsi/scsi (cat /proc/scsi/scsi).
|
||||
manufacturer=XYZ model = "UVW1" {
|
||||
scsi2logical=1 can-bsr can-partitions auto-lock
|
||||
mode1 blocksize=1k
|
||||
mode2 blocksize=1M }
|
||||
0
tests/data/not-a-char-device
Normal file
0
tests/data/not-a-char-device
Normal file
34
tests/mt-cli.test
Normal file
34
tests/mt-cli.test
Normal file
@@ -0,0 +1,34 @@
|
||||
# Wrong argument
|
||||
./mt -x
|
||||
>>>2 /usage: /
|
||||
>>>= 1
|
||||
|
||||
# Missing tape argument
|
||||
./mt -f
|
||||
>>>2 /usage: /
|
||||
>>>= 1
|
||||
|
||||
# Unknown command
|
||||
./mt to-the-moon
|
||||
>>>2 /mt: unknown command "to-the-moon"/
|
||||
>>>= 1
|
||||
|
||||
# Too many arguments
|
||||
./mt rewind 1
|
||||
>>>2 /mt: too many arguments for the command 'rewind'\./
|
||||
>>>= 1
|
||||
|
||||
# Ambigous command
|
||||
./mt l
|
||||
>>>2 /mt: ambiguous command "l"/
|
||||
>>>= 1
|
||||
|
||||
# Shortened but not ambiguous command.
|
||||
./mt rewi 1
|
||||
>>>2 /mt: too many arguments for the command 'rewind'\./
|
||||
>>>= 1
|
||||
|
||||
# Densities command - the only one not requiring a tape.
|
||||
./mt densities
|
||||
>>> /LTO-6/
|
||||
>>>= 0
|
||||
19
tests/mt-errors.test
Normal file
19
tests/mt-errors.test
Normal file
@@ -0,0 +1,19 @@
|
||||
# Wrong tape argument
|
||||
./mt -f /dev/no-such-tape rewind
|
||||
>>>2 /no-such-tape: No such file or directory/
|
||||
>>>= 1
|
||||
|
||||
# Wrong file in show options
|
||||
./mt -f tests/data/not-a-char-device stshowoptions
|
||||
>>>2 /mt: not a character device/
|
||||
>>>= 1
|
||||
|
||||
# /dev/null is not a tape device. Error message is ugly, though.
|
||||
./mt -f /dev/null stshowoptions
|
||||
>>>2 /Can't read the sysfs file '\/sys\/class\/scsi_tape/
|
||||
>>>= 2
|
||||
|
||||
# /dev/null is not a tape device, so status fails.
|
||||
./mt -f /dev/null status
|
||||
>>>2 /Inappropriate ioctl for device/
|
||||
>>>= 2
|
||||
51
tests/stinit-errors.test
Normal file
51
tests/stinit-errors.test
Normal file
@@ -0,0 +1,51 @@
|
||||
# Check handling of missing file
|
||||
./stinit -p -f no-such-database
|
||||
>>>2 /Can't find SCSI tape database/
|
||||
>>>= 1
|
||||
|
||||
# No file passed
|
||||
./stinit -p -f
|
||||
>>>2 /Usage:/
|
||||
>>>= 1
|
||||
|
||||
# Wrong arguments
|
||||
./stinit -x
|
||||
>>>2 /Usage:/
|
||||
>>>= 1
|
||||
|
||||
# Illegal ordering of arguments
|
||||
./stinit -f stinit.def.examples 1000 -
|
||||
>>>2 /Usage:/
|
||||
>>>= 1
|
||||
|
||||
# Check bad mode
|
||||
./stinit -v -v -p -f tests/data/illegal-mode.data
|
||||
>>> /Errors found!/
|
||||
>>>2 /Illegal mode for/
|
||||
>>>= 1
|
||||
|
||||
# No modes defined
|
||||
#./stinit -v -v -f tests/data/no-modes.data
|
||||
#>>> /Errors found!/
|
||||
#>>>2 /Illegal mode for/
|
||||
#>>>= 1
|
||||
|
||||
# Wrong tape device
|
||||
./stinit -f stinit.def.examples /dev/no-such-tape
|
||||
>>>2 /Can't find tape number for name/
|
||||
>>>= 0
|
||||
|
||||
# Wrong tape number. Well, this is flaky, but let's hope nobody has
|
||||
# 1000 tapes.
|
||||
./stinit -f stinit.def.examples 1000
|
||||
>>>2 /Can't find any device files for tape 1000/
|
||||
>>>= 1
|
||||
|
||||
./stinit -f stinit.def.examples 1000
|
||||
>>>2 /Definition for '1000' failed/
|
||||
>>>= 1
|
||||
|
||||
# Wrong tape number (non-numeric).
|
||||
./stinit -f stinit.def.examples 1000a
|
||||
>>>2 /Invalid tape device index '1000a': don't know how to parse 'a'/
|
||||
>>>= 0
|
||||
30
tests/stinit-parsing.test
Normal file
30
tests/stinit-parsing.test
Normal file
@@ -0,0 +1,30 @@
|
||||
# Check example file parsing
|
||||
./stinit -p -f stinit.def.examples
|
||||
>>>= 0
|
||||
|
||||
# Extra arguments ignored while file parsing
|
||||
./stinit -p -f stinit.def.examples abc
|
||||
>>>2 /Extra arguments .* ignored/
|
||||
>>>= 0
|
||||
|
||||
# Checking complete stinit parsing
|
||||
./stinit -v -v -p -f stinit.def.examples
|
||||
>>> /No errors found./
|
||||
>>>2 /Mode 1 definition: scsi2logical=1 can-bsr=1 auto-lock=0 two-fms=0 drive-buffering=1 buffer-writes read-ahead=1 async-writes=1 can-partitions=0 fast-eom=1 blocksize=0 sili=1 timeout=900 long-timeout=14400 density=0x44 compression=0/
|
||||
>>>= 0
|
||||
|
||||
# Check units
|
||||
./stinit -v -v -p -f tests/data/large-units.data
|
||||
>>> /No errors found./
|
||||
>>>2 /blocksize=1(k|M)/
|
||||
>>>= 0
|
||||
|
||||
# Incomplete block
|
||||
./stinit -p -v -f tests/data/incomplete-block.data
|
||||
>>>2 /End of definition block not found for/
|
||||
>>>= 1
|
||||
|
||||
# Wrong definition
|
||||
./stinit -p -v -f tests/data/bad-definition.data
|
||||
>>>2 /Warning: errors in definition for/
|
||||
>>>= 1
|
||||
Reference in New Issue
Block a user