? tftpd ? tftpd.8.gz Index: Makefile =================================================================== RCS file: /home/ncvs/src/libexec/tftpd/Makefile,v retrieving revision 1.9 diff -u -r1.9 Makefile --- Makefile 26 Mar 2001 14:22:11 -0000 1.9 +++ Makefile 22 Nov 2007 23:46:23 -0000 @@ -8,5 +8,6 @@ MAN= tftpd.8 CFLAGS+=-I${.CURDIR}/../../usr.bin/tftp .PATH: ${.CURDIR}/../../usr.bin/tftp +WFORMAT=0 .include Index: tftpd.8 =================================================================== RCS file: /home/ncvs/src/libexec/tftpd/tftpd.8,v retrieving revision 1.21 diff -u -r1.21 tftpd.8 --- tftpd.8 3 Jun 2007 15:32:06 -0000 1.21 +++ tftpd.8 22 Nov 2007 23:46:23 -0000 @@ -40,7 +40,8 @@ .Nd Internet Trivial File Transfer Protocol server .Sh SYNOPSIS .Nm tftpd -.Op Fl cClnw +.Op Fl cClnwW +.Op Fl F Ar strftime-format .Op Fl s Ar directory .Op Fl u Ar user .Op Fl U Ar umask @@ -142,6 +143,13 @@ specified via .Fl s if a directory does not exist for the client's IP. +.It Fl F +Use this +.Xr strftime 3 +compatible format string for the creation of the suffix if +.Fl W +is specified. +By default the string "%Y%m%d" is used. .It Fl l Log all requests using .Xr syslog 3 @@ -184,6 +192,17 @@ By default .Nm requires that the file specified in a write request exist. +Note that this only works in directories writable by the user +specified with +.Fl u +option +.It Fl W +As +.Fl w +but append a YYYYMMDD.nn sequence number to the end of the filename. +Note that the string YYYYMMDD can be changed the +.Fl F +option. .El .Sh SEE ALSO .Xr tftp 1 , @@ -212,10 +231,17 @@ .Fl u option was introduced in .Fx 4.2 , -and the +the .Fl c option was introduced in -.Fx 4.3 . +.Fx 4.3 , +and the +.Fl F +and +.Fl W +options were introduced in +.Fx 7 . +.Pp .Sh BUGS Files larger than 33488896 octets (65535 blocks) cannot be transferred without client and server supporting blocksize negotiation (RFC1783). Index: tftpd.c =================================================================== RCS file: /home/ncvs/src/libexec/tftpd/tftpd.c,v retrieving revision 1.37 diff -u -r1.37 tftpd.c --- tftpd.c 31 May 2005 17:22:53 -0000 1.37 +++ tftpd.c 22 Nov 2007 23:46:23 -0000 @@ -110,6 +110,8 @@ static int logging; static int ipchroot; static int create_new = 0; +static char *newfile_format = "%Y%m%d"; +static int increase_name = 0; static mode_t mask = S_IWGRP|S_IWOTH; static const char *errtomsg(int); @@ -134,7 +136,7 @@ tzset(); /* syslog in localtime */ openlog("tftpd", LOG_PID | LOG_NDELAY, LOG_FTP); - while ((ch = getopt(argc, argv, "cClns:u:U:w")) != -1) { + while ((ch = getopt(argc, argv, "cCF:lns:u:U:wW")) != -1) { switch (ch) { case 'c': ipchroot = 1; @@ -142,6 +144,9 @@ case 'C': ipchroot = 2; break; + case 'F': + newfile_format = optarg; + break; case 'l': logging = 1; break; @@ -160,6 +165,10 @@ case 'w': create_new = 1; break; + case 'W': + create_new = 1; + increase_name = 1; + break; default: syslog(LOG_WARNING, "ignoring unknown option -%c", ch); } @@ -513,6 +522,57 @@ FILE *file; /* + * Find the next value for YYYYMMDD.nn when the file to be written should + * be unique. Due to the limitations of nn, we will fail if nn reaches 100. + * Besides, that is four updates per hour on a file, which is kind of + * execessive anyway. + */ +static int +find_next_name(char *filename, int *fd) +{ + int i; + time_t tval; + size_t len; + struct tm lt; + char yyyymmdd[MAXPATHLEN]; + char newname[MAXPATHLEN]; + struct stat sb; + int ret; + + /* Create the YYYYMMDD part of the filename */ + time(&tval); + lt = *localtime(&tval); + len = strftime(yyyymmdd, sizeof(yyyymmdd), newfile_format, <); + if (len == 0) { + syslog(LOG_WARNING, + "Filename suffix too long (%d characters maximum)", + MAXPATHLEN); + return (EACCESS); + } + + /* Make sure the new filename is not too long */ + if (strlen(filename) > MAXPATHLEN - len - 5) { + syslog(LOG_WARNING, + "Filename too long (%d characters, %d maximum)", + strlen(filename), MAXPATHLEN - len - 5); + return (EACCESS); + } + + /* Find the first file which doesn't exist */ + for (i = 0; i < 100; i++) { + sprintf(newname, "%s.%s.%02d", filename, yyyymmdd, i); + *fd = open(newname, + O_WRONLY | O_CREAT | O_EXCL, + S_IRUSR | S_IWUSR | S_IRGRP | + S_IWGRP | S_IROTH | S_IWOTH); + if (*fd > 0) + return 0; + } + + return (EEXIST); +} + +/* * Validate file access. Since we * have no uid or gid, for now require * file to exist and be publicly @@ -528,6 +588,7 @@ { struct stat stbuf; int fd; + int error; struct dirlist *dirp; static char pathname[MAXPATHLEN]; char *filename = *filep; @@ -610,10 +671,18 @@ if (mode == RRQ) fd = open(filename, O_RDONLY); else { - if (create_new) - fd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, 0666); - else - fd = open(filename, O_WRONLY|O_TRUNC); + if (create_new) { + if (increase_name) { + error = find_next_name(filename, &fd); + if (error > 0) + return (error + 100); + } else + fd = open(filename, + O_WRONLY | O_TRUNC | O_CREAT, + S_IRUSR | S_IWUSR | S_IRGRP | + S_IWGRP | S_IROTH | S_IWOTH ); + } else + fd = open(filename, O_WRONLY | O_TRUNC); } if (fd < 0) return (errno + 100);