} \
} \
while (0)
-
+
\f
static void
str[len-1] = 0;
}
}
-
+
\f
char *input_buf_ptr = NULL;
size_t input_buf_size = 0;
-char *
+static char *
rmt_read (void)
{
ssize_t rc = getline (&input_buf_ptr, &input_buf_size, stdin);
return NULL;
}
-void
+static void
rmt_write (const char *fmt, ...)
{
va_list ap;
va_start (ap, fmt);
vfprintf (stdout, fmt, ap);
+ fflush (stdout);
VDEBUG (10, "S: ", fmt, ap);
}
-void
+static void
rmt_reply (uintmax_t code)
{
char buf[UINTMAX_STRSIZE_BOUND];
rmt_write ("A%s\n", umaxtostr (code, buf));
}
-void
+static void
rmt_error_message (int code, const char *msg)
{
DEBUG1 (10, "S: E%d\n", code);
DEBUG1 (10, "S: %s\n", msg);
DEBUG1 (1, "error: %s\n", msg);
fprintf (stdout, "E%d\n%s\n", code, msg);
+ fflush (stdout);
}
-void
+static void
rmt_error (int code)
{
rmt_error_message (code, strerror (code));
#define RMT_KW(s,v) { #s, sizeof (#s) - 1, v }
-int
+static int
xlat_kw (const char *s, const char *pfx,
struct rmt_kw const *kw, int *valp, const char **endp)
{
slen -= pfxlen;
}
}
-
+
for (; kw->name; kw++)
{
if (slen >= kw->len
return 1;
}
-const char *
+static const char *
skip_ws (const char *s)
{
while (*s && c_isblank (*s))
{ NULL }
};
-int
+static int
decode_open_flag (const char *mstr, int *pmode)
{
+ int numeric_mode = 0;
int mode = 0;
+ const char *p;
- while (mstr)
+ mstr = skip_ws (mstr);
+ if (c_isdigit (*mstr))
{
- int v;
- const char *p;
-
- mstr = skip_ws (mstr);
- if (*mstr == 0)
- break;
- else if (c_isdigit (*mstr))
- v = strtol (mstr, (char**) &p, 10);
- else if (xlat_kw (mstr, "O_", open_flag_kw, &v, &p))
- {
- rmt_error_message (EINVAL, "invalid open mode");
- return 1;
- }
+ numeric_mode = strtol (mstr, (char**) &p, 10);
+ mstr = skip_ws (p);
+ }
- mode |= v;
-
- if (*p && c_isblank (*p))
- p = skip_ws (p);
- if (*p == 0)
- break;
- else if (*p == '|')
- {
- /* FIXMEL
- if (p[1] == 0)
- rmt_error_message (EINVAL, "invalid open mode");
- */
- mstr = p + 1;
- }
- else
+ if (*mstr)
+ {
+ while (mstr)
{
- rmt_error_message (EINVAL, "invalid open mode");
- return 1;
+ int v;
+
+ mstr = skip_ws (mstr);
+ if (*mstr == 0)
+ break;
+ else if (c_isdigit (*mstr))
+ v = strtol (mstr, (char**) &p, 10);
+ else if (xlat_kw (mstr, "O_", open_flag_kw, &v, &p))
+ {
+ rmt_error_message (EINVAL, "invalid open mode");
+ return 1;
+ }
+
+ mode |= v;
+
+ if (*p && c_isblank (*p))
+ p = skip_ws (p);
+ if (*p == 0)
+ break;
+ else if (*p == '|')
+ {
+ /* FIXMEL
+ if (p[1] == 0)
+ rmt_error_message (EINVAL, "invalid open mode");
+ */
+ mstr = p + 1;
+ }
+ else
+ {
+ rmt_error_message (EINVAL, "invalid open mode");
+ return 1;
+ }
}
}
+ else
+ mode = numeric_mode;
*pmode = mode;
return 0;
}
/* Syntax
------
O<device>\n<flags>\n
-
+
Function
--------
Opens the <device> with given <flags>. If a device had already been opened,
it is closed before opening the new one.
-
+
Arguments
---------
<device> - name of the device to open.
64|512
CREAT|TRUNC
+ In addition, a compined form is also allowed, i.e. a decimal mode followed
+ by its symbolic representation. In this case the symbolic representation
+ is given preference.
+
Reply
-----
- A0\n on success, E<errno>\n<msg>\n on error.
-
+ A0\n on success, E0\n<msg>\n on error.
+
Extensions
----------
- The BSD version allows only decimal number as <flags>.
+ BSD version allows only decimal number as <flags>
*/
-
+
static void
open_device (char *str)
{
char *device = xstrdup (str);
char *flag_str;
int flag;
-
+
flag_str = rmt_read ();
if (!flag_str)
{
/* Syntax
------
C[<device>]\n
-
+
Function
--------
Close the currently open device.
Arguments
---------
Any arguments are silently ignored.
-
+
Reply
-----
- A0\n on success, E<errno>\n<msg>\n on error.
+ A0\n on success, E0\n<msg>\n on error.
*/
static void
-close_device ()
+close_device (void)
{
if (close (device_fd) < 0)
rmt_error (errno);
/* Syntax
------
L<whence>\n<offset>\n
-
+
Function
--------
Perform an lseek(2) on the currently open device with the specified
parameters.
-
+
Arguments
---------
<whence> - Where to measure offset from. Valid values are:
Reply
-----
A<offset>\n on success. The <offset> is the new offset in file.
- E<errno>\n<msg>\n on error.
+ E0\n<msg>\n on error.
Extensions
----------
- The BSD version allows only 0,1,2 as <whence>.
+ BSD version allows only 0,1,2 as <whence>.
*/
static struct rmt_kw const seek_whence_kw[] =
RMT_KW(END, SEEK_END),
{ NULL }
};
-
-void
+
+static void
lseek_device (const char *str)
{
char *p;
int whence;
off_t off;
uintmax_t n;
-
+
if (str[0] && str[1] == 0)
{
switch (str[0])
rmt_error_message (EINVAL, N_("Invalid seek offset"));
return;
}
-
+
if (n != off || errno == ERANGE)
{
rmt_error_message (EINVAL, N_("Seek offset out of range"));
/* Syntax
------
R<count>\n
-
+
Function
--------
Read <count> bytes of data from the current device.
-
+
Arguments
---------
<count> - number of bytes to read.
-
+
Reply
-----
On success: A<rdcount>\n, followed by <rdcount> bytes of data read from
the device.
- On error: E<errno>\n<msg>\n
+ On error: E0\n<msg>\n
*/
-void
+static void
read_device (const char *str)
{
char *p;
size_t size;
uintmax_t n;
size_t status;
-
+
n = size = strtoumax (str, &p, 10);
if (*p)
{
rmt_error_message (EINVAL, N_("Invalid byte count"));
return;
}
-
+
if (n != size || errno == ERANGE)
{
rmt_error_message (EINVAL, N_("Byte count out of range"));
/* Syntax
------
W<count>\n followed by <count> bytes of input data.
-
+
Function
--------
Write data onto the current device.
-
+
Arguments
---------
<count> - number of bytes.
-
+
Reply
-----
On success: A<wrcount>\n, where <wrcount> is number of bytes actually
written.
- On error: E<errno>\n<msg>\n
+ On error: E0\n<msg>\n
*/
-void
+static void
write_device (const char *str)
{
char *p;
size_t size;
uintmax_t n;
size_t status;
-
+
n = size = strtoumax (str, &p, 10);
if (*p)
{
rmt_error_message (EINVAL, N_("Invalid byte count"));
return;
}
-
+
if (n != size || errno == ERANGE)
{
rmt_error_message (EINVAL, N_("Byte count out of range"));
/* Syntax
------
I<opcode>\n<count>\n
-
+
Function
--------
Perform a MTIOCOP ioctl(2) command using the specified paramedters.
-
+
Arguments
---------
<opcode> - MTIOCOP operation code.
<count> - mt_count.
-
+
Reply
-----
On success: A0\n
- On error: E<errno>\n<msg>\n
+ On error: E0\n<msg>\n
*/
-void
+static void
iocop_device (const char *str)
{
char *p;
long opcode;
off_t count;
uintmax_t n;
-
+
opcode = strtol (str, &p, 10);
if (*p)
{
rmt_error_message (EINVAL, N_("Invalid byte count"));
return;
}
-
+
if (n != count || errno == ERANGE)
{
rmt_error_message (EINVAL, N_("Byte count out of range"));
return;
}
-
+
#ifdef MTIOCTOP
{
struct mtop mtop;
/* Syntax
------
S\n
-
+
Function
--------
Return the status of the open device, as obtained with a MTIOCGET
ioctl call.
-
+
Arguments
---------
None
-
+
Reply
-----
On success: A<count>\n followed by <count> bytes of data.
- On error: E<errno>\n<msg>\n
+ On error: E0\n<msg>\n
*/
-void
+static void
status_device (const char *str)
{
if (*str)
rmt_error_message (ENOSYS, N_("Operation not supported"));
#endif
}
-
+
\f
const char *argp_program_version = "rmt (" PACKAGE_NAME ") " VERSION;
case 'd':
dbglev = strtol (arg, NULL, 0);
break;
-
+
case DEBUG_FILE_OPTION:
dbgout = fopen (arg, "w");
if (!dbgout)
error (EXIT_FAILURE, errno, _("cannot open %s"), arg);
break;
-
+
case ARGP_KEY_FINI:
if (dbglev)
{
else if (dbgout)
dbglev = 1;
break;
-
+
default:
return ARGP_ERR_UNKNOWN;
}
return 0;
}
-
+
static struct argp argp = {
options,
parse_opt,
char *buf;
int idx;
int stop = 0;
-
+
set_program_name (argv[0]);
argp_version_setup ("rmt", rmt_authors);
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
}
-
+
if (argp_parse (&argp, argc, argv, ARGP_IN_ORDER, &idx, NULL))
exit (EXIT_FAILURE);
if (idx != argc)
error (EXIT_FAILURE, errno, _("cannot open %s"), argv[idx]);
dbglev = 1;
}
-
+
while (!stop && (buf = rmt_read ()) != NULL)
{
switch (buf[0])
close_device ();
stop = 1;
break;
-
+
case 'I':
iocop_device (buf + 1);
break;
-
+
case 'L':
lseek_device (buf + 1);
break;
-
+
case 'O':
open_device (buf + 1);
break;
-
+
case 'R':
read_device (buf + 1);
break;
-
+
case 'S':
status_device (buf + 1);
break;
-
+
case 'W':
write_device (buf + 1);
break;
-
+
default:
DEBUG1 (1, "garbage input %s\n", buf);
rmt_error_message (EINVAL, N_("Garbage command"));
return EXIT_FAILURE; /* exit status used to be 3 */
- }
+ }
}
if (device_fd >= 0)
close_device ();