From: Vaibhav Bajpai Date: Sun, 5 May 2013 17:23:14 +0000 (+0200) Subject: added file locking capability if --csv results are written to file X-Git-Tag: v0.85~5 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=562551b4d3aafc8e2fc65538384ec34a0f477307;p=thirdparty%2Fmtr.git added file locking capability if --csv results are written to file --- diff --git a/mtr.c b/mtr.c index 7675265..75a3b06 100644 --- a/mtr.c +++ b/mtr.c @@ -30,7 +30,9 @@ #include #include #include - +#include +#include +#include #include "mtr.h" #include "mtr-curses.h" @@ -174,6 +176,64 @@ read_from_file(const char* progname, const char *filename) { if (in != stdin) fclose(in); } +/* + * If the file stream is associated with a regular file, lock the file + * in order coordinate writes to a common file from multiple mtr + * instances. This is useful if, for example, multiple mtr instances + * try to append results to a common file. + */ + +static void +lock(const char* progname, FILE *f) { + int fd; + struct stat buf; + static struct flock lock; + + assert(f); + + lock.l_type = F_WRLCK; + lock.l_start = 0; + lock.l_whence = SEEK_END; + lock.l_len = 0; + lock.l_pid = getpid(); + + fd = fileno(f); + if ((fstat(fd, &buf) == 0) && S_ISREG(buf.st_mode)) { + if (fcntl(fd, F_SETLKW, &lock) == -1) { + fprintf(stderr, "%s: fcntl: %s (ignored)\n", + progname, strerror(errno)); + } + } +} + +/* + * If the file stream is associated with a regular file, unlock the + * file (which presumably has previously been locked). + */ + +static void +unlock(const char* progname, FILE *f) { + int fd; + struct stat buf; + static struct flock lock; + + assert(f); + + lock.l_type = F_UNLCK; + lock.l_start = 0; + lock.l_whence = SEEK_END; + lock.l_len = 0; + lock.l_pid = getpid(); + + fd = fileno(f); + if ((fstat(fd, &buf) == 0) && S_ISREG(buf.st_mode)) { + if (fcntl(fd, F_SETLKW, &lock) == -1) { + fprintf(stderr, "%s: fcntl: %s (ignored)\n", + progname, strerror(errno)); + } + } +} + void init_fld_options (void) { @@ -615,14 +675,16 @@ int main(int argc, char **argv) } } - display_open(); - dns_open(); + lock(argv[0], stdout); + display_open(); + dns_open(); - display_mode = 0; - display_loop(); + display_mode = 0; + display_loop(); - net_end_transit(); - display_close(now); + net_end_transit(); + display_close(now); + unlock(argv[0], stdout); if ( DisplayMode != DisplayCSV ) break; else names = names->next;