/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2002 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* University Copyright- Copyright (c) 1982, 1986, 1988
* The Regents of the University of California
* All Rights Reserved
*
* University Acknowledgment- Portions of this document are derived from
* software developed by the University of California, Berkeley, and its
* contributors.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* TFTP User Program -- Command Interface.
*/
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
#include <netdb.h>
#include <fcntl.h>
#include <string.h>
#include <limits.h>
#include "tftpcommon.h"
#include "tftpprivate.h"
#define NELEM(a) (sizeof (a) / sizeof ((a)[0]))
int f;
int verbose;
int trace;
int srexmtval;
int blksize;
int tsize_opt;
static int connected;
static void intr(int);
static void quit(int, char **);
static void help(int, char **);
static void setverbose(int, char **);
static void settrace(int, char **);
static void status(int, char **);
static void get(int, char **);
static void put(int, char **);
static void setpeer(int, char **);
static void modecmd(int, char **);
static void setrexmt(int, char **);
static void settimeout(int, char **);
static void setbinary(int, char **);
static void setascii(int, char **);
static void setblksize(int, char **);
static void setsrexmt(int, char **);
static void settsize(int, char **);
static void setmode(char *);
static void putusage(char *);
static void getusage(char *);
static char *finddelimiter(char *);
static char *removebrackets(char *);
static int prompt_for_arg(char *, int, char *);
static char *tail(char *);
static void command(int);
static void makeargv(int *, char ***);
struct cmd {
char *name;
char *help;
void (*handler)(int, char **);
};
"server";
"timeout for server";
"the server";
{ NULL }
};
int
{
int top;
port = default_port;
if (f < 0) {
perror("tftp: socket");
exit(3);
}
perror("tftp: bind");
exit(1);
}
if (argc > 1) {
exit(0);
}
for (;;)
/*NOTREACHED*/
return (0);
}
/* Prompt for command argument, add to buffer with space separator */
static int
{
int ch;
return (-1);
}
return (-1);
}
/* Flush what didn't fit in the buffer */
;
return (-1);
} else {
}
return (0);
}
static void
{
hostname);
else
}
static void
{
int error_num;
char *hostnameinput;
if (argc < 2) {
return;
}
argv[0]);
return;
}
/*
* If host->h_name is a IPv4-mapped IPv6 literal, we'll convert
* it to IPv4 literal address.
*/
sizeof (hostname));
} else {
sizeof (hostname));
}
} else {
/* Keeping with previous semantics */
connected = 0;
return;
}
port = default_port;
if (argc == 3) {
argv[2]);
connected = 0;
return;
}
}
connected = 1;
}
static struct modes {
char *m_name;
char *m_mode;
} modes[] = {
{ "ascii", "netascii" },
{ "netascii", "netascii" },
{ "binary", "octet" },
{ "image", "octet" },
{ "octet", "octet" },
/* { "mail", "mail" }, */
{ 0, 0 }
};
static void
{
struct modes *p;
if (argc < 2) {
mode);
return;
}
if (argc == 2) {
return;
}
/* drop through and print usage message */
}
p = modes;
(void) puts(" ]");
}
/*ARGSUSED*/
static void
{
setmode("octet");
}
/*ARGSUSED*/
static void
{
setmode("netascii");
}
static void
{
if (verbose)
}
/*
* Send file(s).
*/
static void
{
int fd;
int n;
if (argc < 2) {
return;
}
if (argc < 2) {
return;
}
char *cp;
int error_num;
if (finddelimiter(argv[n])) {
return;
}
*targ++ = 0;
return;
}
connected = 1;
/*
* If hp->h_name is a IPv4-mapped IPv6 literal, we'll convert
* it to IPv4 literal address.
*/
sizeof (hostname));
} else {
sizeof (hostname));
}
}
if (!connected) {
return;
}
if (argc < 4) {
if (fd < 0) {
return;
}
if (verbose)
(void) printf("putting %s to %s:%s [%s]\n",
return;
}
/* this assumes the target is a directory */
/* on a remote unix system. hmmmm. */
return;
}
sizeof (buf)) {
continue;
}
if (fd < 0) {
continue;
}
if (verbose)
(void) printf("putting %s to %s:%s [%s]\n",
}
}
static void
putusage(char *s)
{
" %s file ... target (when already connected)\n", s, s);
}
/*
* Receive file(s).
*/
static void
{
int fd;
int n;
char *cp;
char *src;
int error_num;
if (argc < 2) {
return;
}
if (argc < 2) {
return;
}
if (!connected) {
for (n = 1; n < argc; n++)
if (finddelimiter(argv[n]) == 0) {
return;
}
}
for (n = 1; n < argc; n++) {
else {
char *hostnameinput;
*src++ = 0;
continue;
}
connected = 1;
/*
* If hp->h_name is a IPv4-mapped IPv6 literal, we'll
* convert it to IPv4 literal address.
*/
sizeof (hostname));
} else {
sizeof (hostname));
}
}
if (argc < 4) {
if (fd < 0) {
return;
}
if (verbose)
(void) printf("getting from %s:%s to %s [%s]\n",
break;
}
if (fd < 0) {
continue;
}
if (verbose)
(void) printf("getting from %s:%s to %s [%s]\n",
}
}
static void
getusage(char *s)
{
" %s file file ... file if connected\n", s, s);
}
static void
{
int t;
if (argc < 2) {
return;
}
if (argc != 2) {
return;
}
if (t < 0)
else
rexmtval = t;
}
static void
{
int t;
if (argc < 2) {
return;
}
if (argc != 2) {
return;
}
if (t < 0)
else
maxtimeout = t;
}
/*ARGSUSED*/
static void
{
if (connected)
else
(void) puts("Not connected.");
(void) printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
(void) printf("Transfer blocksize option: ");
if (blksize == 0)
(void) puts("off");
else
(void) printf("Server rexmt-interval option: ");
if (srexmtval == 0)
(void) puts("off");
else
}
/*ARGSUSED*/
static void
{
(void) cancel_alarm();
}
static char *
{
char *s;
while (*filename != '\0') {
if (s == NULL)
break;
if (s[1] != '\0')
return (&s[1]);
*s = '\0';
}
return (filename);
}
/*
* Command parser.
*/
static void
{
struct cmd *c;
int ch;
if (!top)
(void) putchar('\n');
for (;;) {
else
continue;
}
/* Flush what didn't fit in the buffer */
;
} else {
if (line[0] != '\0') {
int argc;
char **argv;
if (c == AMBIGCMD)
(void) fputs("?Ambiguous command\n",
stderr);
else if (c == NULL)
(void) fputs("?Invalid command\n",
stderr);
else
}
}
}
}
static struct cmd *
{
char *p, *q;
return (NULL);
for (q = name; *q == *p++; q++)
if (*q == '\0') /* exact match? */
return (c);
if (*q == '\0') /* the name was a prefix */
}
return (found);
}
/*
* Given a string, this function returns the pointer to the delimiting ':'.
* The string can contain an IPv6 literal address, which should be inside a
* pair of brackets, e.g. [1::2]. Any colons inside a pair of brackets are not
* accepted as delimiters. Returns NULL if delimiting ':' is not found.
*/
static char *
{
char *cp;
if (*cp == '[')
else if (*cp == ']')
return (cp);
}
return (NULL);
}
/*
* Given a string which is possibly surrounded by brackets, e.g. [1::2], this
* function returns a string after removing those brackets. If the brackets
* don't match, it does nothing.
*/
static char *
{
}
return (newstr);
}
/*
*/
static void
{
char *cp;
char **argp;
int argc;
static char **argv;
static int argv_size;
perror("tftp: malloc");
exit(1);
}
}
argc = 0;
cp++;
if (*cp == '\0')
break;
argc++;
perror("tftp: realloc");
exit(1);
}
}
cp++;
if (*cp == '\0')
break;
*cp++ = '\0';
}
}
/*ARGSUSED*/
static void
{
exit(0);
}
/*
* Help command.
*/
static void
{
struct cmd *c;
if (argc == 1) {
(void) puts("Commands may be abbreviated. Commands are:\n");
c->help);
return;
}
while (--argc > 0) {
char *arg;
if (c == AMBIGCMD)
arg);
else if (c == NULL)
arg);
else
}
}
/*ARGSUSED*/
static void
{
}
/*ARGSUSED*/
static void
{
}
static void
{
int b;
if (argc < 2) {
return;
}
if (argc != 2) {
return;
}
/* RFC 2348 specifies valid blksize range, allow 0 to turn option off */
if ((b < MIN_BLKSIZE || b > MAX_BLKSIZE) && b != 0)
else
blksize = b;
}
static void
{
int t;
if (argc < 2) {
return;
}
if (argc != 2) {
return;
}
/* RFC 2349 specifies valid timeout range, allow 0 to turn option off */
if ((t < MIN_TIMEOUT || t > MAX_TIMEOUT) && t != 0)
else
srexmtval = t;
}
static void
{
if (argc != 1) {
return;
}
}