Clean up handling of unspecified names. Clarify man page.

This commit is contained in:
Peter Dufault 1995-01-26 23:48:41 +00:00
parent daa21be5f0
commit 672412c27e
2 changed files with 111 additions and 97 deletions

View File

@ -82,14 +82,18 @@ Block) to perform the desired command. These functions assist in
building up the CDB, submitting it to the SCSI subsystem, and decoding
the result.
.Pp
Look at the
.Xr scsi 8
command before using the library directly - simple programs are
best implemented as scripts using that facility.
.Pp
To provide for security,
not all devices accept the SCIOCCOMAND ioctl. For tape
drives, only the control device accepts it. For disk drives, only
the RAWPART partition (partition d in 2.0) accepts it. Any device
that comes on line as an UNKNOWN device will accept the ioctl, and
the "super scsi"
not all devices accept the SCIOCCOMAND ioctl. It is accepted by the
control device for tape drives, partition D for disk drives, partition C
for CD ROM drives, and any "unknown" device.
The "super scsi"
.Xr ssc 4
device also accepts it.
device also accepts the ioctl.
.Pp
Most of the SCSI library functions build up and manipulate the
.Ar scsireq
@ -115,7 +119,6 @@ typedef struct scsireq {
} scsireq_t;
.Ed
.Pp
The function
.Fn scsireq_new
allocates a new
.Ar scsireq
@ -166,30 +169,34 @@ indicates a data in phase (a transfer into the user buffer at
indicates a data out phase (a transfer out of the user buffer).
.Pp
.Fr fmt
is an ASCII CDB format specifier used to build up the SCSI CDB.
is a CDB format specifier used to build up the SCSI CDB.
This text string is made up of a list of field specifiers. Field
specifiers specify the value for each CDB field (including indicating
that the value be taken from the next argument in the
variable argument list), the width
of the field in bits or bytes, and an optional name.
The optional name is the final part of a field specifier and
is in curly braces. A valid example is:
of the field in bits or bytes, and an optional name. White space is
ignored, and the pound sign ('#') introduces a comment that ends at the
end of the current line.
.Pp
The optional name is the first part of a field specifier and
is in curly braces. The text in curly braces in this example are
the names:
.Bd -literal -offset indent
.Fr "v:b1 {PS} 0:b1 {Reserved} v:b6 {Page Code}"
.Fr "{PS} v:b1 {Reserved} 0:b1 {Page Code} v:b6 # Mode select page"
.Ed
.Pp
This field specifier has two one bit fields and one six bit field.
The second one bit field is the constant value 0 and the first
one bit field and the six bit field are taken from the variable
argument list.
Multi byte fields are swapped into the SCSI byte order in the
CDB and
white space is ignored.
CDB and white space is ignored.
.Pp
When the field is a hex value or the letter v, (e.g.,
.Fr "1A"
or
.Fr "v" )
a single byte value
then a single byte value
is copied to the next unused byte of the CDB.
When the letter
.Fr v
@ -203,17 +210,17 @@ followed by a field width specifier (e.g.,
.Fr 3:b4 ,
.Fr 3:i3 ,
.FR v:i3 )
is used to specify a field of a given bit or byte width.
specifies a field of a given bit or byte width.
Either the constant value or (for the V specifier) the next integer value from
the variable argument list is copied to the next unused
bits or bytes of the CDB. A decimal number or the letter
bits or bytes of the CDB.
.Pp
A decimal number or the letter
.Fr b
followed by a decimal
number as the field width indicates a bit field of that width.
These bit fields are packed as tightly as possible beginning with the
followed by a decimal number field width indicates a bit field of that width.
The bit fields are packed as tightly as possible beginning with the
high bit (so that it reads the same as the SCSI spec), and a new byte of
the CDB is
started whenever the byte fills completely or when an
the CDB is started whenever a byte fills completely or when an
.Fr i
field is encountered.
.Pp
@ -223,49 +230,50 @@ followed by either
1, 2, 3 or 4 indicates a 1, 2, 3 or 4 byte integral value that must
be swapped into SCSI byte order (MSB first).
.Pp
For the v field specifier
the next integer argument is taken from the variable argument
For the
.Fr v
field specifier the next integer argument is taken from the variable argument
list and that value is used swapped into SCSI byte order.
.Pp
.Fn scsireq_decode
is used to decode information from the data in phase of the SCSI
transfer.
.Pp
The decoding is similar to
the command specifier processing of
.Fn scsireq_build,
.Fn scsireq_build
except that the data is extracted from the data pointed to by
.Fr scsireq->databuf.
The stdarg list must be pointers to integers instead of integer
The stdarg list should be pointers to integers instead of integer
values.
.Pp
In addition, a seek field type and a suppression field modifier are added.
A seek field type and a suppression modifier are added.
The
.Fr *
suppression modifier to a field (e.g.,
suppression modifier (e.g.,
.Fr *i3
or
.Fr *b4 )
suppresses the assignment from that field and can be used to skip
over bytes or bits in the data, without copying them to a dummy variable
in the arg list.
suppresses assignment from the field and can be used to skip
over bytes or bits in the data, without having to copy
them to a dummy variable in the arg list.
.Pp
A seek field type
The seek field type
.Fr s
is provided. This ``seeks'' to an absolute position in the data (
permits you to skip over data.
This seeks to an absolute position (
.Fr s3 )
or a relative position (
.Fr s+3 )
in the data, based on whether or not the seek value has a '+' sign.
The value can also be
in the data, based on whether or not the presence of the '+' sign.
The seek value can be specified as
.Fr v
and the next integer value will be taken from the arg list
and used as the seek value.
and the next integer value from the argument list will be
used as the seek value.
.Pp
.Fn scsireq_buff_decode
decodes an arbitrary data buffer identically to the method
used by the
.Fn scsireq_decode
function.
decodes an arbitrary data buffer using the method
described above in
.Fn scsireq_decode .
.Pp
.Fn scsireq_encode
encodes the data phase section of the structure. The encoding is
@ -286,10 +294,6 @@ or not, and so on.
checks environment variables and initializes the library for
consistent library use and then calls the regular open system call.
.Pp
.Fn scsi_debug and
.Fn scsi_debug_output
are used for debugging.
.Pp
.Fn scsi_debug
prints the results of a scsireq_enter function to the specified stdio
stream.
@ -311,11 +315,12 @@ and
return the same pointer as the one passed in.
.Pp
The functions
.Fn scsireq_buff_decode ,
.Fn scsireq_buff_decode and
.Fn scsireq_decode
and
return the number of assignments performed.
.Pp
.Fn scsireq_encode
return the number of fields processed.
returns the number of fields processed.
.Pp
The function
.Fn scsireq_enter

View File

@ -30,7 +30,7 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* $Id: scsi.c,v 1.1.1.1 1995/01/24 12:10:11 dufault Exp $
* $Id: scsi.c,v 1.2 1995/01/25 00:33:50 dufault Exp $
*/
#include <stdlib.h>
#include <stdio.h>
@ -132,20 +132,11 @@ scsireq_t *scsireq_new(void)
*
*/
#define ARG_PUT(ARG) \
do \
{ \
if (arg_put) \
(*arg_put)(puthook, letter, (void *)((long)(ARG)), 1, field_name); \
else \
*(va_arg(ap, int *)) = (ARG); \
} while (0)
static int do_buff_decode(u_char *databuf, size_t len,
void (*arg_put)(void *, int , void *, int, char *), void *puthook,
char *fmt, va_list ap)
{
int decoded = 0;
int assigned = 0;
int width;
int suppress;
int plus;
@ -156,19 +147,46 @@ char *fmt, va_list ap)
char letter;
char field_name[80];
# define ARG_PUT(ARG) \
do \
{ \
if (!suppress) \
{ \
if (arg_put) \
(*arg_put)(puthook, letter, \
(void *)((long)(ARG)), 1, field_name); \
else \
*(va_arg(ap, int *)) = (ARG); \
assigned++; \
} \
field_name[0] = 0; \
suppress = 0; \
} while (0)
u_char bits = 0; /* For bit fields */
int shift = 0; /* Bits already shifted out */
suppress = 0;
field_name[0] = 0;
while (!done)
{
switch(letter = *fmt)
{
case ' ':
case ' ': /* White space */
case '\t':
case '\r':
case '\n':
case '\f':
fmt++;
break;
case '#': /* Comment */
while (*fmt && (*fmt != '\n'))
fmt++;
if (fmt)
fmt++; /* Skip '\n' */
break;
case '*': /* Suppress assignment */
fmt++;
suppress = 1;
@ -185,7 +203,8 @@ char *fmt, va_list ap)
fmt++;
}
fmt++; /* Skip '}' */
if (fmt)
fmt++; /* Skip '}' */
field_name[i] = 0;
}
break;
@ -209,10 +228,7 @@ char *fmt, va_list ap)
shift, bits, value, width, mask[width]);
#endif
if (!suppress)
ARG_PUT(value);
else
suppress = 0;
ARG_PUT(value);
shift -= width;
}
@ -226,43 +242,31 @@ char *fmt, va_list ap)
switch(width)
{
case 1:
if (!suppress)
ARG_PUT(*databuf);
else
suppress = 0;
ARG_PUT(*databuf);
databuf++;
break;
case 2:
if (!suppress)
ARG_PUT(
(*databuf) << 8 |
*(databuf + 1));
else
suppress = 0;
ARG_PUT(
(*databuf) << 8 |
*(databuf + 1));
databuf += 2;
break;
case 3:
if (!suppress)
ARG_PUT(
(*databuf) << 16 |
(*(databuf + 1)) << 8 |
*(databuf + 2));
else
suppress = 0;
ARG_PUT(
(*databuf) << 16 |
(*(databuf + 1)) << 8 |
*(databuf + 2));
databuf += 3;
break;
case 4:
if (!suppress)
ARG_PUT(
(*databuf) << 24 |
(*(databuf + 1)) << 16 |
(*(databuf + 2)) << 8 |
*(databuf + 3));
else
suppress = 0;
ARG_PUT(
(*databuf) << 24 |
(*(databuf + 1)) << 16 |
(*(databuf + 2)) << 8 |
*(databuf + 3));
databuf += 4;
break;
@ -279,7 +283,6 @@ char *fmt, va_list ap)
width = strtol(fmt, &fmt, 10);
if (!suppress)
{
if (arg_put)
(*arg_put)(puthook, letter, databuf, width, field_name);
else
@ -295,11 +298,11 @@ char *fmt, va_list ap)
*p = 0;
}
}
assigned++;
}
else
suppress = 0;
databuf += width;
decoded++;
field_name[0] = 0;
suppress = 0;
break;
case 's': /* Seek */
@ -330,7 +333,6 @@ char *fmt, va_list ap)
else
databuf = base + width; /* Absolute seek */
decoded++;
break;
case 0:
@ -343,7 +345,7 @@ char *fmt, va_list ap)
}
}
return decoded;
return assigned;
}
int scsireq_decode(scsireq_t *scsireq, char *fmt, ...)
@ -438,6 +440,13 @@ char *fmt, int *width_p, int *value_p, char *name, int n_name, int *error_p)
state = DONE;
else if (isspace(*p))
p++;
else if (*p == '#')
{
while (*p && *p != '\n')
p++;
if (p)
p++;
}
else if (*p == '{')
{
int i = 0;