diff --git a/SOURCES/tftp-hpa-5.2-tftp-exit-code-cmdmode.patch b/SOURCES/tftp-hpa-5.2-tftp-exit-code-cmdmode.patch new file mode 100644 index 0000000..fd6ba95 --- /dev/null +++ b/SOURCES/tftp-hpa-5.2-tftp-exit-code-cmdmode.patch @@ -0,0 +1,617 @@ +From 172bb0456bfbad4932078ffce7bbaffd4f97c755 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Zaoral?= +Date: Wed, 16 Jul 2025 15:03:43 +0200 +Subject: [PATCH] tftp: propagate errors in single command mode + +--- + tftp/extern.h | 4 +- + tftp/main.c | 132 ++++++++++++++++++++++++++++---------------------- + tftp/tftp.c | 22 +++++++-- + 3 files changed, 94 insertions(+), 64 deletions(-) + +diff --git a/tftp/extern.h b/tftp/extern.h +index 78474fc..a2ed209 100644 +--- a/tftp/extern.h ++++ b/tftp/extern.h +@@ -34,7 +34,7 @@ + #ifndef RECVFILE_H + #define RECVFILE_H + +-void tftp_recvfile(int, const char *, const char *); +-void tftp_sendfile(int, const char *, const char *); ++int tftp_recvfile(int, const char *, const char *); ++int tftp_sendfile(int, const char *, const char *); + + #endif +diff --git a/tftp/main.c b/tftp/main.c +index 2ed9819..d0ab424 100644 +--- a/tftp/main.c ++++ b/tftp/main.c +@@ -105,20 +105,20 @@ int portrange = 0; + unsigned int portrange_from = 0; + unsigned int portrange_to = 0; + +-void get(int, char **); +-void help(int, char **); +-void modecmd(int, char **); +-void put(int, char **); +-void quit(int, char **); +-void setascii(int, char **); +-void setbinary(int, char **); +-void setpeer(int, char **); +-void setrexmt(int, char **); +-void settimeout(int, char **); +-void settrace(int, char **); +-void setverbose(int, char **); +-void status(int, char **); +-void setliteral(int, char **); ++int get(int, char **); ++int help(int, char **); ++int modecmd(int, char **); ++int put(int, char **); ++int quit(int, char **); ++int setascii(int, char **); ++int setbinary(int, char **); ++int setpeer(int, char **); ++int setrexmt(int, char **); ++int settimeout(int, char **); ++int settrace(int, char **); ++int setverbose(int, char **); ++int status(int, char **); ++int setliteral(int, char **); + + static void command(void); + +@@ -132,7 +132,7 @@ static void settftpmode(const struct modes *); + struct cmd { + const char *name; + const char *help; +- void (*handler) (int, char **); ++ int (*handler) (int, char **); + }; + + struct cmd cmdtab[] = { +@@ -191,7 +191,7 @@ char *xstrdup(const char *); + + const char *program; + +-static void usage(int errcode) ++static int usage(int errcode) + { + fprintf(stderr, + #ifdef HAVE_IPV6 +@@ -208,7 +208,7 @@ static void usage(int errcode) + int main(int argc, char *argv[]) + { + union sock_addr sa; +- int arg; ++ int arg, ret; + static int pargc, peerargc; + static int iscmd = 0; + char **pargv; +@@ -347,8 +347,8 @@ int main(int argc, char *argv[]) + pargv[1]); + exit(EX_USAGE); + } +- (*c->handler) (pargc, pargv); +- exit(0); ++ ret = (*c->handler) (pargc, pargv); ++ exit(ret); + } + #ifdef WITH_READLINE + #ifdef HAVE_READLINE_HISTORY_H +@@ -407,7 +407,7 @@ static void getmoreargs(const char *partial, const char *mprompt) + #endif + } + +-void setpeer(int argc, char *argv[]) ++int setpeer(int argc, char *argv[]) + { + int err; + +@@ -419,7 +419,7 @@ void setpeer(int argc, char *argv[]) + } + if ((argc < 2) || (argc > 3)) { + printf("usage: %s host-name [port]\n", argv[0]); +- return; ++ return EX_USAGE; + } + + peeraddr.sa.sa_family = ai_fam; +@@ -428,7 +428,7 @@ void setpeer(int argc, char *argv[]) + printf("Error: %s\n", gai_strerror(err)); + printf("%s: unknown host\n", argv[1]); + connected = 0; +- return; ++ return EX_NOHOST; + } + ai_fam = peeraddr.sa.sa_family; + if (f == -1) { /* socket not open */ +@@ -465,7 +465,7 @@ void setpeer(int argc, char *argv[]) + if (*ep || myport > 65535UL) { + printf("%s: bad port number\n", argv[2]); + connected = 0; +- return; ++ return EX_USAGE; + } + port = htons((u_short) myport); + } +@@ -481,16 +481,17 @@ void setpeer(int argc, char *argv[]) + hostname, tp, (unsigned int)ntohs(port)); + } + connected = 1; ++ return 0; + } + +-void modecmd(int argc, char *argv[]) ++int modecmd(int argc, char *argv[]) + { + const struct modes *p; + const char *sep; + + if (argc < 2) { + printf("Using %s mode to transfer files.\n", mode->m_mode); +- return; ++ return 0; + } + if (argc == 2) { + for (p = modes; p->m_name; p++) +@@ -498,7 +499,7 @@ void modecmd(int argc, char *argv[]) + break; + if (p->m_name) { + settftpmode(p); +- return; ++ return 0; + } + printf("%s: unknown mode\n", argv[1]); + /* drop through and print usage message */ +@@ -512,21 +513,23 @@ void modecmd(int argc, char *argv[]) + sep = " | "; + } + printf(" ]\n"); +- return; ++ return EX_USAGE; + } + +-void setbinary(int argc, char *argv[]) ++int setbinary(int argc, char *argv[]) + { + (void)argc; + (void)argv; /* Quiet unused warning */ + settftpmode(MODE_OCTET); ++ return 0; + } + +-void setascii(int argc, char *argv[]) ++int setascii(int argc, char *argv[]) + { + (void)argc; + (void)argv; /* Quiet unused warning */ + settftpmode(MODE_NETASCII); ++ return 0; + } + + static void settftpmode(const struct modes *newmode) +@@ -539,7 +542,7 @@ static void settftpmode(const struct modes *newmode) + /* + * Send file(s). + */ +-void put(int argc, char *argv[]) ++int put(int argc, char *argv[]) + { + int fd; + int n, err; +@@ -554,14 +557,14 @@ void put(int argc, char *argv[]) + } + if (argc < 2) { + putusage(argv[0]); +- return; ++ return EX_USAGE; + } + targ = argv[argc - 1]; + if (!literal && strchr(argv[argc - 1], ':')) { + for (n = 1; n < argc - 1; n++) + if (strchr(argv[n], ':')) { + putusage(argv[0]); +- return; ++ return EX_USAGE; + } + cp = argv[argc - 1]; + targ = strchr(cp, ':'); +@@ -572,14 +575,14 @@ void put(int argc, char *argv[]) + printf("Error: %s\n", gai_strerror(err)); + printf("%s: unknown host\n", argv[1]); + connected = 0; +- return; ++ return EX_NOHOST; + } + ai_fam = peeraddr.sa.sa_family; + connected = 1; + } + if (!connected) { + printf("No target machine specified.\n"); +- return; ++ return EX_USAGE; + } + if (argc < 4) { + cp = argc == 2 ? tail(targ) : argv[1]; +@@ -587,14 +590,14 @@ void put(int argc, char *argv[]) + if (fd < 0) { + fprintf(stderr, "tftp: "); + perror(cp); +- return; ++ return EX_OSERR; + } + if (verbose) + printf("putting %s to %s:%s [%s]\n", + cp, hostname, targ, mode->m_mode); + sa_set_port(&peeraddr, port); +- tftp_sendfile(fd, targ, mode->m_mode); +- return; ++ err = tftp_sendfile(fd, targ, mode->m_mode); ++ return err; + } + /* this assumes the target is a directory */ + /* on a remote unix system. hmmmm. */ +@@ -605,6 +608,7 @@ void put(int argc, char *argv[]) + strcpy(remote_pth, targ); + remote_pth[dirlen-1] = '/'; + cp = remote_pth + dirlen; ++ err = 0; + for (n = 1; n < argc - 1; n++) { + #ifdef WITH_READLINE + namelen = strlen(tail(argv[n])) + 1; +@@ -619,14 +623,17 @@ void put(int argc, char *argv[]) + if (fd < 0) { + fprintf(stderr, "tftp: "); + perror(argv[n]); ++ err = EX_OSERR; + continue; + } + if (verbose) + printf("putting %s to %s:%s [%s]\n", + argv[n], hostname, remote_pth, mode->m_mode); + sa_set_port(&peeraddr, port); +- tftp_sendfile(fd, remote_pth, mode->m_mode); ++ err |= tftp_sendfile(fd, remote_pth, mode->m_mode); + } ++ ++ return err; + } + + static void putusage(char *s) +@@ -638,10 +645,10 @@ static void putusage(char *s) + /* + * Receive file(s). + */ +-void get(int argc, char *argv[]) ++int get(int argc, char *argv[]) + { + int fd; +- int n; ++ int n, err; + char *cp; + char *src; + +@@ -653,28 +660,28 @@ void get(int argc, char *argv[]) + } + if (argc < 2) { + getusage(argv[0]); +- return; ++ return EX_USAGE; + } + if (!connected) { + for (n = 1; n < argc; n++) + if (literal || strchr(argv[n], ':') == 0) { + getusage(argv[0]); +- return; ++ return EX_USAGE; + } + } ++ err = 0; + for (n = 1; n < argc; n++) { + src = strchr(argv[n], ':'); + if (literal || src == NULL) + src = argv[n]; + else { +- int err; +- + *src++ = 0; + peeraddr.sa.sa_family = ai_fam; + err = set_sock_addr(argv[n], &peeraddr, &hostname); + if (err) { + printf("Warning: %s\n", gai_strerror(err)); + printf("%s: unknown host\n", argv[1]); ++ err = EX_NOHOST; + continue; + } + ai_fam = peeraddr.sa.sa_family; +@@ -687,13 +694,13 @@ void get(int argc, char *argv[]) + if (fd < 0) { + fprintf(stderr, "tftp: "); + perror(cp); +- return; ++ return EX_OSERR; + } + if (verbose) + printf("getting from %s:%s to %s [%s]\n", + hostname, src, cp, mode->m_mode); + sa_set_port(&peeraddr, port); +- tftp_recvfile(fd, src, mode->m_mode); ++ err = tftp_recvfile(fd, src, mode->m_mode); + break; + } + cp = tail(src); /* new .. jdg */ +@@ -702,14 +709,16 @@ void get(int argc, char *argv[]) + if (fd < 0) { + fprintf(stderr, "tftp: "); + perror(cp); ++ err = EX_OSERR; + continue; + } + if (verbose) + printf("getting from %s:%s to %s [%s]\n", + hostname, src, cp, mode->m_mode); + sa_set_port(&peeraddr, port); +- tftp_recvfile(fd, src, mode->m_mode); ++ err |= tftp_recvfile(fd, src, mode->m_mode); + } ++ return err; + } + + static void getusage(char *s) +@@ -720,7 +729,7 @@ static void getusage(char *s) + + int rexmtval = TIMEOUT; + +-void setrexmt(int argc, char *argv[]) ++int setrexmt(int argc, char *argv[]) + { + int t; + +@@ -732,18 +741,19 @@ void setrexmt(int argc, char *argv[]) + } + if (argc != 2) { + printf("usage: %s value\n", argv[0]); +- return; ++ return EX_USAGE; + } + t = atoi(argv[1]); + if (t < 0) + printf("%s: bad value\n", argv[1]); + else + rexmtval = t; ++ return 0; + } + + int maxtimeout = 5 * TIMEOUT; + +-void settimeout(int argc, char *argv[]) ++int settimeout(int argc, char *argv[]) + { + int t; + +@@ -755,24 +765,26 @@ void settimeout(int argc, char *argv[]) + } + if (argc != 2) { + printf("usage: %s value\n", argv[0]); +- return; ++ return EX_USAGE; + } + t = atoi(argv[1]); + if (t < 0) + printf("%s: bad value\n", argv[1]); + else + maxtimeout = t; ++ return 0; + } + +-void setliteral(int argc, char *argv[]) ++int setliteral(int argc, char *argv[]) + { + (void)argc; + (void)argv; /* Quiet unused warning */ + literal = !literal; + printf("Literal mode %s.\n", literal ? "on" : "off"); ++ return 0; + } + +-void status(int argc, char *argv[]) ++int status(int argc, char *argv[]) + { + (void)argc; + (void)argv; /* Quiet unused warning */ +@@ -785,6 +797,7 @@ void status(int argc, char *argv[]) + literal ? "on" : "off"); + printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n", + rexmtval, maxtimeout); ++ return 0; + } + + void intr(int sig) +@@ -929,7 +942,7 @@ static void makeargv(void) + *argp++ = 0; + } + +-void quit(int argc, char *argv[]) ++int quit(int argc, char *argv[]) + { + (void)argc; + (void)argv; /* Quiet unused warning */ +@@ -939,7 +952,7 @@ void quit(int argc, char *argv[]) + /* + * Help command. + */ +-void help(int argc, char *argv[]) ++int help(int argc, char *argv[]) + { + struct cmd *c; + +@@ -949,7 +962,7 @@ void help(int argc, char *argv[]) + printf("Commands may be abbreviated. Commands are:\n\n"); + for (c = cmdtab; c->name; c++) + printf("%-*s\t%s\n", (int)HELPINDENT, c->name, c->help); +- return; ++ return 0; + } + while (--argc > 0) { + char *arg; +@@ -962,22 +975,25 @@ void help(int argc, char *argv[]) + else + printf("%s\n", c->help); + } ++ return 0; + } + +-void settrace(int argc, char *argv[]) ++int settrace(int argc, char *argv[]) + { + (void)argc; + (void)argv; /* Quiet unused warning */ + + trace = !trace; + printf("Packet tracing %s.\n", trace ? "on" : "off"); ++ return 0; + } + +-void setverbose(int argc, char *argv[]) ++int setverbose(int argc, char *argv[]) + { + (void)argc; + (void)argv; /* Quiet unused warning */ + + verbose = !verbose; + printf("Verbose mode %s.\n", verbose ? "on" : "off"); ++ return 0; + } +diff --git a/tftp/tftp.c b/tftp/tftp.c +index d31553b..3a3a193 100644 +--- a/tftp/tftp.c ++++ b/tftp/tftp.c +@@ -62,11 +62,11 @@ static void tpacket(const char *, struct tftphdr *, int); + /* + * Send the requested file. + */ +-void tftp_sendfile(int fd, const char *name, const char *mode) ++int tftp_sendfile(int fd, const char *name, const char *mode) + { + struct tftphdr *ap; /* data and ack packets */ + struct tftphdr *dp; +- int n; ++ int n, err; + volatile int is_request; + volatile u_short block; + volatile int size, convert; +@@ -84,6 +84,7 @@ void tftp_sendfile(int fd, const char *name, const char *mode) + block = 0; + is_request = 1; /* First packet is the actual WRQ */ + amount = 0; ++ err = 0; + + signal(SIGALRM, timer); + do { +@@ -94,6 +95,7 @@ void tftp_sendfile(int fd, const char *name, const char *mode) + size = readit(file, &dp, convert); + if (size < 0) { + nak(errno + 100, NULL); ++ err = EX_OSERR; + break; + } + dp->th_opcode = htons((u_short) DATA); +@@ -108,6 +110,7 @@ void tftp_sendfile(int fd, const char *name, const char *mode) + &peeraddr.sa, SOCKLEN(&peeraddr)); + if (n != size + 4) { + perror("tftp: sendto"); ++ err = EX_OSERR; + goto abort; + } + read_ahead(file, convert); +@@ -121,6 +124,7 @@ void tftp_sendfile(int fd, const char *name, const char *mode) + alarm(0); + if (n < 0) { + perror("tftp: recvfrom"); ++ err = EX_OSERR; + goto abort; + } + sa_set_port(&peeraddr, SOCKPORT(&from)); /* added */ +@@ -131,6 +135,7 @@ void tftp_sendfile(int fd, const char *name, const char *mode) + ap_block = ntohs((u_short) ap->th_block); + if (ap_opcode == ERROR) { + printf("Error code %d: %s\n", ap_block, ap->th_msg); ++ err = EX_PROTOCOL; + goto abort; + } + if (ap_opcode == ACK) { +@@ -163,16 +168,18 @@ void tftp_sendfile(int fd, const char *name, const char *mode) + stopclock(); + if (amount > 0) + printstats("Sent", amount); ++ ++ return err; + } + + /* + * Receive a file. + */ +-void tftp_recvfile(int fd, const char *name, const char *mode) ++int tftp_recvfile(int fd, const char *name, const char *mode) + { + struct tftphdr *ap; + struct tftphdr *dp; +- int n; ++ int n, err; + volatile u_short block; + volatile int size, firsttrip; + volatile unsigned long amount; +@@ -190,6 +197,7 @@ void tftp_recvfile(int fd, const char *name, const char *mode) + block = 1; + firsttrip = 1; + amount = 0; ++ err = 0; + + signal(SIGALRM, timer); + do { +@@ -211,6 +219,7 @@ void tftp_recvfile(int fd, const char *name, const char *mode) + SOCKLEN(&peeraddr)) != size) { + alarm(0); + perror("tftp: sendto"); ++ err = EX_OSERR; + goto abort; + } + write_behind(file, convert); +@@ -224,6 +233,7 @@ void tftp_recvfile(int fd, const char *name, const char *mode) + alarm(0); + if (n < 0) { + perror("tftp: recvfrom"); ++ err = EX_OSERR; + goto abort; + } + sa_set_port(&peeraddr, SOCKPORT(&from)); /* added */ +@@ -234,6 +244,7 @@ void tftp_recvfile(int fd, const char *name, const char *mode) + dp_block = ntohs((u_short) dp->th_block); + if (dp_opcode == ERROR) { + printf("Error code %d: %s\n", dp_block, dp->th_msg); ++ err = EX_PROTOCOL; + goto abort; + } + if (dp_opcode == DATA) { +@@ -258,6 +269,7 @@ void tftp_recvfile(int fd, const char *name, const char *mode) + size = writeit(file, &dp, n - 4, convert); + if (size < 0) { + nak(errno + 100, NULL); ++ err = EX_OSERR; + break; + } + amount += size; +@@ -272,6 +284,8 @@ void tftp_recvfile(int fd, const char *name, const char *mode) + stopclock(); + if (amount > 0) + printstats("Received", amount); ++ ++ return err; + } + + static int +-- +2.50.1 + diff --git a/SOURCES/tftp-server-tmpfiles.conf b/SOURCES/tftp-server-tmpfiles.conf new file mode 100644 index 0000000..2d7d2a3 --- /dev/null +++ b/SOURCES/tftp-server-tmpfiles.conf @@ -0,0 +1 @@ +d /var/lib/tftpboot 0755 root root - diff --git a/SPECS/tftp.spec b/SPECS/tftp.spec index d9b3ba2..40f3f47 100644 --- a/SPECS/tftp.spec +++ b/SPECS/tftp.spec @@ -3,12 +3,13 @@ Summary: The client for the Trivial File Transfer Protocol (TFTP) Name: tftp Version: 5.2 -Release: 38%{?dist} +Release: 40%{?dist} License: BSD URL: http://www.kernel.org/pub/software/network/tftp/ Source0: http://www.kernel.org/pub/software/network/tftp/tftp-hpa/tftp-hpa-%{version}.tar.bz2 Source1: tftp.socket Source2: tftp.service +Source3: tftp-server-tmpfiles.conf Patch0: tftp-0.40-remap.patch Patch2: tftp-hpa-0.39-tzfix.patch @@ -23,6 +24,7 @@ Patch10: tftp-enhanced-logging.patch Patch11: tftp-hpa-5.2-gcc10.patch Patch12: tftp-rewrite-macro.patch Patch13: tftp-hpa-5.2-covscan.patch +Patch14: tftp-hpa-5.2-tftp-exit-code-cmdmode.patch BuildRequires: autoconf BuildRequires: gcc @@ -66,6 +68,7 @@ systemd socket activation, and is disabled by default. %patch11 -p1 -b .gcc10 %patch12 -p1 -b .rewrite-macro %patch13 -p1 -b .covscan +%patch14 -p1 -b .cmd_exit_code %build autoreconf @@ -77,12 +80,14 @@ mkdir -p ${RPM_BUILD_ROOT}%{_bindir} mkdir -p ${RPM_BUILD_ROOT}%{_mandir}/man{1,8} mkdir -p ${RPM_BUILD_ROOT}%{_sbindir} mkdir -p ${RPM_BUILD_ROOT}%{_localstatedir}/lib/tftpboot +mkdir -p ${RPM_BUILD_ROOT}%{_tmpfilesdir} mkdir -p ${RPM_BUILD_ROOT}%{_unitdir} make INSTALLROOT=${RPM_BUILD_ROOT} SBINDIR=%{_sbindir} MANDIR=%{_mandir} INSTALL='install -p' install install -p -m 644 %SOURCE1 ${RPM_BUILD_ROOT}%{_unitdir} install -p -m 644 %SOURCE2 ${RPM_BUILD_ROOT}%{_unitdir} +install -p -m 644 %SOURCE3 ${RPM_BUILD_ROOT}%{_tmpfilesdir}/%{name}.conf %post server %systemd_post tftp.socket @@ -104,9 +109,16 @@ install -p -m 644 %SOURCE2 ${RPM_BUILD_ROOT}%{_unitdir} %dir %{_localstatedir}/lib/tftpboot %{_sbindir}/in.tftpd %{_mandir}/man8/* +%{_tmpfilesdir}/%{name}.conf %{_unitdir}/* %changelog +* Mon Jul 21 2025 Lukáš Zaoral - 5.2-40 +- tftp: propagate exit codes in non-interactive mode (RHEL-96947) + +* Wed Feb 26 2025 Lukáš Zaoral - 5.2-39 +- fix creation of /var/lib/tftpboot in image mode (RHEL-77491) + * Thu Jan 04 2024 Lukáš Zaoral - 5.2-38 - fix regression with too chatty syslog calls when IPv6 is disabled (RHEL-19588)