.gitignore000066400000000000000000000003451201445343400130500ustar00rootroot00000000000000.deps PLATFORM Makefile Makefile.in aclocal.m4 configure autom4te.cache stamp-h1 config.h config.log config.status test/Makefile.in redhat/atftp.spec *.o atftp atftpd *.tar.gz config.guess config.sub depcomp install-sh missing BUGS000066400000000000000000000010271201445343400115410ustar00rootroot00000000000000If you find some bugs, please send us a detailed description of the problem observed. Please include the logfile and a full description of your setup. To get a detailed log, use --verbose=7 and --logfile /var/log/tftpd to generate a separate logfile. Please include the number of machines that were booting of the server, the type of server (single or dual processor, processor speed, etc.) and the type of network you have (10Mbit, 100Mbit or 1Gbit). Jean-Pierre Lefebvre Remi Lefebvre Changelog000066400000000000000000000273501201445343400126770ustar00rootroot00000000000000atftp (0.7.xx) * atftpd.c: Fixed a potential DoS bug (introduced by the IPv6 patch) thankfully taken from Debian atftpd-0.7.dfsg-11 * Fix Debian Bug #613582 and #258998 atftpd: does not reply properly when there's more than 1 interface * Fix Debian Bug #622840 atftpd: Forgets port if both --port and --bind-address are used * Fix Debian Bug #606969 atftp exits with no error after a get when disk is full * Fix Debian Bug #575831 atftp: error return value when tftp put file * Fix missing default port from Ubuntu bug #972834 * Merged patches to improve debugging and warning messages (from Florian Fainelli ) * Merged patch from Gentoo distribution: add support for proprietary password extension necessary for transferring files to linksys routers (atftp client) * Added patch from Gentoo bug #322601: client fails for filenames containing spaces * Listening Address configuration fixed * Added Patch "Blksize option can be smaller than SEGSIZE" (from Michał Rzechonek ) * Merged Debian patchset 0.7.dfsg-9.3 into main see debian changelog below for details * Initial Developer + Maintainer "Jean-Pierre Lefebvre" gave up maintenance, thanks for all the work!!! * New Project home: http://sourceforge.net/projects/atftp/ ======================================================== debian changelog inserted here for completeness ======================================================== atftp (0.7.dfsg-9.3) unstable; urgency=low * Non-maintainer upload. * Apply patch listen on requested port when in daemon mode. Thanks to Len Sorensen. (Closes: #609813) -- tony mancill Wed, 12 Jan 2011 20:58:05 -0800 atftp (0.7.dfsg-9.2) unstable; urgency=low * Non-maintainer upload. * Fixed use of sendto() over a connected datagram socket on FreeBSD (closes: #598474). -- Giovanni Mascellani Mon, 04 Oct 2010 16:46:32 +0200 atftp (0.7.dfsg-9.1) unstable; urgency=low * Non-maintainer upload. * Apply IPv6 support patch by Ben Hutchings. Closes: #580473 * Add AC_GNU_SOURCE to configure.ac to address FTBFS. - Patches applied directly to sources to minimize changes for NMU, as the current Debian packaging does not include a patch system. -- tony mancill Wed, 15 Sep 2010 21:24:52 -0700 atftp (0.7.dfsg-9) unstable; urgency=medium * urgency=medium RC bug. * use rmdir instead of rm in postrm. Closes: #573992, #574211 * added $remote_fs in Required-Start -- Ludovic Drolez Mon, 29 Mar 2010 18:55:55 +0200 atftp (0.7.dfsg-8) unstable; urgency=low * depends on libreadline-dev. Closes: #553729 * Purge empty dir. Closes: #531282 * /srv/tftp is now the default tftp root data directory. Closes: #537642 * Updated cs.po. Closes: #534959 * Updated config.sub .guess. Closes: #536295 * Fixed a typo in the help screen. Closes: #537405 * Make sure we have the --daemon option before starting atftpd. Closes: #535604 -- Ludovic Drolez Tue, 21 Aug 2009 17:03:24 +0200 atftp (0.7.dfsg-7) unstable; urgency=low * Crash fix. Closes: #514521 * Updated sv.po. Closes: #503348 * Added support for logging to stdout. Closes: #484739 * Added the --listen-local patch. Closes: #366632 * Recommends inet-superserver. Closes: #516407 -- Ludovic Drolez Wed, 01 Apr 2009 17:03:07 +0200 atftp (0.7.dfsg-6) unstable; urgency=medium * Urgency = medium because of a grave bug * Now generate a cleaner /etc/default/atftpd file. Closes: #489757 * Do not overwrite /etc/default/atftpd and inetd.conf. Closes: #490152 * The basedir is now created with proper permissions. Upload feature tested. Closes: #489757 * Updated sv.po. Closes: #491757 -- Ludovic Drolez Tue, 22 Jul 2008 19:07:56 +0200 atftp (0.7.dfsg-5) unstable; urgency=medium * inetd.conf: change udp to udp4. Closes: #484932 * fixed pcre substitutions. Closes: #473777 -- Ludovic Drolez Fri, 13 Jun 2008 16:00:57 +0200 atftp (0.7.dfsg-4) unstable; urgency=medium * Urgency=medium because of RC bug fixed * Choosed /var/lib/tftpboot as default tftp directory, and removed the provides field. Closes: #455263, #411322 * Moved the watch file. Closes: #449674 * Fixed incorrect options handling thanks to Hollis Blanchard. Closes: #332621 * Updated pt.po. Closes: #443653 -- Ludovic Drolez Tue, 18 Dec 2007 18:49:33 +0100 atftp (0.7.dfsg-3) unstable; urgency=high * Removed the inetd dependency. * Added Leo Weppelman select patch. Closes: #411456 * Fixed the FTBFS. Closes: #436310 -- Ludovic Drolez Mon, 6 Aug 2007 20:52:06 +0200 atftp (0.7.dfsg-2) unstable; urgency=medium * Use CLOCKS_PER_SEC instead of CLK_TCK. Fixed a FTBFS. Closes: #420900 * Re-added a kFreeBSD patch lost by a NMU !!! Closes: #404063, #402700 * New debconf translations. Closes: #410212, #414112, #422416 -- Ludovic Drolez Fri, 18 May 2007 17:59:01 +0200 atftp (0.7.dfsg-1.2) unstable; urgency=low * Non-maintainer upload to fix a pending l10n issues that affects the experimental Debian i18n server. * Debconf translations: - Japanese fixed. Closes: #410525 -- Christian Perrier Sun, 11 Feb 2007 15:08:39 +0100 atftp (0.7.dfsg-1.1) unstable; urgency=low * Non-maintainer upload to fix longstanding l10n issues * Debconf templates translations: - German updated. Closes: #399964 - Japanense updated. Closes: #402616 - Dutch updated. Closes: #392215 - French updated. Closes: #393740 - Russian updated. Closes: #404426 - Spanish updated. Closes: #402098 -- Christian Perrier Sat, 20 Jan 2007 12:48:31 +0100 atftp (0.7.dfsg-1) unstable; urgency=medium * Integrated the NMUs. Closes: #382683, #365188, #389830 * If netbase is not installed, then we don't need to use update-inetd. Closes: #388295 * Bump Standards-Version to 3.7.2. * Add debconf-updatepo to the rules. * Russian translation of debconf messages thanks to Yuri Kozlov. Closes: #368498 -- Ludovic Drolez Mon, 2 Oct 2006 00:31:23 +0200 atftp (0.7.dfsg-0.2) unstable; urgency=low * Non-maintainer upload. * debian/control: Remove netkit-inetd recommends, and make the netbase dependency versioned. netbase provides the appropriate inetd dependency. Closes: #382683. -- Roger Leigh Sun, 20 Aug 2006 17:11:26 +0100 atftp (0.7.dfsg-0.1) unstable; urgency=low * Non-maintainer upload. * Repackage upstream without RFC (Closes: #365188) -- Julien Danjou Thu, 1 Jun 2006 15:53:11 +0200 atftp (0.7-11) unstable; urgency=low * added a patch for freebsd. Closes: #342391 * added debconf Portuguese translation. Closes: #342284 -- Ludovic Drolez Tue, 13 Dec 2005 16:29:05 +0100 atftp (0.7-10) unstable; urgency=low * DH_COMPAT=4 and added ${misc:Depends}. Closes: #331747 * Debconf Swedish translation update. Closes: #330263 -- Ludovic Drolez Fri, 7 Oct 2005 15:00:35 +0200 atftp (0.7-9) unstable; urgency=medium * Random segfaults fixed. Closes: #271816 * Now only recommend netkid-inetd. Closes: #313208 * Updated the Vietnamese debconf translation. Closes: #313122 -- Ludovic Drolez Tue, 21 Jun 2005 21:51:23 +0200 atftp (0.7-8) unstable; urgency=low * Typos removed from atftpd.templates. Closes: #309468 * Added the Vietnamese translation for debconf. Closes: #309461 * Thanks to Clytie Siddall for submitting the two bugs above. -- Ludovic Drolez Tue, 7 Jun 2005 21:31:25 +0200 atftp (0.7-7) unstable; urgency=low * Fixed a FTBFS on amd64. Closes: #297549 * Added Japanese and Brazilian debconf translations. Closes: #304280,#297038 -- Ludovic Drolez Tue, 12 Apr 2005 12:55:47 +0200 atftp (0.7-6) unstable; urgency=low * Segfault fixed on AMD64. Closes: Bug#291829 * debian 'watch' file added. -- Ludovic Drolez Wed, 26 Jan 2005 19:12:44 +0100 atftp (0.7-5) unstable; urgency=high * Ugency=high because of a RC bug fixed. * Removed a bashism in the postinst. Closes: #289633 * Czech po-debconf translation added by Miroslav Kure. Closes: #288014 * Danish po-debconf translation added by Morten Brix Pedersen. Closes: #288133 * Copyright fixed. Closes: #290062 -- Ludovic Drolez Tue, 11 Jan 2005 12:19:27 +0100 atftp (0.7-4) unstable; urgency=low * updated all po-debconf translations. Closes: #281561 * polish debconf translation added. Thanks to Bartosz Fenski. * added debconf support for setting the multicast TTL value * default mcast subnet changed to 239.239.239.0/24 since some routers do not seem to like 239.255.0.0/24 -- Ludovic Drolez Mon, 28 Dec 2004 19:11:57 +0100 atftp (0.7-3) unstable; urgency=low * /etc/default/atftpd removed on purge. Closes: #279707 * purging stops atftpd. Closes: #275258 * punctuation modified. Closes: #275692 * updated the German debconf translation. Closes: #275691 -- Ludovic Drolez Fri, 5 Nov 2004 14:32:57 +0100 atftp (0.7-2) unstable; urgency=medium * Patched tftp.c, to have an exit status !=0 when an error occurs * Data corruption bug in multicast mode fixed. Closes: #275052 Urgency set to medium because of this bug. * Typos in description corrected. Closes: #272565 * Dutch debconf translation added. Closes: #245913 * Debconf: removed the initial question and changed priority levels. Closes: #266329 -- Ludovic Drolez Sun, 26 Sep 2004 14:25:40 +0200 ======================================================== debian changelog insert ends here ======================================================== Prior versions of atftp where using the Debian changelog as the main changelog file. This was easier since my brother was the maintainer. From now on, I'm using a separate file (this file). Debian related changes will be maintained by the maintainer and not reflected in this source tree. atftp (0.7) * Fixed typo (Debian bug: #147218). * Fixed French translations for real this time (Debian bug: #136339). * Add DESTDIR to install rules in Makefile.am, used when building RPM. (from Jose Pedro Oliveira) * Fix make dist problem where not all files get in the archives (from Joshua Aune) * add dist-hook to remove CVS files * Fix bad timeout behaviour. (Debian bug: #155300) (Debian bug: #180461) * Fix description in control file (Debian bug: #162836) * Client can now compile without libreadline. This is also a configure option (based on Leif Lindholm patch) * Copy argz function from libc (provided by Leif Lindholm). Configure use this local copy if argz functions not found in libc. * Incorporate proposed enhencement (failing multicast client and fixes) from Leif Lindholm and Bojan Pisler, with some modifications in the implementation. * Incorporate PCRE support from Jeff Miller. * Add mtftp support (as defined in PXE specification) * Fixed type (Debian bug: #181796) * Fix (from Steve Kemp) security issue reported here: http://www.securitytracker.com/alerts/2002/Sep/1005231.html http://www.netric.org/advisories/netric-adv010.txt * Make atftp reply on the same interface as the received request * Add --bind-address option for atftpd to bind to a particular IP address only (from Thomas Anders ) * Implement netascii support * Implement --pidfile option (see man page) * Update debian files -- J-P Fri, 21 Feb 2003 00:17:31 -0500 FAQ000066400000000000000000000124701201445343400114140ustar00rootroot000000000000001) What are the best values for --tftpd-timeout, --retry-timeout and --max-thread ? There is no absolute answer to that question. It is highly dependent of your personnal setup. Here's an explanation of what they mean and how to tune them. --tftpd-timeout controls how much time the server will wait for an incomming connection before killing the main thread. If you use small number, the server will be respawned by inetd when a new query arrives. If number is high, atftpd will behave more like a standalone server in that it will always receive queries directly. When booting a whole cluster, the first tftp request will start the daemon and have higher latency. All other clients will be handled directly by the tftp server. It is a good idea to set the timeout high enough so that the main thread won't hog your system killing itself and respawning all the time. --retry-timeout controls how much time the server waits before retransmitting a packet. If you expect some lag on the network (when the network is under high load), it is a good idea to increase that value. Note that the client's delay must be taken into consideration. The client can set the server delay too, and it overides the --retry-timeout value. --max-thread controls how many simultaneous client may be served. This limit depends on your server's performance. It also depends on the maximum load you are willing to put on the server. For exemple, this server may have other things to do, and you want to limit the number of clients booting at the same time to 10. The maximum number of threads is also throttled by the available bandwidth of the network and server, because packet cannot be processed fast enough and there is a maximum rate at which servers may be started. But this is not a desirable condition and --maxthread should be set to avoid that. 2) Why do I get "recvfrom: Connection refused" in my log file? That indicates that either your server or network can't handle all the packets fast enough. What happens is the following: - client sends a RRQ (read request) - server starts a thread (A) that sends a DATA packet - the client times out and sends a second RRQ - server A sends the whole file - client and server thread A both exit normally - server finally starts a second thread (B) for the second RRQ - the server thread sends a DATA packet to the client - the client isn't listenning anymore, we got a connection refused. Solution: a) increase timeout on client and server side b) reduce the number of concurrent thread allowed c) do nothing, it's not harmfull at all. 3) How can I boot a simple image from the network? A boot from LAN setup requires the following on the server side: a dhcp server, a tftp server (atftpd), a working pxelinux config, a kernel image and a root file system image. You can get documentation on how to configure the dhcp server to work with pxelinux from the pxelinux and dhcp documentation. For atftp to work out of the box, be sure to have the following line in your inetd.conf and to restart the inetd daemon: tftp dgram udp wait nobody /usr/sbin/tcpd /usr/sbin/in.tftpd /tftpboot You also need to have /tftpboot world readable. The pxelinux configuration is the same as syslinux. Documentation for it can be found in the syslinux package. The configuration file for pxelinux will tell it the name of the kernel and file system images to download. It is very important that you tell the kernel image where to get its root file system with rdev like this for example: rdev image /dev/ramdisk You can find detailed information on how to create a filesystem image in the Bootdisk HOWTO (www.linuxdoc.org). On the client side, you need to have a boot ROM. Have a look at Etherboot (www.etherboot.org), NetTools and Nilo (www.nilo.org) to find out more information about this if you need to burn one. After you got all of these setup, you should see the client attempt to get an IP address on boot, download pxelinux.bin, then download the kernel and filesystem images and boot from it. 4) I followed the above steps and it still fails to boot! Try putting log verbosity at high in the concerned programs on the server side and see if something fails or if you get the requests at all. You should see dhcpd give a lease to the client, if it doesn't, your dhcp configuration is faulty. You can also monitor the activity on the network to track down the problem using tools like tcpdump or ethereal. 5) How do I setup multicast stuff? - Make sure your client and server support multicast. - Make sure you server routing table know what to do with multicast addresses. You need to do something like this: route add -net 224.0.0.0 netmask 240.0.0.0 dev eth0 - Make sure your network is working by testing with atftp client against atftpd server That's currently all that I've made working folks. I've never tried a multicast boot ROM or boot loader yet. 6) What inetd or xinetd configuration should I use? Something like that for inetd in /etc/inetd.conf: tftp dgram udp wait nobody /usr/sbin/tcpd /usr/sbin/in.tftpd For xinetd, in /etc/xinetd.conf: service tftp { socket_type = dgram protocol = udp wait = no user = nobody server = /usr/sbin/in.tftpd server_args = } This is the basic stuff. Read inetd or xinetd man page for more specialised configuration.INSTALL000066400000000000000000000076421201445343400121200ustar00rootroot00000000000000The simplest way to install atftp is using either the Debian package or one provided by your distribution if any. If you need to install atftp from source, here's the procedure. 1) Needed libraries ---------------- libpthread Needed for the atftpd server. libwrap Optional if you need host access control. libpcre Optional if you want to perform file name substitution. See README.PCRE. libreadline Optional. Used by the atftp client for better command line input and history. 2) Needed tools ------------ At least, you need these programs: make gcc You may also need these: git automake (tested using version 1.7 and 1.8) autoconf (tested with version 2.50) 3) How to compile -------------- 3.1) From tarball ./configure [options] (this generates makefiles) make (actually build the programs) su -c 'make install' (install files (default location is /usr) 3.2) From git checkout git clone git://atftp.git.sourceforge.net/gitroot/atftp/atftp (this creates a clone of the git repository) cd atftp (change into the newly created subdir) ./autogen.sh (this generates the configure script) ./configure [options] (this generate makefiles) make (actually build the programs) su -c 'make install' (install files (default location is /usr) 4) How to start atftpd server -------------------------- 4.1) Using the inetd super server Add this line to the /etc/inetd.conf file: tftp dgram udp wait nobody /usr/sbin/tcpd /usr/sbin/in.tftpd /tftpboot You can add needed option to atftpd as you which at the end of the line. 4.2) Using xinetd Add this to the /etc/xinetd.conf file, or create /etc/xinetd.d/tftp-udp file with the following content: # tftp-udp service tftp { id = tftp-udp disable = no socket_type = dgram protocol = udp wait = no user = nobody nice = 5 server = /usr/local/sbin/atftpd server_args = /tftpboot # add other server argument as necessary } # eof 4.3) As a stand alone server from init.d scripts You need to add the proper init script in you boot sequence. The Debian package automatically does that. I'm not aware if any rpm based distribution include init scripts. If you absolutely need this on rpm based distribution or on other systems, start with the Debian scripts and adapt it to your particular system. 5) Information for future developers of atftp ------------------------------------------ 5.1) Cleanup the source directory After some work and compiling in the package sources, you can delete the files produced from the compilers by running make clean Note: The "Makefile" necessary for this operation is only available if the "./configure" command has been run at least once. More cleanup is done with the command make distclean This removes all files produced by "./configure" - which includes the Makefile. If you want to use "make " again, you need to run "./configure" before. 5.2) Create a release tarball If a new release should be created, first edit configure.ac and change the AM_INIT_AUTOMAKE parameter to the new release version number. Then execute "./autogen.sh" and "./configure". After that, make distcheck creates a tar archive with the requested version number, unpacks it immedia- tely in a temporary subdirectory, compiles the package and executes the test.sh suite and cleans all that up. If you get the final message ============================================= atftp- archives ready for distribution: atftp-.tar.gz ============================================= then you can upload atftp-.tar.gz to http://sourceforge.net/projects/atftp/files/ LICENSE000066400000000000000000000431101201445343400120620ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. Makefile.am000066400000000000000000000033551201445343400131200ustar00rootroot00000000000000# Makefile.am # Automake makefile for atftp # # $Id: Makefile.am,v 1.15 2004/03/16 01:37:24 jp Exp $ # # Copyright (c) 2001 Jean-Pierre Lefebvre # and Remi Lefebvre # # atftp is free software; you can redistribute them and/or modify them # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later AUTOMAKE_OPTIONS = foreign SUBDIRS = . test DIST_SUBDIRS = $(SUBDIRS) CLEANFILES = *~ DISTCLEANFILES = libtool PLATFORM AM_CPPFLAGS = -D_GNU_SOURCE man_MANS = atftp.1 atftpd.8 dist_scripts = autogen.sh dist_docs = BUGS Changelog FAQ LICENSE README.CVS README.MCAST README.PCRE dist_dirs = test redhat docs debian EXTRA_DIST = $(dist_docs) $(dist_dirs) $(man_MANS) $(dist_scripts) noinst_HEADERS = argz.h logger.h options.h stats.h tftp.h tftp_def.h tftp_io.h \ tftpd.h tftpd_pcre.h tftpd_mtftp.h bin_PROGRAMS = atftp atftp_LDADD = $(LIBTERMCAP) $(LIBREADLINE) atftp_SOURCES = tftp.c tftp_io.c logger.c options.c tftp_def.c tftp_file.c \ argz.c tftp_mtftp.c sbin_PROGRAMS = atftpd atftpd_LDADD = $(LIBWRAP) $(LIBPTHREAD) $(LIBPCRE) atftpd_SOURCES = tftpd.c logger.c options.c stats.c tftp_io.c tftp_def.c \ tftpd_file.c tftpd_list.c tftpd_mcast.c argz.c tftpd_pcre.c \ tftpd_mtftp.c install-exec-hook: (cd $(DESTDIR)$(sbindir) && ln -sf atftpd in.tftpd) install-data-hook: (cd $(DESTDIR)$(mandir)/man8 && ln -sf atftpd.8 in.tftpd.8) uninstall-local: rm -f $(DESTDIR)$(sbindir)/in.tftpd $(DESTDIR)$(mandir)/man8/in.tftpd.8 dist-hook: cd $(distdir) && rm -rf `find . -type d -name CVS` README000066400000000000000000000035721201445343400117450ustar00rootroot00000000000000 Jean-Pierre Lefebvre August 20th, 2000 ----------------- atftp stands for Advanced Trivial File Transfer Protocol. It is called "advanced", by contrast to others TFTP servers, for two reasons. Firstly, it is intended to be fully compliant with all related RFCs. This include RFC1350, RFC2090, RFC2347, RFC2348 and RFC2349. To my knowledge, there is no TFTP server currently available in the public domain that fulfills this requirement. Secondly, atftp is intended for serving boot files to large clusters. It is multi-threaded and support multicast (RFC2090 and PXE), allowing faster boot of hundreds of machine simultaneously. I started writing the atftp server after trying to boot Debian from the LAN using pxelinux (distributed with syslinux). Since pxelinux needs support for the "tsize" option defined in RFC2349, I looked for different TFTP servers but found none that fulfilled my needs. With atftp, I have successfully used pxelinux and dhcpd to boot from the LAN. Unfortunately, new development will slow down since I do it on my spare time and atftp now does what I need. However, atftp is actively maintained. Comments, bug reports and patches are welcome. Great thanks to my brother Remi who works on the client and server implementation and the debian packaging. Authors ------- Jean-Pierre Lefebvre Remi Lefebvre Contributors ------------ Jeff Miller Leif Lindholm Jens Schmidt Svend Odgaard Joshua Aune Mario Lorenz Allen Reese Thayne Harbaugh Thomas Anders Michał Rzechonek Florian Fainelli README.CVS000066400000000000000000000014701201445343400123720ustar00rootroot00000000000000atftp-0.7.1 and later ===================== Development of atftp has switched over to a sourceforge project. A git repository is used for the source code. A copy of the repository can be fetched with the command git clone git://atftp.git.sourceforge.net/gitroot/atftp/atftp Please read the file INSTALL for further instructions. atftp-0.7 ========= The development for atftp is done using CVS. It is possible to access the repository read-only by using the following CVSROOT with a null password: :pserver:anonymous@heimlich.syspark.com:/var/cvs/atftp It is also possible to grant write access to the CVS repository for people wishing to participate in the development. Please address such requests to either of us. Thanks -- Remi Lefebvre Jean-Pierre Lefebvre README.MCAST000066400000000000000000000034621201445343400126110ustar00rootroot00000000000000Atftp supports multicast transfer. This feature allows the server to send a file to many clients at once. There are two ways of doing multicast TFTP. One is documented in RFC2090 and the other is known as MTFTP and documented in Intel's PXE specification. Atftp supports both protocols. RFC2090 ------- Multicast using RFC2090 is very similar to any other TFTP transfer. The read request sent by the client contains an option to inform the server to use multicast. The server will send configuration information (IP and port) through the option acknowledge mechanism. The initial read request is done at the same port as without multicast (port 69 in most configuration). Data transfer is done at IP and port chosen by the server. When more clients connect to the server, atftpd tries to find a thread currently sending the same file. If it exists, this thread will take care of the new client. If not, a new thread is started for that new client. It is possible to send many different files to many clients when using multicast. Each file transfer uses a unique IP and port. MTFTP ----- The PXE specification uses a completely different (and incompatible with RFC2090) way of doing things. Basically, the TFTP request is sent at a different port than a normal TFTP request. Various options like IP address, port and timeout value are fetched by the client from a DHCP server. Server configuration is done with command line arguments and a configuration file. It is much less flexible than RFC2090 since configuration of the DHCP server must match the configuration of atftpd. See the file mtftp.conf as an example. Most boot ROMs use this method for multicast transfer since it is part of the PXE specification (ftp://download.intel.com/labs/manage/wfm/download/pxespec.pdf). Note: mtftp support starting in atftp 0.7 is experimental. README.PCRE000066400000000000000000000026221201445343400124700ustar00rootroot00000000000000File name mangling with PCRE in atftpd ====================================== Here is an attempt at using PCRE (Perl Compatible Regular Expressions) with a TFTP server. The first question on your mind is most likely "Why in blazes would anyone want to use a regular expression with a TFTP server?" Imagine you have a network of machines that all download an identical config file, but each machine requests its file as .conf where is the serial number of the machine. This set up is useful when you wish each machine to have custom configs. When you which to have identical configurations on each box this is annoying. The solution is to map all requested files ending in .conf to one master.conf file via a regex. The exact expression I use is ^\w*\.conf$ master.conf The left hand side is the expression to match, the right hand side is the substitution. This is equivalent to perls s/// statement. One or more of these expressions can be stored in a file (one per line) and feed to atftpd via a --pcre switch on the command line. For example, ./atftpd --daemon --pcre ./test/pcre_pattern.txt /tftpboot/ Also included is a test program using the --pcre-test option. You can interactively (or via redirection) feed file name to atftpd and look at the substitution to verify your rules. for example, ./atftpd --pcre-test ./test/pcre_pattern.txt Jeff. (jeffm@ghostgun.com) TODO000066400000000000000000000023731201445343400115530ustar00rootroot00000000000000Client ------ Server ------ * Use mmap instead of read/write. This way, we'll benefit from zero copy networking in 2.4.x * number_of_timeout should be per client * Get ICMP error message * add maximum number of client for a multicast server thread. Use new thread to server the file if needed? * It may be necessary to free client structure when client is done to make sure a long lasting multicast server never build up a huge list of done client * Rate control not working yet. Both ---- * revise man pages * add statistics mor mtftp * Verify the whole logging thing * Support IPv6 * Decide what to do when we got memory allocation failure (other than exit) * There is a problem when using block size around 56000 up to 65464. (56944 for Glenn McGrath, 64546 for me on linux 2.4 with Debian unstable). Server send packets (they are fragmented), client machine receive packet but not the application. On an other setup, (linux 2.2.19, Debian 2.2) it work fine up to the maximum of 65464. * When receiving error packet, buffer not beeing initilised with 0 seems to create error. String sended by peer to not have proper 0 termination??? Not confirmed. Generic ------- - Redhat/atftp.spec and test/Makefile are included in make dist and should not. argz.c000066400000000000000000000062031201445343400121660ustar00rootroot00000000000000/* * argz.h * The functions below are "borrowed" from glibc-2.2.3 (argz-next.c). * This has been done to make atftp compile with uclibc, BSD, Solaris * and other platform without glic * * * $Id: argz.c,v 1.1 2003/01/21 01:38:35 jp Exp $ * * Copyright (c) 2000 Jean-Pierre Lefebvre * and Remi Lefebvre * * atftp is free software; you can redistribute them and/or modify them * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * */ #ifndef HAVE_ARGZ /* Routines for dealing with '\0' separated arg vectors. Copyright (C) 1995, 96, 97, 98, 99, 2000 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #include #include "argz.h" char * argz_next (const char *argz, size_t argz_len, const char *entry) { if (entry) { if (entry < argz + argz_len) entry = strchr (entry, '\0') + 1; return entry >= argz + argz_len ? NULL : (char *) entry; } else if (argz_len > 0) return (char *) argz; else return NULL; } error_t argz_create_sep (const char *string, int delim, char **argz, size_t *len) { size_t nlen = strlen (string) + 1; if (nlen > 1) { const char *rp; char *wp; *argz = (char *) malloc (nlen); if (*argz == NULL) return ENOMEM; rp = string; wp = *argz; do if (*rp == delim) { if (wp > *argz && wp[-1] != '\0') *wp++ = '\0'; else --nlen; } else *wp++ = *rp; while (*rp++ != '\0'); if (nlen == 0) { free (*argz); *argz = NULL; *len = 0; } *len = nlen; } else { *argz = NULL; *len = 0; } return 0; } size_t argz_count (const char *argz, size_t len) { size_t count = 0; while (len > 0) { size_t part_len = strlen(argz); argz += part_len + 1; len -= part_len + 1; count++; } return count; } /* Puts pointers to each string in ARGZ, plus a terminating 0 element, into ARGV, which must be large enough to hold them all. */ void argz_extract (const char *argz, size_t len, char **argv) { while (len > 0) { size_t part_len = strlen (argz); *argv++ = (char *) argz; argz += part_len + 1; len -= part_len + 1; } *argv = 0; } #endif argz.h000066400000000000000000000173211201445343400121760ustar00rootroot00000000000000/* * argz.h * Source file borrowed from glibc-2.2.3. This has been done to make * atftp compile with uclibc, BSD, Solaris and other platform without * glic * * $Id: argz.h,v 1.1 2003/01/21 01:38:35 jp Exp $ * * Copyright (c) 2000 Jean-Pierre Lefebvre * and Remi Lefebvre * * atftp is free software; you can redistribute them and/or modify them * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * */ /* Routines for dealing with '\0' separated arg vectors. Copyright (C) 1995, 96, 97, 98, 99, 2000 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #ifndef _ARGZ_H #define _ARGZ_H 1 #include #define __need_error_t #include #include /* Need size_t, and strchr is called below. */ #ifndef __const # define __const const #endif #ifndef __error_t_defined typedef int error_t; #endif __BEGIN_DECLS /* Make a '\0' separated arg vector from a unix argv vector, returning it in ARGZ, and the total length in LEN. If a memory allocation error occurs, ENOMEM is returned, otherwise 0. The result can be destroyed using free. */ extern error_t __argz_create (char *__const __argv[], char **__restrict __argz, size_t *__restrict __len) __THROW; extern error_t argz_create (char *__const __argv[], char **__restrict __argz, size_t *__restrict __len) __THROW; /* Make a '\0' separated arg vector from a SEP separated list in STRING, returning it in ARGZ, and the total length in LEN. If a memory allocation error occurs, ENOMEM is returned, otherwise 0. The result can be destroyed using free. */ extern error_t __argz_create_sep (__const char *__restrict __string, int __sep, char **__restrict __argz, size_t *__restrict __len) __THROW; extern error_t argz_create_sep (__const char *__restrict __string, int __sep, char **__restrict __argz, size_t *__restrict __len) __THROW; /* Returns the number of strings in ARGZ. */ extern size_t __argz_count (__const char *__argz, size_t __len) __THROW __attribute_pure__; extern size_t argz_count (__const char *__argz, size_t __len) __THROW __attribute_pure__; /* Puts pointers to each string in ARGZ into ARGV, which must be large enough to hold them all. */ extern void __argz_extract (__const char *__restrict __argz, size_t __len, char **__restrict __argv) __THROW; extern void argz_extract (__const char *__restrict __argz, size_t __len, char **__restrict __argv) __THROW; /* Make '\0' separated arg vector ARGZ printable by converting all the '\0's except the last into the character SEP. */ extern void __argz_stringify (char *__argz, size_t __len, int __sep) __THROW; extern void argz_stringify (char *__argz, size_t __len, int __sep) __THROW; /* Append BUF, of length BUF_LEN to the argz vector in ARGZ & ARGZ_LEN. */ extern error_t __argz_append (char **__restrict __argz, size_t *__restrict __argz_len, __const char *__restrict __buf, size_t _buf_len) __THROW; extern error_t argz_append (char **__restrict __argz, size_t *__restrict __argz_len, __const char *__restrict __buf, size_t __buf_len) __THROW; /* Append STR to the argz vector in ARGZ & ARGZ_LEN. */ extern error_t __argz_add (char **__restrict __argz, size_t *__restrict __argz_len, __const char *__restrict __str) __THROW; extern error_t argz_add (char **__restrict __argz, size_t *__restrict __argz_len, __const char *__restrict __str) __THROW; /* Append SEP separated list in STRING to the argz vector in ARGZ & ARGZ_LEN. */ extern error_t __argz_add_sep (char **__restrict __argz, size_t *__restrict __argz_len, __const char *__restrict __string, int __delim) __THROW; extern error_t argz_add_sep (char **__restrict __argz, size_t *__restrict __argz_len, __const char *__restrict __string, int __delim) __THROW; /* Delete ENTRY from ARGZ & ARGZ_LEN, if it appears there. */ extern void __argz_delete (char **__restrict __argz, size_t *__restrict __argz_len, char *__restrict __entry) __THROW; extern void argz_delete (char **__restrict __argz, size_t *__restrict __argz_len, char *__restrict __entry) __THROW; /* Insert ENTRY into ARGZ & ARGZ_LEN before BEFORE, which should be an existing entry in ARGZ; if BEFORE is NULL, ENTRY is appended to the end. Since ARGZ's first entry is the same as ARGZ, argz_insert (ARGZ, ARGZ_LEN, ARGZ, ENTRY) will insert ENTRY at the beginning of ARGZ. If BEFORE is not in ARGZ, EINVAL is returned, else if memory can't be allocated for the new ARGZ, ENOMEM is returned, else 0. */ extern error_t __argz_insert (char **__restrict __argz, size_t *__restrict __argz_len, char *__restrict __before, __const char *__restrict __entry) __THROW; extern error_t argz_insert (char **__restrict __argz, size_t *__restrict __argz_len, char *__restrict __before, __const char *__restrict __entry) __THROW; /* Replace any occurrences of the string STR in ARGZ with WITH, reallocating ARGZ as necessary. If REPLACE_COUNT is non-zero, *REPLACE_COUNT will be incremented by number of replacements performed. */ extern error_t __argz_replace (char **__restrict __argz, size_t *__restrict __argz_len, __const char *__restrict __str, __const char *__restrict __with, unsigned int *__restrict __replace_count); extern error_t argz_replace (char **__restrict __argz, size_t *__restrict __argz_len, __const char *__restrict __str, __const char *__restrict __with, unsigned int *__restrict __replace_count); /* Returns the next entry in ARGZ & ARGZ_LEN after ENTRY, or NULL if there are no more. If entry is NULL, then the first entry is returned. This behavior allows two convenient iteration styles: char *entry = 0; while ((entry = argz_next (argz, argz_len, entry))) ...; or char *entry; for (entry = argz; entry; entry = argz_next (argz, argz_len, entry)) ...; */ extern char *__argz_next (__const char *__restrict __argz, size_t __argz_len, __const char *__restrict __entry) __THROW; extern char *argz_next (__const char *__restrict __argz, size_t __argz_len, __const char *__restrict __entry) __THROW; #ifdef __USE_EXTERN_INLINES extern inline char * __argz_next (__const char *__argz, size_t __argz_len, __const char *__entry) { if (__entry) { if (__entry < __argz + __argz_len) __entry = strchr (__entry, '\0') + 1; return __entry >= __argz + __argz_len ? (char *) NULL : (char *) __entry; } else return __argz_len > 0 ? (char *) __argz : 0; } extern inline char * argz_next (__const char *__argz, size_t __argz_len, __const char *__entry) { return __argz_next (__argz, __argz_len, __entry); } #endif /* Use extern inlines. */ __END_DECLS #endif /* argz.h */ atftp.1000066400000000000000000000061461201445343400122650ustar00rootroot00000000000000.\" Hey, EMACS: -*- nroff -*- .TH ATFTP 1 "December 27, 2000" .\" Some roff macros, for reference: .\" .nh disable hyphenation .\" .hy enable hyphenation .\" .ad l left justify .\" .ad b justify to both left and right margins .\" .nf disable filling .\" .fi enable filling .\" .br insert line break .\" .sp insert n+1 empty lines .\" for manpage-specific macros, see man(7) .SH NAME atftp \- TFTP client (RFC1350). .SH SYNOPSIS .B atftp [options] [host [port]] .SH DESCRIPTION .B atftp can be used interactively or in batch mode to retrieve files from TFTP servers. When used interactively, a summary of the commands can be printed by typing 'help'. This TFTP client support all basic features from RFC1350, RFC2347, RFC2348 and RFC2349. It also support multicast implementation of RFC2090 and mtftp as defined in the PXE specification. .SH OPTIONS This program supports both the usual GNU command line syntax, with long options starting with two dashes ('--') as well as short options. Some options are usable in batch mode only, they have no meaning when atftp is use interactively. A description of the options is shown below. .TP .B \-g, \-\-get Non interactive invocation only. Instruct atftp to fetch a file from a tftp server. .TP .B \-\-mget Non interactive invocation only. Used to fetch a file from a mtftp capable server. .TP .B \-p, \-\-put Non interactive invocation only. Instruct atftp to send a file to a tftp server. .TP .B \-P, \-\-password Give password to tftp server. This is a non-standard extension to the atftp client necessary for Linksys routers and shouldn't be used elsewhere. .TP .B \-l, \-\-local-file Non interactive invocation only. The client side (locat) file name to read or write. Must be used in conjunction with \-\-get or \-\-put. .TP .B \-r, \-\-remote-file Non interactive invocation only. The server side (remote) file name to get or put. Must be used in conjunction with \-\-get or \-\-put. .TP .B \-\-tftp-timeout Number of seconds for timeout of the client. Default is 5 seconds. .TP .B \-\-option <"name value"> Set option "name" to "value". This command supports exactly the same arguments as the interactive one. For example, use: --option "blksize 1428" to configure block size. .br Possible Values are: .br --option "tsize enable" --option "tsize disable" --option "blksize 8" --option "blksize 65464" .TP .B \-\-mtftp <"name value"> Set mtftp possible options. Accepts the same options as the interactive mtftp command. For example, use: --mtftp "client-port 76" to configure client side port to use. .TP .B \-\-no\-source\-port\-checking See atftpd's man page. .TP .B \-\-verbose Instruct atftp to be verbose. It will print more information about what's going on. .TP .B \-\-trace This is useful for debugging purpose to display all packet going to and from the network. .TP .B \-V, \-\-version Print version. .TP .B \-h, \-\-help Print a summary of command line arguments. .SH AUTHOR This manual page was written by Remi Lefebvre and Jean-Pierre Lefebvre . atftpd.8000066400000000000000000000212611201445343400124330ustar00rootroot00000000000000.\" Hey, EMACS: -*- nroff -*- .TH ATFTPD 8 "December 27, 2000" .\" Some roff macros, for reference: .\" .nh disable hyphenation .\" .hy enable hyphenation .\" .ad l left justify .\" .ad b justify to both left and right margins .\" .nf disable filling .\" .fi enable filling .\" .br insert line break .\" .sp insert n+1 empty lines .\" for manpage-specific macros, see man(7) .SH NAME atftpd \- Trivial File Transfer Protocol Server. .SH SYNOPSIS .B atftpd .RI [ options ] " directory" .SH DESCRIPTION .B atftpd is a TFTP (RFC1350) server. By default it is started by inetd on most sytems, but may run as a stand alone daemon. This server is multi-threaded and supports all options described in RFC2347 (option extension), RFC2348 (blksize), RFC2349 (tsize and timeout) and RFC2090 (multicast option). It also supports mtftp as defined in the PXE specification. .SH OPTIONS This program supports both the usual GNU command line syntax, with long options starting with two dashes ('-') as well as short options. A description of the options is included below. .TP .B \-t, \-\-tftpd\-timeout Number of seconds of inactivity before the server exits. This value has meaning only when the server is started by inetd. In daemon mode, the server never exits. Default is 300 seconds. .TP .B \-r, \-\-retry\-timeout How many seconds to wait for a reply before retransmitting a packet. Default is 5 seconds. This can be overridden by the TFTP client with the 'timeout' option. .TP .B \-m, \-\-maxthread Maximum number of concurrent threads allowed. Default is 100. .TP .B \-v, \-\-verbose[=value] Increase or set the logging level. No arguments will increase by one the current value. Default is LOG_NOTICE, see syslog(3) for log level. Valid value range from 0 (LOG_EMERG) to 7 (LOG_DEBUG). .TP .B \-\-trace When verbose level is set to 7, this will output debug information for each packet sent or received from the network. .TP .B \-\-no\-timeout disable 'timeout' from RFC2349. This will prevent the server from acknowledging the 'timeout' option requested by the client. .TP .B \-\-no\-tsize disable 'tsize' from RFC2349. This will prevent the server from acknowledging the 'tsize' option requested by the client. .TP .B \-\-no\-blksize disable 'blksize' from RFC2348. This will prevent the server from acknowledging the 'blksize' request by the client. .TP .B \-\-no\-multicast disable 'multicast' from RFC2090. This will prevent the server from acknowledging the 'multicast' request by the client. .TP .B \-\-logfile Log to a specific file instead of only syslog. 'nobody' (or any user used to run the server) must have permissions on the given file. Assuming the file is /var/log/atftpd.log, simply run: "touch /var/log/atftpd.log" and then "chown nobody.nogroup /var/log/atftpd.log". When the server is run in daemon mode, /dev/stdout or /dev/stderr can be used. Specifying a single dash as the filename will send logs to stdout (file descriptor 1). .TP .B \-\-pidfile Write the PID of the server to the specified file. This may be useful when automatically starting and stopping one or more instance of the server. .TP .B \-\-daemon Run as a daemon. Do not use this option if atftpd is started by inetd. .TP .B \-\-no-fork When \-\-daemon is specified, this option will prevent the server from forking to background. It is useful for debugging purpose or specialized usage. .TP .B \-\-user By default, the server change identity to the user nobody and group nogroup. Specify an alternate user.group with this option. .TP .B \-\-group Alternate way of specifying the group. If group is specified with \-\-user and \-\-group, the last option will be used. .TP .B \-\-port Specify the port on which atftpd listens. Useful when \-\-daemon is specified. Default is standard tftp port as determined by \fIgetservbyname\fR\|(3). .TP .B \-\-bind\-address Specify the IP address which atftpd binds to. Useful when \-\-daemon is specified. Default is to bind to all interfaces. Only one address can be specified, the server can only listen to one or all interfaces. .TP .B \-\-mcast\-ttl Specify the TTL to be used for multicast datagram. By default a value of 1 is used. Note that TTL has a special meaning in multicast as it is used to determine the scope of the packets. The value of 1 means the packets don't leave the local network, see ip(4). Scope may also be determine by the address as described RFC2365. .TP .B \-\-mcast\-addr Specify the IP address range to be used for multicast transfer. Format string may comprise range and list of values: "239.255.0.0-31,128-132,200". Default value is "239.255.0.0-255". This address range is proposed in RFC2365 for local scope. .TP .B \-\-mcast\-port Specify the UDP port to use for multicast transfer. Format string may contain range and list of port number: "1758-2000,8000-9000". default value is "1758". .TP .B \-\-pcre Specify a pattern/replacement file to use. This allow to replace requested file name based on Perl Compatible Regular Expression. See README.PCRE. .TP .B \-\-pcre\-test Test a pattern/replacement file. When using this option, the server will not start as usual but just read file name from stdin and printout the substitution. .TP .B \-\-mtftp This will start a mtftp server thread for each valid entry in the supplied file. See PXE specification for detail about mtftp. An example file is provided in the source distribution. .TP .B \-\-mtftp\-port Port the mtftp server shall listen to for incomming request. .TP .B \-\-no\-source\-port\-checking In some specific cases of networks using load balancer or other equipment performing NAT (network address translation), some needs to disable source port checking because port number as been translated. If you want to use this feature, you must know why you need it and the implication. Be aware that this option violate the RFC1350. This option has effect only for non-multicast transfer. .TP .B \-\-mcast\-switch\-client This option allow the server to proceed with the next multicast client as soon as the current client timeout. When the current master client fails to send an acknowledge (ACK) to the server, the server will send an option acknowledge (OACK) to the master client with the field MC (master client) set to false and send an OACK to the next multicast client with MC set to true. Without this option, the server will retry the current master client up to 5 times and then mark it done, proceding with the next one. .TP .B \-V, \-\-version Show version of program. .TP .B \-h, \-\-help Show summary of options. .TP .B path This is the root directory used by the TFTP server. All requested files from a TFTP client must reside in this directory. If not specified, the directory defaults to /tftpboot. Since atftpd run as the nobody user, the permission of the directory must be set properly to allow file reading and writing. .SH STATS Starting with release 0.2, the server collects some statistics. Currently the server compute system load, time between connections and some thread statistics like number of file sent, received, number of abort... To see those stats in the logs, you need to set --verbose=6 (LOG_NOTICE) or higher. .SH SECURITY TFTP by itself has no provision for security. There is no user authentication and TFTP clients get access to all files within the specified root directory for which the server has permission. Some level of security can be gained using atftp libwrap support. Adding proper entry to /etc/hosts.allow and /etc/hosts.deny will restrict access to trusted hosts. Daemon name to use in these files is in.tftpd. .SH PCRE The atftpd server provides a way to dynamically replace requested file name by a new one based on Perl compatible regular expression. Pairs of pattern/replacement are read from the specified files. Upon reception of a read request, the server will first try to open the file name requested. If it fails, then it will search for a replacement based on the content of the pattern file. If this still fails, then an error will be sent to the client. This feature is available only for read request. It makes no sense doing this substitution for client writing files to the server. .SH MTFTP The mtftp name refer to multicasrt tftp as define by the PXE specification. See pxespec.txt for the source of the specification. Note that this is not the same as RFC2090. PXE compliant boot implements mtftp, not RFC2090. .SH SEE ALSO .BR inetd (8), hosts_access (5), libpcre (7), RFC1350, RFC2090, RFC2347, RFC2348, RFC2349 and pxespec.pdf. .SH AUTHOR This manual page was written by Remi Lefebvre and Jean-Pierre Lefebvre . autogen.sh000077500000000000000000000050241201445343400130600ustar00rootroot00000000000000#!/bin/sh AUTOCONF_REQUIRED_VERSION=2.5 AUTOMAKE_REQUIRED_VERSION=1.7 check_version ( ) { if [ "x$1" = "x" ] ; then echo "INTERNAL ERROR: check_version was not provided a minimum version" exit 1 fi _min="$1" if [ "x$2" = "x" ] ; then echo "INTERNAL ERROR: version check was not provided a comparison version" exit 1 fi _cur="$2" # needed to handle versions like 1.10 and 1.4-p6 _min="`echo ${_min}. | sed 's/[^0-9]/./g' | sed 's/\.\././g'`" _cur="`echo ${_cur}. | sed 's/[^0-9]/./g' | sed 's/\.\././g'`" _min_major="`echo $_min | cut -d. -f1`" _min_minor="`echo $_min | cut -d. -f2`" _min_patch="`echo $_min | cut -d. -f3`" _cur_major="`echo $_cur | cut -d. -f1`" _cur_minor="`echo $_cur | cut -d. -f2`" _cur_patch="`echo $_cur | cut -d. -f3`" if [ "x$_min_major" = "x" ] ; then _min_major=0 fi if [ "x$_min_minor" = "x" ] ; then _min_minor=0 fi if [ "x$_min_patch" = "x" ] ; then _min_patch=0 fi if [ "x$_cur_minor" = "x" ] ; then _cur_major=0 fi if [ "x$_cur_minor" = "x" ] ; then _cur_minor=0 fi if [ "x$_cur_patch" = "x" ] ; then _cur_patch=0 fi # $VERBOSE_ECHO "Checking if ${_cur_major}.${_cur_minor}.${_cur_patch} is greater than ${_min_major}.${_min_minor}.${_min_patch}" RESULT=1 if [ $_min_major -lt $_cur_major ] ; then RESULT=0 elif [ $_min_major -eq $_cur_major ] ; then if [ $_min_minor -lt $_cur_minor ] ; then RESULT=0 elif [ $_min_minor -eq $_cur_minor ] ; then if [ $_min_patch -lt $_cur_patch ] ; then RESULT=0 elif [ $_min_patch -eq $_cur_patch ] ; then RESULT=0 fi fi fi if [ $RESULT -eq 1 ] ; then echo "yes (version $1)" else echo "no (version $1)" fi return $RESULT } echo -n "checking for autoconf >= $AUTOCONF_REQUIRED_VERSION ... " if autoconf --version >/dev/null; then VER=$(autoconf --version | grep -iw autoconf | sed "s/.* \([0-9.]*\)[-a-z0-9]*$/\1/") check_version $VER $AUTOCONF_REQUIRED_VERSION else echo "not found" exit 1 fi echo -n "checking for automake >= $AUTOMAKE_REQUIRED_VERSION ... " if automake --version >/dev/null; then VER=$(automake --version | grep -iw automake | sed "s/.* \([0-9.]*\)[-a-z0-9]*$/\1/") check_version $VER $AUTOMAKE_REQUIRED_VERSION else echo "not found" exit 1 fi aclocal autoheader automake --add-missing autoconf config.h.in000066400000000000000000000116211201445343400131020ustar00rootroot00000000000000/* config.h.in. Generated from configure.ac by autoheader. */ /* Define to 1 if you have the header file. */ #undef HAVE_ARGZ_H /* Define to 1 if you have the header file. */ #undef HAVE_ARPA_INET_H /* Define to 1 if you have the header file. */ #undef HAVE_ARPA_TFTP_H /* "Use completion" */ #undef HAVE_COMPLETION_MATCHES /* Define to 1 if you have the `gethostbyaddr' function. */ #undef HAVE_GETHOSTBYADDR /* Define to 1 if you have the `gethostbyname' function. */ #undef HAVE_GETHOSTBYNAME /* Define to 1 if you have the `gethostbyname_r' function. */ #undef HAVE_GETHOSTBYNAME_R /* Define to 1 if you have the header file. */ #undef HAVE_GETOPT_H /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the `memcpy' function. */ #undef HAVE_MEMCPY /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* "Support MTFTP protocol" */ #undef HAVE_MTFTP /* Define to 1 if you have the header file. */ #undef HAVE_NETDB_H /* "Support for libpcre pattern subsitution" */ #undef HAVE_PCRE /* Define to 1 if you have the header file. */ #undef HAVE_PCRE_H /* Define to 1 if you have the header file. */ #undef HAVE_PTHREAD_H /* "Support for readline in tftp client" */ #undef HAVE_READLINE /* Define to 1 if you have the header file. */ #undef HAVE_READLINE_HISTORY_H /* Define to 1 if you have the header file. */ #undef HAVE_READLINE_READLINE_H /* "Use completion" */ #undef HAVE_RL_COMPLETION_MATCHES /* Define to 1 if you have the header file. */ #undef HAVE_SIGNAL_H /* Define to 1 if you have the `socket' function. */ #undef HAVE_SOCKET /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the `strcasecmp' function. */ #undef HAVE_STRCASECMP /* Define to 1 if you have the `strchr' function. */ #undef HAVE_STRCHR /* Define to 1 if you have the `strcmp' function. */ #undef HAVE_STRCMP /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the `strlen' function. */ #undef HAVE_STRLEN /* Define to 1 if you have the `strncasecmp' function. */ #undef HAVE_STRNCASECMP /* Define to 1 if you have the `strncmp' function. */ #undef HAVE_STRNCMP /* Define to 1 if you have the `strncpy' function. */ #undef HAVE_STRNCPY /* Define to 1 if you have the `strstr' function. */ #undef HAVE_STRSTR /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SOCKET_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TIME_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_TCPD_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* "Support for libwrap" */ #undef HAVE_WRAP /* Name of package */ #undef PACKAGE /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define as the return type of signal handlers (`int' or `void'). */ #undef RETSIGTYPE /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Define to 1 if you can safely include both and . */ #undef TIME_WITH_SYS_TIME /* Enable extensions on AIX 3, Interix. */ #ifndef _ALL_SOURCE # undef _ALL_SOURCE #endif /* Enable GNU extensions on systems that have them. */ #ifndef _GNU_SOURCE # undef _GNU_SOURCE #endif /* Enable threading extensions on Solaris. */ #ifndef _POSIX_PTHREAD_SEMANTICS # undef _POSIX_PTHREAD_SEMANTICS #endif /* Enable extensions on HP NonStop. */ #ifndef _TANDEM_SOURCE # undef _TANDEM_SOURCE #endif /* Enable general extensions on Solaris. */ #ifndef __EXTENSIONS__ # undef __EXTENSIONS__ #endif /* Version number of package */ #undef VERSION /* Define to 1 if on MINIX. */ #undef _MINIX /* Define to 2 if the system does not provide POSIX.1 features except with this defined. */ #undef _POSIX_1_SOURCE /* Define to 1 if you need to in order for `stat' and other things to work. */ #undef _POSIX_SOURCE /* Define to empty if `const' does not conform to ANSI C. */ #undef const /* Define to `unsigned int' if does not define. */ #undef size_t configure.ac000066400000000000000000000132541201445343400133510ustar00rootroot00000000000000dnl configure.in dnl dnl $Id: configure.ac,v 1.3 2004/03/16 01:51:40 jp Exp $ dnl dnl Copyright (c) 2001 Jean-Pierre Lefebvre dnl and Remi Lefebvre dnl dnl atftp is free software; you can redistribute them and/or modify them dnl under the terms of the GNU General Public License as published by the dnl Free Software Foundation; either version 2 of the License, or (at your dnl option) any later version. AC_INIT(tftp.c) AM_INIT_AUTOMAKE(atftp, 0.7) AC_SUBST(VERSION) AM_CONFIG_HEADER(config.h) ISODATE=`date +%Y-%m-%d` AC_SUBST(ISODATE) dnl canonicalize the host AC_CANONICAL_HOST dnl AC_CANONICAL_TARGET PLATFORM="${host_vendor}-${host_cpu}-${host_os}" AC_SUBST(PLATFORM) dnl Additional argument AC_ARG_ENABLE(libreadline, [ --enable-libreadline enable readline support in client], [ case "${enableval}" in yes) libreadline=true ;; no) libreadline=false ;; esac], [libreadline=true]) AC_ARG_ENABLE(libwrap, [ --enable-libwrap enable libwrap support in server], [ case "${enableval}" in yes) libwrap=true ;; no) libwrap=false ;; esac], [libwrap=true]) AC_ARG_ENABLE(libpcre, [ --enable-libpcre enable libpcre support in server], [ case "${enableval}" in yes) libpcre=true ;; no) libpcre=false ;; esac], [libpcre=true]) AC_ARG_ENABLE(mtftp, [ --enable-mtftp enable mtftp support in server], [ case "${enableval}" in yes) mtftp=true ;; no) mtftp=false ;; esac], [mtftp=true]) AC_ARG_ENABLE(debug, [ --enable-debug enable debug code in server/client], [ case "${enableval}" in yes) debug=true ;; no) debug=false ;; esac], [debug=false]) dnl Check for programs AC_PROG_CC AC_GNU_SOURCE dnl Check for AIX AC_AIX CFLAGS="-g -Wall -D_REENTRANT" if test x$debug = xtrue; then CFLAGS="$CFLAGS -O0 -DDEBUG" else if test -n "$auto_cflags"; then if test -n "$GCC"; then CFLAGS="$CFLAGS -g -O2 -Wall -Wno-implicit" else case "$host_os" in *hpux*) CFLAGS="$CFLAGS +O3" ;; *ultrix* | *osf*) CFLAGS="$CFLAGS -O -Olimit 2000" ;; *) CFLAGS="$CFLAGS -O2" ;; esac fi else CFLAGS="$CFLAGS -O2" fi fi AC_PROG_MAKE_SET AC_PROG_INSTALL dnl enable mtftp support if test x$mtftp = xtrue; then AC_DEFINE([HAVE_MTFTP], 1, "Support MTFTP protocol") fi dnl Checks for libraries dnl Thread support is needed in the server AC_CHECK_LIB(pthread, pthread_create, [LIBPTHREAD=-lpthread], [AC_MSG_ERROR(not found)]) AC_SUBST(LIBPTHREAD) dnl If we want libreadline support if test x$libreadline = xtrue; then dnl Debian's readline is already linked to ncurses. It is not the case for dnl all other systems. AC_CHECK_LIB(readline, tgetent, LIBTERMCAP="", AC_CHECK_LIB(ncurses, tgetent, LIBTERMCAP=-lncurses, AC_CHECK_LIB(curses, tgetent, LIBTERMCAP=-lcurses, AC_CHECK_LIB(termcap, tgetent, LIBTERMCAP=-ltermcap, AC_MSG_RESULT(no))))) AC_SUBST(LIBTERMCAP) dnl Check for readline AC_CHECK_LIB(readline, readline, [LIBREADLINE=-lreadline] [AC_DEFINE([HAVE_READLINE], 1, "Support for readline in tftp client")], AC_MSG_RESULT(no), $LIBTERMCAP) AC_SUBST(LIBREADLINE) dnl Verify readline has completion support (this function changes from dnl release to release :( AC_CHECK_LIB(readline, rl_completion_matches, AC_DEFINE([HAVE_RL_COMPLETION_MATCHES], 1, "Use completion"), AC_CHECK_LIB(readline, completion_matches, AC_DEFINE([HAVE_COMPLETION_MATCHES], 1, "Use completion"), AC_MSG_RESULT(no), $LIBTERMCAP), $LIBTERMCAP) fi dnl If we want to compile libwrap stuff, check for libraries if test x$libwrap = xtrue; then dnl Checking to libwrap. Some systems don't define default values for dnl allow_severity and deny_severity so we need a somewhat more complicated dnl test here. We automatically link against nsl since libwrap is not dnl already linked with it on all systems. orig_LIBS="$LIBS" LIBS="-lnsl -lwrap" AC_MSG_CHECKING([for hosts_ctl in -lwrap]) AC_TRY_LINK([ #include int allow_severity; int deny_severity; ], hosts_ctl("", STRING_UNKNOWN, STRING_UNKNOWN, STRING_UNKNOWN); , LIBWRAP="-lnsl -lwrap" LIBS="$orig_LIBS" AC_MSG_RESULT(yes) AC_DEFINE([HAVE_WRAP], 1, "Support for libwrap") , LIBWRAP="" LIBS="$orig_LIBS" AC_MSG_RESULT(no) ) AC_SUBST(LIBWRAP) fi dnl If we want to compile pcre stuff, check for libraries if test x$libpcre = xtrue; then dnl Checking to pcre. AC_CHECK_LIB(pcre, pcre_version, [LIBPCRE=-lpcre] [AC_DEFINE([HAVE_PCRE], 1, "Support for libpcre pattern subsitution")]) AC_SUBST(LIBPCRE) fi dnl Checks for header files. AC_HEADER_STDC AC_CHECK_HEADERS(sys/time.h sys/types.h sys/socket.h) AC_CHECK_HEADERS(arpa/inet.h arpa/tftp.h) AC_CHECK_HEADERS(getopt.h unistd.h signal.h pthread.h argz.h) AC_CHECK_HEADERS(netdb.h) AC_CHECK_HEADERS(readline/readline.h) AC_CHECK_HEADERS(readline/history.h) if test x$libwrap = xtrue; then AC_CHECK_HEADERS(tcpd.h) fi if test x$libpcre = xtrue; then AC_CHECK_HEADERS(pcre.h) fi dnl Checks for typedefs, structures, and compiler characteristics. AC_C_CONST AC_TYPE_SIZE_T AC_HEADER_TIME AC_TYPE_SIGNAL dnl Checks for library functions. AC_CHECK_FUNCS(strchr memcpy strstr strcmp strncmp strncpy strlen) AC_CHECK_FUNCS(strncasecmp strcasecmp strncmp) AC_CHECK_FUNCS(socket gethostbyname gethostbyname_r gethostbyaddr) dnl Write platform to file for support reporting AC_OUTPUT_COMMANDS([ outfile=PLATFORM tmpfile=${outfile} cat > $tmpfile << _EOF_ $PLATFORM _EOF_ ], [PLATFORM=$PLATFORM]) AC_OUTPUT(Makefile test/Makefile redhat/atftp.spec) docs/000077500000000000000000000000001201445343400120065ustar00rootroot00000000000000docs/pxespec.txt000066400000000000000000000002761201445343400142230ustar00rootroot00000000000000The PXE specification defined multicast TFTP knowed as MTFTP. This is not the same as RFC2090 and is defined in this document: ftp://download.intel.com/labs/manage/wfm/download/pxespec.pdf logger.c000066400000000000000000000073351201445343400125110ustar00rootroot00000000000000/* hey emacs! -*- Mode: C; c-file-style: "k&r"; indent-tabs-mode: nil -*- */ /* * logger.c * functions for logging messages. * * $Id: logger.c,v 1.12 2004/02/27 02:05:26 jp Exp $ * * Copyright (c) 2000 Jean-Pierre Lefebvre * and Remi Lefebvre * * atftp is free software; you can redistribute them and/or modify them * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include "logger.h" #define MAXLEN 128 static int log_syslog_is_open = 0; static int log_priority = 0; static char *log_filename = NULL; static int log_fd; static FILE *log_fp = NULL; static char *log_ident; /* * Open a file for logging. If filename is NULL, then use * stderr for the client or the syslog for the server. Log * only message less or equal to priority. */ void open_logger(char *ident, char *filename, int priority) { close_logger(); /* make sure we initialise variables and close previously opened log. */ log_priority = priority; if (ident) log_ident = strdup(ident); else log_ident = "unset"; if (filename) { log_filename = strdup(filename); if (!strcmp(filename, "-")) { log_fd = STDOUT_FILENO; log_fp = fdopen(log_fd, "a"); return; } } else { openlog(log_ident, LOG_PID, LOG_DAEMON); log_syslog_is_open = 1; } if (log_filename) { if ((log_fd = open(log_filename, O_WRONLY | O_APPEND)) < 0) { openlog(log_ident, LOG_PID, LOG_DAEMON); log_syslog_is_open = 1; logger(LOG_CRIT, "Unable to open %s for logging, " "reverting to syslog", log_filename); } else log_fp = fdopen(log_fd, "a"); } } /* * Same as syslog but allow to format a string, like printf, when logging to * file. This fonction will either call syslog or fprintf depending of the * previous call to open_logger(). */ void logger(int severity, const char *fmt, ...) { char message[MAXLEN]; char time_buf[MAXLEN]; char hostname[MAXLEN]; time_t t; struct tm *tm; va_list args; va_start(args, fmt); time(&t); tm = localtime(&t); strftime(time_buf, MAXLEN, "%b %d %H:%M:%S", tm); gethostname(hostname, MAXLEN); if (severity <= log_priority) { vsnprintf(message, sizeof(message), fmt, args); if (log_fp) { fprintf(log_fp, "%s %s %s[%d.%li]: %s\n", time_buf, hostname, log_ident, getpid(), pthread_self(), message); fflush(log_fp); } else if (log_syslog_is_open) syslog(severity, "%s", message); else fprintf(stderr, "%s %s %s[%d.%li]: %s\n", time_buf, hostname, log_ident, getpid(), pthread_self(), message); } va_end(args); } /* * Close the file or syslog. Initialise variables. */ void close_logger(void) { log_priority = 0; if (log_syslog_is_open) closelog(); log_syslog_is_open = 0; if (log_fp) fclose(log_fp); log_fp = NULL; if (log_filename) free(log_filename); log_filename = NULL; if (log_ident) free(log_ident); } logger.h000066400000000000000000000013341201445343400125070ustar00rootroot00000000000000/* hey emacs! -*- Mode: C; c-file-style: "k&r"; indent-tabs-mode: nil -*- */ /* * logger.h * * $Id: logger.h,v 1.6 2000/12/27 00:57:16 remi Exp $ * * Copyright (c) 2000 Jean-Pierre Lefebvre * and Remi Lefebvre * * atftp is free software; you can redistribute them and/or modify them * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * */ #ifndef logger_h #define logger_h #include void open_logger(char *ident, char *filename, int priority); void logger(int severity, const char *fmt, ...); void close_logger(void); #endif options.c000066400000000000000000000223041201445343400127160ustar00rootroot00000000000000/* hey emacs! -*- Mode: C; c-file-style: "k&r"; indent-tabs-mode: nil -*- */ /* * options.c * Set of functions to deal with the options structure and for parsing * options in TFTP data buffer. * * $Id: options.c,v 1.16 2003/04/25 00:16:18 jp Exp $ * * Copyright (c) 2000 Jean-Pierre Lefebvre * and Remi Lefebvre * * atftp is free software; you can redistribute them and/or modify them * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * */ #include "config.h" #include #include #include #include #if HAVE_ARGZ #include #else #include "argz.h" #endif #include #include #include "options.h" /* * Fill a structure with the request packet of the client. */ int opt_parse_request(char *data, int data_size, struct tftp_opt *options) { char *entry = NULL; char *tmp; struct tftphdr *tftp_data = (struct tftphdr *)data; size_t size = data_size - sizeof(tftp_data->th_opcode); /* read filename */ entry = argz_next(tftp_data->th_stuff, size, entry); if (!entry) return ERR; else opt_set_options(options, "filename", entry); /* read mode */ entry = argz_next(tftp_data->th_stuff, size, entry); if (!entry) return ERR; else opt_set_options(options, "mode", entry); /* scan for options */ // FIXME: we should use opt_parse_options() here while ((entry = argz_next(tftp_data->th_stuff, size, entry))) { tmp = entry; entry = argz_next(tftp_data->th_stuff, size, entry); if (!entry) return ERR; else opt_set_options(options, tmp, entry); } return OK; } /* * Fill a structure looking only at TFTP options. */ int opt_parse_options(char *data, int data_size, struct tftp_opt *options) { char *entry = NULL; char *tmp; struct tftphdr *tftp_data = (struct tftphdr *)data; size_t size = data_size - sizeof(tftp_data->th_opcode); while ((entry = argz_next(tftp_data->th_stuff, size, entry))) { tmp = entry; entry = argz_next(tftp_data->th_stuff, size, entry); if (!entry) return ERR; else opt_set_options(options, tmp, entry); } return OK; } /* * Set an option by name in the structure. * name is the name of the option as in tftp_def.c. * name is it's new value, that must comply with the rfc's. * When setting an option, it is marked as specified. * */ int opt_set_options(struct tftp_opt *options, char *name, char *value) { int i; for (i = 0; i < OPT_NUMBER; i++) { if (strncasecmp(name, options[i].option, OPT_SIZE) == 0) { options[i].specified = 1; if (value) Strncpy(options[i].value, value, VAL_SIZE); else Strncpy(options[i].value, tftp_default_options[i].value, VAL_SIZE); return OK; } } return ERR; } /* * Return "value" for a given option name in the given option * structure. */ int opt_get_options(struct tftp_opt *options, char *name, char *value) { int i; for (i = 0; i < OPT_NUMBER; i++) { if (strncasecmp(name, options[i].option, OPT_SIZE) == 0) { if (options[i].enabled) Strncpy(value, options[i].value, VAL_SIZE); else return ERR; return OK; } } return ERR; } /* * Disable an option by name. */ int opt_disable_options(struct tftp_opt *options, char *name) { int i; for (i = 2; i < OPT_NUMBER; i++) { if (name == NULL) options[i].specified = 0; else { if (strncasecmp(name, options[i].option, OPT_SIZE) == 0) { options[i].specified = 0; return OK; } } } if (name == NULL) return OK; return ERR; } /* * Return 1 if one or more options are specified in the options structure. */ int opt_support_options(struct tftp_opt *options) { int i; int support = 0; for (i = 2; i < OPT_NUMBER; i++) { if (options[i].specified) support = 1; } return support; } /* * The next few functions deal with TFTP options. Function's name are self * explicative. */ int opt_get_tsize(struct tftp_opt *options) { int tsize; if (options[OPT_TSIZE].enabled && options[OPT_TSIZE].specified) { tsize = atoi(options[OPT_TSIZE].value); return tsize; } return ERR; } int opt_get_timeout(struct tftp_opt *options) { int timeout; if (options[OPT_TIMEOUT].enabled && options[OPT_TIMEOUT].specified) { timeout = atoi(options[OPT_TIMEOUT].value); return timeout; } return ERR; } int opt_get_blksize(struct tftp_opt *options) { int blksize; if (options[OPT_BLKSIZE].enabled && options[OPT_BLKSIZE].specified) { blksize = atoi(options[OPT_BLKSIZE].value); return blksize; } return ERR; } int opt_get_multicast(struct tftp_opt *options, char *addr, int *port, int *mc) { char *token = NULL; char *string = NULL; char *temp = NULL; if (options[OPT_MULTICAST].enabled && options[OPT_MULTICAST].specified) { string = strdup(options[OPT_MULTICAST].value); /* get first argument */ if ((token = strtok_r(string, ",", &temp)) == NULL) { free(string); return ERR; } else Strncpy(addr, token, IPADDRLEN); /* get second argument */ if ((token = strtok_r(NULL, ",", &temp)) == NULL) { free(string); return ERR; } else { *port = atoi(token); if ((*port < 0) || (*port > 65536)) { free(string); return ERR; } } /* get third (last) argument */ if ((token = strtok_r(NULL, ",", &temp)) == NULL) { free(string); return ERR; } else { *mc = atoi(token); if ((*mc != 0) && (*mc != 1)) { free(string); return ERR; } } free(string); return *mc; } return ERR; } void opt_set_tsize(int tsize, struct tftp_opt *options) { snprintf(options[OPT_TSIZE].value, VAL_SIZE, "%d", tsize); } void opt_set_timeout(int timeout, struct tftp_opt *options) { snprintf(options[OPT_TIMEOUT].value, VAL_SIZE, "%d", timeout); } void opt_set_blksize(int blksize, struct tftp_opt *options) { snprintf(options[OPT_BLKSIZE].value, VAL_SIZE, "%d", blksize); } void opt_set_multicast(struct tftp_opt *options, char *addr, int port, int mc) { snprintf(options[OPT_MULTICAST].value, VAL_SIZE, "%s,%d,%d", addr, port, mc); } /* * Format the content of the options structure (this is the content of a * read or write request) to a string. */ void opt_request_to_string(struct tftp_opt *options, char *string, int len) { int i, index = 0; for (i = 0; i < 2; i++) { if ((index + strlen(options[i].option) + 2) < len) { Strncpy(string + index, options[i].option, len - index); index += strlen(options[i].option); Strncpy(string + index, ": ", len - index); index += 2; } if ((index + strlen(options[i].value) + 2) < len) { Strncpy(string + index, options[i].value, len - index); index += strlen(options[i].value); Strncpy(string + index, ", ", len - index); index += 2; } } opt_options_to_string(options, string + index, len - index); } /* * Convert the options structure to a string. */ void opt_options_to_string(struct tftp_opt *options, char *string, int len) { int i, index = 0; for (i = 2; i < OPT_NUMBER; i++) { if (options[i].specified && options[i].enabled) { if ((index + strlen(options[i].option) + 2) < len) { Strncpy(string + index, options[i].option, len - index); index += strlen(options[i].option); Strncpy(string + index, ": ", len - index); index += 2; } if ((index + strlen(options[i].value) + 2) < len) { Strncpy(string + index, options[i].value, len - index); index += strlen(options[i].value); Strncpy(string + index, ", ", len - index); index += 2; } } } if (index > 0) string[index - 2] = 0; else string[0] = 0; } options.h000066400000000000000000000036731201445343400127330ustar00rootroot00000000000000/* hey emacs! -*- Mode: C; c-file-style: "k&r"; indent-tabs-mode: nil -*- */ /* * options.h * * $Id: options.h,v 1.7 2001/07/06 23:35:18 jp Exp $ * * Copyright (c) 2000 Jean-Pierre Lefebvre * and Remi Lefebvre * * atftp is free software; you can redistribute them and/or modify them * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * */ #ifndef options_h #define options_h #include "tftp_def.h" /* Structure definition for tftp options. */ struct tftp_opt { char option[OPT_SIZE]; char value[VAL_SIZE]; int specified; /* specified by the client (for tftp server) */ int enabled; /* enabled for use by server or client */ }; extern struct tftp_opt tftp_default_options[OPT_NUMBER]; int opt_parse_request(char *data, int data_size, struct tftp_opt *options); int opt_parse_options(char *data, int data_size, struct tftp_opt *options); int opt_set_options(struct tftp_opt *options, char *name, char *value); int opt_get_options(struct tftp_opt *options, char *name, char *value); int opt_disable_options(struct tftp_opt *options, char *name); int opt_support_options(struct tftp_opt *options); int opt_get_tsize(struct tftp_opt *options); int opt_get_timeout(struct tftp_opt *options); int opt_get_blksize(struct tftp_opt *options); int opt_get_multicast(struct tftp_opt *options, char *addr, int *port, int *mc); void opt_set_tsize(int tsize, struct tftp_opt *options); void opt_set_timeout(int timeout, struct tftp_opt *options); void opt_set_blksize(int blksize, struct tftp_opt *options); void opt_set_multicast(struct tftp_opt *options, char *addr, int port, int mc); void opt_request_to_string(struct tftp_opt *options, char *string, int len); void opt_options_to_string(struct tftp_opt *options, char *string, int len); #endif redhat/000077500000000000000000000000001201445343400123255ustar00rootroot00000000000000redhat/README000066400000000000000000000005601201445343400132060ustar00rootroot00000000000000The spec file provided in this directory was provided by Allen Reese . For support/requests regarding the rpm packages, please contact him. The rpm packages aren't officially supported by the project and we do not test them. The spec file is provided as a conveniance to redhat users. -- Remi Lefebvre Sat Jul 14 20:34:41 EST 2001 redhat/atftp.spec.in000066400000000000000000000026001201445343400147220ustar00rootroot00000000000000Name: atftp Summary: Advanced Trivial File Transfer Protocol (ATFTP) - TFTP server Group: System Environment/Daemons Version: @VERSION@ Release: 1 Copyright: GPL Vendor: Linux Networx Inc. Source: /usr/src/redhat/SOURCES/atftp-%{version}.tar.gz Buildroot: /var/tmp/atftp-buildroot Packager: Allen Reese %description Multithreaded TFTP server implementing all options (option extension and multicast) as specified in RFC1350, RFC2090, RFC2347, RFC2348 and RFC2349. Atftpd also support multicast protocol knowed as mtftp, defined in the PXE specification. The server supports being started from inetd(8) as well as a deamon using init scripts. %package client Summary: Advanced Trivial File Transfer Protocol (ATFTP) - TFTP client Group: Applications/Internet %description client Advanced Trivial File Transfer Protocol client program for requesting files using the TFTP protocol. %prep %setup %build %configure make %install [ -n "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != '/' ] && rm -rf $RPM_BUILD_ROOT %makeinstall %files %{_mandir}/man8/atftpd.8.gz %{_sbindir}/atftpd %{_mandir}/man8/in.tftpd.8.gz %{_sbindir}/in.tftpd %files client %{_mandir}/man1/atftp.1.gz %{_bindir}/atftp %preun %post %clean [ -n "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != '/' ] && rm -rf $RPM_BUILD_ROOT %changelog * Tue Jan 07 2003 Thayne Harbaugh - put client in sub-rpm stats.c000066400000000000000000000131431201445343400123620ustar00rootroot00000000000000/* hey emacs! -*- Mode: C; c-file-style: "k&r"; indent-tabs-mode: nil -*- */ /* * stats.c * some functions to collect statistics * * $Id: stats.c,v 1.6 2002/03/27 03:02:12 jp Exp $ * * Copyright (c) 2000 Jean-Pierre Lefebvre * and Remi Lefebvre * * atftp is free software; you can redistribute them and/or modify them * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. */ #include "config.h" #include #include #include "tftp_def.h" #include "stats.h" #include "logger.h" /* * That structure allows global statistic to be collected. See stats.h. */ struct server_stats s_stats; /* * Must be called to initilise stats structure and record the * start time. */ void stats_start(void) { /* stats struct initialisation */ memset(&s_stats, 0, sizeof(s_stats)); s_stats.min_time.tv_sec = LONG_MAX; pthread_mutex_init(&s_stats.mutex, NULL); gettimeofday(&s_stats.start_time, NULL); } /* * Called when execution is finnished, before calling stats_print. */ void stats_end(void) { gettimeofday(&s_stats.end_time, NULL); } /* * Called by server threads each time a file is sent succesfully. * Be aware that a mutex is locked in there. */ void stats_send_locked(void) { pthread_mutex_lock(&s_stats.mutex); s_stats.number_of_server++; s_stats.num_file_send++; pthread_mutex_unlock(&s_stats.mutex); } /* * Called by verver threads each time a file is received. */ void stats_recv_locked(void) { pthread_mutex_lock(&s_stats.mutex); s_stats.number_of_server++; s_stats.num_file_recv++; pthread_mutex_unlock(&s_stats.mutex); } /* * Called by server threads each time tftpd_send_file or tftpd_recv_file * return with error. */ void stats_err_locked(void) { pthread_mutex_lock(&s_stats.mutex); s_stats.number_of_err++; pthread_mutex_unlock(&s_stats.mutex); } /* * Called by server threads when the maximum number of threads is reached. */ void stats_abort_locked(void) { pthread_mutex_lock(&s_stats.mutex); s_stats.number_of_abort++; pthread_mutex_unlock(&s_stats.mutex); } /* * Called by main thread only (in fact in tftpd_receive_request(), but * before stdin_mutex is released) every time a new thread is created. * We record the number of thread, the number of simultaeous thread, the * between threads. */ void stats_new_thread(int number_of_thread) { struct timeval tmp; if (number_of_thread > s_stats.max_simul_threads) s_stats.max_simul_threads = number_of_thread; /* calculate the arrival time of this thread */ if (s_stats.prev_time.tv_sec != 0) { gettimeofday(&s_stats.curr_time, NULL); timeval_diff(&s_stats.diff_time, &s_stats.curr_time, &s_stats.prev_time); if (timeval_diff(&tmp, &s_stats.diff_time, &s_stats.min_time) < 0) memcpy(&s_stats.min_time, &s_stats.diff_time, sizeof(struct timeval)); if (timeval_diff(&tmp, &s_stats.diff_time, &s_stats.max_time) > 0) memcpy(&s_stats.max_time, &s_stats.diff_time, sizeof(struct timeval)); memcpy(&s_stats.prev_time, &s_stats.curr_time, sizeof(struct timeval)); } else gettimeofday(&s_stats.prev_time, NULL); } /* * Called by server threads when the finnished to add CPU ressources * information. */ void stats_thread_usage_locked(void) { struct tms tms_tmp; times(&tms_tmp); pthread_mutex_lock(&s_stats.mutex); s_stats.tms_thread.tms_utime += tms_tmp.tms_utime; s_stats.tms_thread.tms_stime += tms_tmp.tms_stime; pthread_mutex_unlock(&s_stats.mutex); } /* * Called at the end of the main thread, when no other threads are * running, to print the final statistics. */ void stats_print(void) { struct timeval tmp; timeval_diff(&tmp, &s_stats.end_time, &s_stats.start_time); times(&s_stats.tms); s_stats.tms.tms_utime += s_stats.tms_thread.tms_utime; s_stats.tms.tms_stime += s_stats.tms_thread.tms_stime; logger(LOG_INFO, " Load measurements:"); logger(LOG_INFO, " User: %8.3fs Sys:%8.3fs", (double)(s_stats.tms.tms_utime) / CLOCKS_PER_SEC, (double)(s_stats.tms.tms_stime) / CLOCKS_PER_SEC); logger(LOG_INFO, " Total:%8.3fs CPU:%8.3f%%", (double)(tmp.tv_sec + tmp.tv_usec * 1e-6), (double)(s_stats.tms.tms_utime + s_stats.tms.tms_stime) / (double)(tmp.tv_sec + tmp.tv_usec * 1e-6)); logger(LOG_INFO, " Time between connections:"); if (s_stats.min_time.tv_sec == LONG_MAX) logger(LOG_INFO, " Min: ----- Max: -----"); else logger(LOG_INFO, " Min: %.3fs Max: %.3fs", (double)(s_stats.min_time.tv_sec + s_stats.min_time.tv_usec * 1e-6), (double)(s_stats.max_time.tv_sec + s_stats.max_time.tv_usec * 1e-6)); logger(LOG_INFO, " Thread stats:"); logger(LOG_INFO, " simultaneous threads: %d", s_stats.max_simul_threads); logger(LOG_INFO, " number of servers: %d", s_stats.number_of_server); logger(LOG_INFO, " number of aborts: %d", s_stats.number_of_abort); logger(LOG_INFO, " number of errors: %d", s_stats.number_of_err); logger(LOG_INFO, " number of files sent: %d", s_stats.num_file_send); logger(LOG_INFO, " number of files received: %d", s_stats.num_file_recv); } stats.h000066400000000000000000000037421201445343400123730ustar00rootroot00000000000000/* hey emacs! -*- Mode: C; c-file-style: "k&r"; indent-tabs-mode: nil -*- */ /* * stats.h * * $Id: stats.h,v 1.3 2000/12/27 17:02:23 jp Exp $ * * Copyright (c) 2000 Jean-Pierre Lefebvre * and Remi Lefebvre * * atftp is free software; you can redistribute them and/or modify them * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * */ #ifndef stats_h #define stats_h #include #include #include /* structure to collect some stats */ struct server_stats { /* updated by main thread */ struct timeval start_time; struct timeval end_time; struct tms tms; /* connection statistics, updated by main thread */ int max_simul_threads; /* maximum number of simultaneous server */ struct timeval min_time; /* time between connection stats */ struct timeval max_time; struct timeval curr_time; /* temporary usage for calculation */ struct timeval prev_time; struct timeval diff_time; /* updated by server thread */ pthread_mutex_t mutex; struct tms tms_thread; int number_of_server; /* number of server that return successfully */ int number_of_abort; /* when number max of client is reached */ int number_of_err; /* send or receive that return with error */ int num_file_send; int num_file_recv; int byte_send; /* total byte transfered to client (file) */ int byte_recv; /* total byte read from client (file) */ }; /* Functions defined in stats.c */ void stats_start(void); void stats_end(void); void stats_send_locked(void); void stats_recv_locked(void); void stats_err_locked(void); void stats_abort_locked(void); void stats_new_thread(int number_of_thread); void stats_thread_usage_locked(void); void stats_print(void); #endif test/000077500000000000000000000000001201445343400120355ustar00rootroot00000000000000test/.gitignore000066400000000000000000000000341201445343400140220ustar00rootroot00000000000000atftpd.log out.bin Makefile test/Makefile.am000066400000000000000000000000401201445343400140630ustar00rootroot00000000000000TESTS = test.sh CLEANFILES = *~ test/load.sh000077500000000000000000000007341201445343400133170ustar00rootroot00000000000000#!/bin/bash if [ $# -lt 1 ]; then echo "Usage: load.sh [host] [port]" exit 1 fi TFTP=../atftp HOST=$1 PORT=$2 FILE=linux CONCURENT=40 TIMEOUT=80 LOOP=1 i=$LOOP while [ $i -gt 0 ]; do echo -n "Loop $i " j=$CONCURENT while [ $j -gt 0 ]; do $TFTP --tftp-timeout 5 --timeout 10 --get -r $FILE -l /dev/null $HOST $PORT 2>$j.out& echo -n "." j=$[ $j - 1 ] done echo " done" i=$[ $i - 1 ] if [ $i -gt 0 ]; then sleep $TIMEOUT fi done test/mtftp.conf000066400000000000000000000001611201445343400140340ustar00rootroot00000000000000# format is: # file_name IP Port linux 239.255.1.1 3001 pxelinux.0 239.255.1.2 3001 test/pcre_pattern.txt000066400000000000000000000004001201445343400152560ustar00rootroot00000000000000^[p]?pxelinux.cfg/[0-9A-F]{1,6}$ pxelinux.cfg/default ^[p]?pxelinux.0$ pxelinux.0 linux linux ^str$ replaced1 ^str replaced2 str$ replaced3 repl(ace) m$1 ^\w*\.conf$ master.conf test/test.sh000077500000000000000000000267021201445343400133620ustar00rootroot00000000000000#!/bin/bash # # This script does some testing with atftp server and client # # # assume we are called in the source tree after the build # so binaries are one dir up ATFTP=../atftp ATFTPD=../atftpd # # set some default values for variables used in this script # if the variables are already set when this script is started # those values are used # : ${HOST:=localhost} : ${PORT:=2001} : ${TEMPDIR:="/tmp"} # Number of parallel clients for high server load test : ${NBSERVER:=200} # Some Tests need root access (e.g. to mount a tempfs filesystem) # and need sudo for this, so maybe the script asks for a password # # if these tests should be performed then start test.sh like this: # WANT_INTERACTIVE_TESTS=yes ./test.sh : ${WANT_INTERACTIVE_TESTS:=no} ##################################################################################### DIRECTORY=$(mktemp -d ${TEMPDIR}/atftp-test.XXXXXX) SERVER_ARGS="--daemon --no-fork --logfile=/dev/stdout --port=$PORT --verbose=6 $DIRECTORY" SERVER_LOG=./atftpd.log ERROR=0 # verify that atftp and atftpd are executable if [ -x "$ATFTP" ]; then echo "Using atftp from build directory" else ATFTP=$(which atftp >/dev/null) if [ -x "$ATFTP" ]; then echo "Using $ATFTP" else echo "atftp binary (client) not found - is the PATH setting correct?" exit 1 fi fi if [ -x $ATFTPD ]; then echo "Using atftpd from build directory" else ATFTPD=$(which atftpd >/dev/null) if [ -x "$ATFTPD" ]; then echo "Using $ATFTPD" else echo "atftpd binary (server) not found - is the PATH setting correct?" exit 1 fi fi function start_server() { # start a server echo -n "Starting atftpd server on port $PORT: " $ATFTPD $SERVER_ARGS > $SERVER_LOG & if [ $? != 0 ]; then echo "Error starting server" exit 1 fi sleep 1 ATFTPD_PID=$! # test if server process exists ps -p $ATFTPD_PID >/dev/null 2>&1 if [ $? != 0 ]; then echo "server process died" exit 1 fi echo "PID $ATFTPD_PID" } function stop_server() { echo "Stopping atftpd server" kill $ATFTPD_PID } function check_file() { if cmp $1 $2 2>/dev/null ; then echo "OK" else echo "ERROR" ERROR=1 fi } function test_get_put() { local READFILE="$1" shift echo -n " get, ${READFILE} ($*)... " if [ "$1" = "--option" ]; then $ATFTP "$1" "$2" --get --remote-file ${READFILE} --local-file out.bin $HOST $PORT 2>/dev/null else $ATFTP --get --remote-file ${READFILE} --local-file out.bin $HOST $PORT 2>/dev/null fi check_file $DIRECTORY/${READFILE} out.bin echo -n " put, ${READFILE} ($*)... " if [ "$1" = "--option" ]; then $ATFTP "$1" "$2" --put --remote-file $WRITE --local-file $DIRECTORY/${READFILE} $HOST $PORT 2>/dev/null else $ATFTP --put --remote-file $WRITE --local-file $DIRECTORY/${READFILE} $HOST $PORT 2>/dev/null fi # wait a second # because in some case the server may not have time to close the file # before the file compare. sleep 1 check_file $DIRECTORY/${READFILE} $DIRECTORY/$WRITE rm -f $DIRECTORY/$WRITE out.bin } function test_blocksize() { echo -n " block size $1 bytes ... " $ATFTP --option "blksize $1" --trace --get -r $READ_128K -l /dev/null $HOST $PORT 2> out if [ $(grep DATA out | wc -l) -eq $(( 128*1024 / $1 + 1)) ]; then echo "OK" else echo "ERROR" ERROR=1 fi } # make sure we have /tftpboot with some files if [ ! -d $DIRECTORY ]; then echo "create $DIRECTORY before running this test" exit 1 fi # files needed READ_0=READ_0.bin READ_511=READ_511.bin READ_512=READ_512.bin READ_2K=READ_2K.bin READ_BIG=READ_BIG.bin READ_128K=READ_128K.bin READ_1M=READ_1M.bin WRITE=write.bin echo -n "Creating test files ... " touch $DIRECTORY/$READ_0 touch $DIRECTORY/$WRITE; chmod a+w $DIRECTORY/$WRITE dd if=/dev/urandom of=$DIRECTORY/$READ_511 bs=1 count=511 2>/dev/null dd if=/dev/urandom of=$DIRECTORY/$READ_512 bs=1 count=512 2>/dev/null dd if=/dev/urandom of=$DIRECTORY/$READ_2K bs=1 count=2048 2>/dev/null dd if=/dev/urandom of=$DIRECTORY/$READ_BIG bs=1 count=51111 2>/dev/null dd if=/dev/urandom of=$DIRECTORY/$READ_128K bs=1K count=128 2>/dev/null dd if=/dev/urandom of=$DIRECTORY/$READ_1M bs=1M count=1 2>/dev/null echo "done" start_server # # test get and put # echo "Testng get and put with standard options" test_get_put $READ_0 test_get_put $READ_511 test_get_put $READ_512 test_get_put $READ_2K test_get_put $READ_BIG test_get_put $READ_128K test_get_put $READ_1M echo echo "Testing get and put with misc blocksizes" test_get_put $READ_BIG --option "blksize 8" test_get_put $READ_BIG --option "blksize 256" test_get_put $READ_1M --option "blksize 1428" test_get_put $READ_1M --option "blksize 1533" test_get_put $READ_1M --option "blksize 16000" test_get_put $READ_1M --option "blksize 40000" test_get_put $READ_1M --option "blksize 65464" # do not run the following test as it will hang... #echo #echo "Testing large file with small blocksize so block numbers will wrap over 65536" #test_get_put $READ_1M --option "blksize 10" # # testing for invalid file name # echo echo -n "Test detection of non-existing file name ... " $ATFTP --trace --get -r "thisfiledoesntexist" -l /dev/null $HOST $PORT 2> out if grep -q "" out; then echo OK else echo ERROR ERROR=1 fi # # testing for invalid blocksize # maximum blocksize is 65464 as described in RCF2348 # echo echo "Testing blksize option ..." echo -n " smaller than minimum ... " $ATFTP --option "blksize 7" --trace --get -r $READ_2K -l /dev/null $HOST $PORT 2> out if grep -q "" out; then echo OK else echo ERROR ERROR=1 fi echo -n " bigger than maximum ... " $ATFTP --option "blksize 65465" --trace --get -r $READ_2K -l /dev/null $HOST $PORT 2> out if grep -q "" out; then echo OK else echo ERROR ERROR=1 fi # # testing for tsize # echo "" echo -n "Testing tsize option... " $ATFTP --option "tsize" --trace --get -r $READ_2K -l /dev/null $HOST $PORT 2> out TSIZE=$(grep "OACK out if grep -q "" out; then echo OK else echo ERROR ERROR=1 fi echo -n " maximum ... " $ATFTP --option "timeout 256" --trace --get -r $READ_2K -l /dev/null $HOST $PORT 2> out if grep -q "" out; then echo OK else echo ERROR ERROR=1 fi # Test the behaviour when the server is not reached # we assume there is no tftp server listening on 127.0.0.77 # Returncode must be 255 echo echo -n "Test returncode after timeout when server is unreachable ... " $ATFTP --put --local-file "$DIRECTORY/$READ_2K" 127.0.0.77 2>out Retval=$? echo -n "Returncode $Retval: " if [ $Retval -eq 255 ]; then echo "OK" else echo "ERROR" ERROR=1 fi # Test behaviour when disk is full # # Preparation: create a small ramdisk # we need the "sudo" command for that if [[ $WANT_INTERACTIVE_TESTS = "yes" ]]; then echo SMALL_FS_DIR="${DIRECTORY}/small_fs" echo "Start disk-out-of-space tests, prepare filesystem in ${SMALL_FS_DIR} ..." mkdir "$SMALL_FS_DIR" if [[ $(id -u) -eq 0 ]]; then Sudo="" else Sudo="sudo" echo "trying to mount ramdisk, the sudo command may ask for a password on the next line!" fi $Sudo mount -t tmpfs shm "$SMALL_FS_DIR" -o size=500k echo "disk space before test: $(LANG=C df -k -P "${SMALL_FS_DIR}" | grep "${SMALL_FS_DIR}" | awk '{print $4}') kiB" echo echo -n "Put 1M file to server: " $ATFTP --put --local-file "$DIRECTORY/$READ_1M" --remote-file "small_fs/fillup.bin" $HOST $PORT Retval=$? sleep 1 echo -n "Returncode $Retval: " if [ $Retval -ne 0 ]; then echo "OK" else echo "ERROR" ERROR=1 fi rm "$DIRECTORY/small_fs/fillup.bin" echo echo -n "Get 1M file from server: " $ATFTP --get --remote-file "$READ_1M" --local-file "$DIRECTORY/small_fs/fillup-put.bin" $HOST $PORT Retval=$? sleep 1 echo -n "Returncode $Retval: " if [ $Retval -ne 0 ]; then echo "OK" else echo "ERROR" ERROR=1 fi $Sudo umount "$SMALL_FS_DIR" rmdir "$SMALL_FS_DIR" else echo echo "Disk-out-of-space tests not performed, start with \"WANT_INTERACTIVE_TESTS=yes ./test.sh\" if desired." fi # Test that timeout is well set to 1 sec and works. # we need atftp compiled with debug support to do that # Restart the server with full logging if $ATFTP --help 2>&1 | grep --quiet -- --delay then stop_server OLD_ARGS="$SERVER_ARGS" SERVER_ARGS="$SERVER_ARGS --verbose=7" start_server $ATFTP --option "timeout 1" --delay 200 --get -r $READ_2K -l /dev/null $HOST $PORT 2> /dev/null & CPID=$! sleep 1 kill -s STOP $CPID echo -n "Testing timeout " for i in $(seq 6); do sleep 1 echo -n "." done kill $CPID stop_server sleep 1 grep "timeout: retrying..." $SERVER_LOG | cut -d " " -f 3 > out count=$(wc -l out | cut -d "o" -f1) if [ $count != 5 ]; then ERROR=1 echo "ERROR" else prev=0 res="OK" while read line; do hrs=$(echo $line | cut -d ":" -f 1) min=$(echo $line | cut -d ":" -f 2) sec=$(echo $line | cut -d ":" -f 3) cur=$(( 24*60*10#$hrs + 60*10#$min + 10#$sec )) if [ $prev -gt 0 ]; then if [ $(($cur - $prev)) != 1 ]; then res="ERROR" ERROR=1 fi fi prev=$cur done < out echo " $res" fi SERVER_ARGS="$OLD_ARGS" start_server else echo echo "Detailed timeout test could not be done" echo "Compile atftp with debug support for more timeout testing" fi # # testing PCRE # # # testing multicast # #echo "" #echo -n "Testing multicast option " #for i in $(seq 10); do # echo -n "." # atftp --blksize=8 --multicast -d --get -r $READ_BIG -l out.$i.bin $HOST $PORT 2> /dev/null& #done #echo "OK" # # testing mtftp # # # Test for high server load # echo echo "Testing high server load" echo -n " starting $NBSERVER simultaneous atftp get processes ... " #( for i in $(seq 1 $NBSERVER); do # ($ATFTP --get --remote-file $READ_1M --local-file /dev/null $HOST $PORT 2> out.$i) & # echo -n "+" #done ) for i in $(seq 1 $NBSERVER) do $ATFTP --get --remote-file $READ_1M --local-file /dev/null $HOST $PORT 2> out.$i & done echo "done" let CHECKCOUNTER=0 let MAXCHECKS=30 while [[ $CHECKCOUNTER -lt $MAXCHECKS ]]; do PIDCOUNT=$(pidof $ATFTP|wc -w) if [ $PIDCOUNT -gt 0 ]; then echo " wait for atftp processes to complete: $PIDCOUNT running" let CHECKCOUNTER+=1 sleep 1 else let CHECKCOUNTER=$MAXCHECKS+1 fi done error=0; for i in $(seq 1 $NBSERVER); do if grep -q "timeout: retrying..." out.$i; then error=1; else rm out.$i fi done if [ "$error" -eq "1" ]; then echo ERROR; ERROR=1 else echo OK fi stop_server echo # cleanup if [ "$1" == "--nocleanup" ]; then echo "No Cleanup, keep files from test in $DIRECTORY" else echo "Cleanup test files" rm -f out rm -f $SERVER_LOG $DIRECTORY/$READ_0 $DIRECTORY/$READ_511 $DIRECTORY/$READ_512 rm -f $DIRECTORY/$READ_2K $DIRECTORY/$READ_BIG $DIRECTORY/$READ_128K $DIRECTORY/$READ_1M rm -f $DIRECTORY/$WRITE rmdir $DIRECTORY fi echo -n "Overall Test status: " # Exit with proper error status if [ $ERROR -eq 1 ]; then echo "Errors have occurred" exit 1 else echo "OK" exit 0 fi # vim: ts=4:sw=4:autoindent test/test_suite.txt000066400000000000000000000001021201445343400147570ustar00rootroot000000000000001) test get, put 2) test blksize 3) test tsize 4) test timeout 5) tftp.c000066400000000000000000001057771201445343400122200ustar00rootroot00000000000000/* hey emacs! -*- Mode: C; c-file-style: "k&r"; indent-tabs-mode: nil -*- */ /* * tftp.c * main client file. * * $Id: tftp.c,v 1.47 2004/03/15 23:55:56 jp Exp $ * * Copyright (c) 2000 Jean-Pierre Lefebvre * and Remi Lefebvre * * atftp is free software; you can redistribute them and/or modify them * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #if HAVE_READLINE #include #include #endif #if HAVE_ARGZ #include #else #include "argz.h" #endif #include "tftp.h" #include "tftp_io.h" #include "tftp_def.h" #include "logger.h" #include "options.h" /* Maximum number of args on a line. 20 should be more than enough. */ #define MAXARG 20 /* for readline */ #define HISTORY_FILE ".atftp_history" /* defined as extern in tftp_file.c and mtftp_file.c, set by the signal handler */ int tftp_cancel = 0; /* local flags */ int interactive = 1; /* if false, we run in batch mode */ int tftp_result = OK; /* status of tftp_send_file or tftp_receive_file, used for status() */ /* Structure to hold some information that must be passed to * functions. */ struct client_data data; /* tftp.c local only functions. */ static void signal_handler(int signal); int read_cmd(void); #if HAVE_READLINE # if (HAVE_RL_COMPLETION_MATCHES | HAVE_COMPLETION_MATCHES) int getc_func(FILE *fp); char **completion(const char *text, int start, int end); char *command_generator(const char *text, int state); # endif #endif void make_arg(char *string, int *argc, char ***argv); int process_cmd(int argc, char **argv); int tftp_cmd_line_options(int argc, char **argv); void tftp_usage(void); /* Functions associated with the tftp commands. */ int set_peer(int argc, char **argv); int set_mode(int argc, char **argv); int set_option(int argc, char **argv); int put_file(int argc, char **argv); int get_file(int argc, char **argv); #ifdef HAVE_MTFTP int mtftp_opt(int argc, char **argv); #endif int quit(int argc, char **argv); int set_verbose(int argc, char **argv); int set_trace(int argc, char **argv); int status(int argc, char **argv); int set_timeout(int argc, char **argv); int help(int argc, char **argv); /* All supported commands. */ struct command { const char *name; int (*func)(int argc, char **argv); const char *helpmsg; } cmdtab[] = { {"connect", set_peer, "connect to tftp server"}, {"mode", set_mode, "set file transfer mode (netascii/octet)"}, {"option", set_option, "set RFC1350 options"}, {"put", put_file, "upload a file to the host"}, {"get", get_file, "download a file from the host"}, #ifdef HAVE_MTFTP {"mtftp", mtftp_opt, "set mtftp variables"}, {"mget", get_file, "download file from mtftp server"}, #endif {"quit", quit, "exit tftp"}, {"verbose", set_verbose, "toggle verbose mode"}, {"trace", set_trace, "toggle trace mode"}, {"status", status, "print status information"}, {"timeout", set_timeout, "set the timeout before a retry"}, {"help", help, "print help message"}, {"?", help, "print help message"}, {NULL, NULL, NULL} }; /* * Open the socket, register signal handler and * pass the control to read_cmd. */ int main(int argc, char **argv) { /* Allocate memory for data buffer. */ if ((data.data_buffer = malloc((size_t)SEGSIZE+4)) == NULL) { fprintf(stderr, "tftp: memory allcoation failed.\n"); exit(ERR); } data.data_buffer_size = SEGSIZE + 4; /* Allocate memory for tftp option structure. */ if ((data.tftp_options = malloc(sizeof(tftp_default_options))) == NULL) { fprintf(stderr, "tftp: memory allocation failed.\n"); exit(ERR); } /* Copy default options. */ memcpy(data.tftp_options, tftp_default_options, sizeof(tftp_default_options)); /* Allocate memory for tftp option reply from server. */ if ((data.tftp_options_reply = malloc(sizeof(tftp_default_options))) == NULL) { fprintf(stderr, "tftp: memory allocation failed.\n"); exit(ERR); } /* Copy default options. */ memcpy(data.tftp_options_reply, tftp_default_options, sizeof(tftp_default_options)); /* default options */ #ifdef HAVE_MTFTP data.mtftp_client_port = 76; Strncpy(data.mtftp_mcast_ip, "0.0.0.0", MAXLEN); data.mtftp_listen_delay = 2; data.mtftp_timeout_delay = 2; #endif data.timeout = TIMEOUT; data.checkport = 1; data.trace = 0; data.verbose = 0; #ifdef DEBUG data.delay = 0; #endif /* register SIGINT -> C-c */ signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); /* parse options, and maybe run in non interractive mode */ tftp_cmd_line_options(argc, argv); if (interactive) return read_cmd(); return OK; } /* * When we receive a signal, we set tftp_cancel in order to * abort ongoing transfer. */ void signal_handler(int signal) { /* * if receiving or sending files, we should abort * and send and error ACK */ tftp_cancel = 1; } /* * Read commands with a nice prompt and history (if compile with * libreadline. Otherway we only get the basic. */ int read_cmd(void) { int run = 1; #if HAVE_READLINE char *string = NULL; #else char string[MAXLEN]; #endif int argc; char **argv = NULL; #if HAVE_READLINE char history[MAXLEN]; if (getenv("HOME") != NULL) snprintf(history, sizeof(history), "%s/%s", getenv("HOME"), HISTORY_FILE); else snprintf(history, sizeof(history), "%s", HISTORY_FILE); # if (HAVE_RL_COMPLETION_MATCHES | HAVE_COMPLETION_MATCHES) rl_attempted_completion_function = completion; rl_getc_function = getc_func; # endif #endif #if HAVE_READLINE using_history(); read_history(history); #endif while (run) { #if HAVE_READLINE if ((string = readline("tftp> ")) == NULL) { fprintf(stderr, "\n"); break; } #else fprintf(stderr, "tftp> "); if (fgets(string, MAXLEN, stdin) == NULL) { fprintf(stderr, "\n"); break; } #endif else { #ifndef HAVE_READLINE string[strlen(string)-1] = 0; #endif if (strlen(string) != 0) { make_arg(string, &argc, &argv); if (argc > 0) { #if HAVE_READLINE add_history(string); #endif if (process_cmd(argc, argv) == QUIT) run = 0; } #if HAVE_READLINE free(string); #endif } } } #if HAVE_READLINE /* save history */ write_history(history); #endif return 0; } #if HAVE_READLINE # if (HAVE_RL_COMPLETION_MATCHES | HAVE_COMPLETION_MATCHES) int getc_func(FILE *fp) { fd_set rfds; FD_ZERO(&rfds); FD_SET(fileno(fp), &rfds); if (select(FD_SETSIZE, &rfds, NULL, NULL, NULL) < 0) { rl_kill_full_line(0,0); return '\n'; } return rl_getc(fp); } char **completion(const char *text, int start, int end) { char **matches; matches = (char **)NULL; /* If this word is at the start of the line, then it is a command to complete. Otherwise it is the name of a file in the current directory. */ if (start == 0) #if HAVE_RL_COMPLETION_MATCHES matches = rl_completion_matches(text, command_generator); #endif #if HAVE_COMPLETION_MATCHES matches = completion_matches(text, command_generator); #endif return (matches); } /* Generator function for command completion. STATE lets us know whether to start from scratch; without any state (i.e. STATE == 0), then we start at the top of the list. */ char *command_generator(const char *text, int state) { static int list_index, len; char *name; /* If this is a new word to complete, initialize now. This includes saving the length of TEXT for efficiency, and initializing the index variable to 0. */ if (!state) { list_index = 0; len = strlen (text); } /* Return the next name which partially matches from the command list. */ while ((name = (char *)cmdtab[list_index].name)) { list_index++; if (strncmp (name, text, len) == 0) return strdup(name); } /* If no names matched, then return NULL. */ return NULL; } # endif #endif /* * set argc/argv from variadic string arguments */ void make_arg_vector(int *argc, char***argv, ...) { char **p; char *s; va_list argp; // how many args? *argc = 0; va_start(argp, argv); while ( (s=va_arg(argp, char*)) ) ++*argc; // allocate storage *argv = malloc(*argc * sizeof (char*)); // store args p = *argv; va_start(argp, argv); while ( (s=va_arg(argp, char*)) ) *p++ = s; } /* * Split a string into args. */ void make_arg(char *string, int *argc, char ***argv) { static char *tmp = NULL; size_t argz_len; /* split the string to an argz vector */ if (argz_create_sep(string, ' ', &tmp, &argz_len) != 0) { *argc = 0; return; } /* retreive the number of arguments */ *argc = argz_count(tmp, argz_len); /* give enough space for all arguments to **argv */ if ((*argv = realloc(*argv, (*argc + 1) * sizeof(char *))) == NULL) { *argc = 0; return; } /* extract arguments */ argz_extract(tmp, argz_len, *argv); /* if the last argument is an empty string ... it happens when some extra space are added at the end of string :( */ if (strlen((*argv)[*argc - 1]) == 0) *argc = *argc - 1; } /* * Once a line have been read and splitted, find the corresponding * function and call it. */ int process_cmd(int argc, char **argv) { int i = 0; /* find the command in the command table */ while (1) { if (cmdtab[i].name == NULL) { fprintf(stderr, "tftp: bad command name.\n"); return 0; } if (strcasecmp(cmdtab[i].name, argv[0]) == 0) { return (cmdtab[i].func)(argc, argv); } i++; } } /* * Update sa_peer structure, hostname and port number adequately */ int set_peer(int argc, char **argv) { struct addrinfo hints, *addrinfo; int err; /* sanity check */ if ((argc < 2) || (argc > 3)) { fprintf(stderr, "Usage: %s host-name [port]\n", argv[0]); return ERR; } /* look up the service and host */ memset(&hints, 0, sizeof(hints)); hints.ai_socktype = SOCK_DGRAM; hints.ai_flags = AI_CANONNAME; err = getaddrinfo(argv[1], argc == 3 ? argv[2] : "tftp", &hints, &addrinfo); /* if valid, update s_inn structure */ if (err == 0) err = sockaddr_set_addrinfo(&data.sa_peer, addrinfo); if (err == 0) { Strncpy(data.hostname, addrinfo->ai_canonname, sizeof(data.hostname)); data.hostname[sizeof(data.hostname)-1] = 0; freeaddrinfo(addrinfo); } else { if (err == EAI_SERVICE) { if (argc == 3) fprintf(stderr, "%s: bad port number.\n", argv[2]); else fprintf(stderr, "tftp: udp/tftp, unknown service.\n"); } else { fprintf(stderr, "tftp: unknown host %s.\n", argv[1]); } data.connected = 0; return ERR; } /* copy port number to data structure */ data.port = sockaddr_get_port(&data.sa_peer); data.connected = 1; return OK; } /* * Set the mode to netascii or octet */ int set_mode(int argc, char **argv) { if (argc > 2) { fprintf(stderr, "Usage: %s [netascii] [octet]\n", argv[0]); return ERR; } if (argc == 1) { fprintf(stderr, "Current mode is %s.\n", data.tftp_options[OPT_MODE].value); return OK; } if (strcasecmp("netascii", argv[1]) == 0) Strncpy(data.tftp_options[OPT_MODE].value, "netascii", VAL_SIZE); else if (strcasecmp("octet", argv[1]) == 0) Strncpy(data.tftp_options[OPT_MODE].value, "octet", VAL_SIZE); else { fprintf(stderr, "tftp: unkowned mode %s.\n", argv[1]); fprintf(stderr, "Usage: %s [netascii] [octet]\n", argv[0]); return ERR; } return OK; } /* * Set an option */ int set_option(int argc, char **argv) { char value[VAL_SIZE]; /* if there are no arguments */ if ((argc < 2) || (argc > 3)) { fprintf(stderr, "Usage: option