Add option to TFTP client to ignore ':' in file name

I have encountered a situation where I would like to use tftp-hpa to
retrieve a file that resides within an absolute path containing a ':'
character.  Ala, "tftp foobar -c get C:2/tftpdir/myfile".  Since the
tftp client automatically converts the host:file syntax, I get an
error "tftp: C: Unknown host".

I made a chage to the tftp client code to add a literal mode (-l),
that prevents the special treatment of the ':' character.  I've
attached a patch set for main.c and tftp.1.in for your consideration.
I'm not sure how many folks run into this, but it may be somewhat
common for VxWorks and perhaps MSDOS users.

Thanks,
Craig Johnston
This commit is contained in:
Craig Johnston 2006-12-11 09:23:50 -08:00 committed by H. Peter Anvin
parent e031e3bc9a
commit 899b7d500b
2 changed files with 34 additions and 8 deletions

View file

@ -89,6 +89,7 @@ int f;
u_short port; u_short port;
int trace; int trace;
int verbose; int verbose;
int literal;
int connected; int connected;
const struct modes *mode; const struct modes *mode;
#ifdef WITH_READLINE #ifdef WITH_READLINE
@ -119,6 +120,7 @@ void settimeout (int, char **);
void settrace (int, char **); void settrace (int, char **);
void setverbose (int, char **); void setverbose (int, char **);
void status (int, char **); void status (int, char **);
void setliteral (int, char **);
static void command (void); static void command (void);
@ -157,6 +159,9 @@ struct cmd cmdtab[] = {
{ "trace", { "trace",
"toggle packet tracing", "toggle packet tracing",
settrace }, settrace },
{ "literal",
"toggle literal mode, ignore ':' in file name",
setliteral },
{ "status", { "status",
"show current status", "show current status",
status }, status },
@ -190,7 +195,7 @@ const char *program;
static inline void usage(int errcode) static inline void usage(int errcode)
{ {
fprintf(stderr, "Usage: %s [-v][-m mode] [host [port]] [-c command]\n", program); fprintf(stderr, "Usage: %s [-v][-l][-m mode] [host [port]] [-c command]\n", program);
exit(errcode); exit(errcode);
} }
@ -223,6 +228,9 @@ main(int argc, char *argv[])
/* Print version and configuration to stdout and exit */ /* Print version and configuration to stdout and exit */
printf("%s\n", TFTP_CONFIG_STR); printf("%s\n", TFTP_CONFIG_STR);
exit(0); exit(0);
case 'l':
literal = 1;
break;
case 'm': case 'm':
if ( ++arg >= argc ) if ( ++arg >= argc )
usage(EX_USAGE); usage(EX_USAGE);
@ -502,7 +510,7 @@ put(int argc, char *argv[])
return; return;
} }
targ = argv[argc - 1]; targ = argv[argc - 1];
if (strchr(argv[argc - 1], ':')) { if (!literal && strchr(argv[argc - 1], ':')) {
struct hostent *hp; struct hostent *hp;
for (n = 1; n < argc - 1; n++) for (n = 1; n < argc - 1; n++)
@ -591,14 +599,14 @@ get(int argc, char *argv[])
} }
if (!connected) { if (!connected) {
for (n = 1; n < argc ; n++) for (n = 1; n < argc ; n++)
if (strchr(argv[n], ':') == 0) { if (literal || strchr(argv[n], ':') == 0) {
getusage(argv[0]); getusage(argv[0]);
return; return;
} }
} }
for (n = 1; n < argc ; n++) { for (n = 1; n < argc ; n++) {
src = strchr(argv[n], ':'); src = strchr(argv[n], ':');
if (src == NULL) if (literal || src == NULL)
src = argv[n]; src = argv[n];
else { else {
struct hostent *hp; struct hostent *hp;
@ -699,6 +707,14 @@ settimeout(int argc, char *argv[])
maxtimeout = t; maxtimeout = t;
} }
void
setliteral(int argc, char *argv[])
{
(void)argc; (void)argv; /* Quiet unused warning */
literal = !literal;
printf("Literal mode %s.\n", literal ? "on" : "off");
}
void void
status(int argc, char *argv[]) status(int argc, char *argv[])
{ {
@ -707,8 +723,8 @@ status(int argc, char *argv[])
printf("Connected to %s.\n", hostname); printf("Connected to %s.\n", hostname);
else else
printf("Not connected.\n"); printf("Not connected.\n");
printf("Mode: %s Verbose: %s Tracing: %s\n", mode->m_mode, printf("Mode: %s Verbose: %s Tracing: %s Literal: %s\n", mode->m_mode,
verbose ? "on" : "off", trace ? "on" : "off"); verbose ? "on" : "off", trace ? "on" : "off", literal ? "on" : "off");
printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n", printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
rexmtval, maxtimeout); rexmtval, maxtimeout);
} }

View file

@ -60,6 +60,9 @@ command below.)
Execute \fIcommand\fP as if it had been entered on the tftp prompt. Execute \fIcommand\fP as if it had been entered on the tftp prompt.
Must be specified last on the command line. Must be specified last on the command line.
.TP .TP
.B \-l
Default to literal mode. Used to avoid special processing of ':' in a file name.
.TP
\fB\-m\fP \fImode\fP \fB\-m\fP \fImode\fP
Set the default transfer mode to \fImode\fP. This is usually used with \-c. Set the default transfer mode to \fImode\fP. This is usually used with \-c.
.TP .TP
@ -119,7 +122,12 @@ host, if the host has already been specified, or a string of the form
.I "host:filename" .I "host:filename"
to specify both a host and filename at the same time. If the latter to specify both a host and filename at the same time. If the latter
form is used, the last hostname specified becomes the default for form is used, the last hostname specified becomes the default for
future transfers. future transfers. Enable
.B literal
mode to prevent special treatment of the ':' character (e.g. C:\\dir\\file).
.TP
.B literal
Toggle literal mode. When set, this mode prevents special treatment of ':' in filenames.
.TP .TP
\fBmode\fP \fItransfer-mode\fP \fBmode\fP \fItransfer-mode\fP
Specify the mode for transfers; Specify the mode for transfers;
@ -151,7 +159,9 @@ form is used, the hostname specified becomes the default for future
transfers. If the remote-directory form is used, the remote host is transfers. If the remote-directory form is used, the remote host is
assumed to be a UNIX system or another system using assumed to be a UNIX system or another system using
.B / .B /
as directory separator. as directory separator. Enable
.B literal
mode to prevent special treatment of the ':' character (e.g. C:\\dir\\file).
.TP .TP
.B quit .B quit
Exit Exit