summary refs log tree commit diff
path: root/fq.c
blob: 7f6f5fd34fd9ca1f422a522b66d2b3f5cf47b3e6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/*
 * fq [FILES...] - follow output of nq jobs, quitting when they are done
 *
 * To the extent possible under law,
 * Christian Neukirchen <chneukirchen@gmail.com>
 * has waived all copyright and related or neighboring rights to this work.
 * http://creativecommons.org/publicdomain/zero/1.0/
 */

#include <sys/file.h>
#include <sys/stat.h>
#include <sys/types.h>

#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define DELAY 250000

#ifdef __linux__
#define USE_INOTIFY
#endif

#ifdef USE_INOTIFY
#include <sys/inotify.h>
char ibuf[8192];
#endif

char buf[8192];

int
islocked(int fd)
{
	if (flock(fd, LOCK_EX|LOCK_NB) == -1) {
		return (errno == EWOULDBLOCK);
	} else {
		flock(fd, LOCK_UN);
		return 0;
	}
}

int
main(int argc, char *argv[])
{
	int i, fd;
	off_t off, loff;
	ssize_t rd;
	int didsth = 0;

#ifdef USE_INOTIFY
	int ifd, wd;
#endif

	close(0);

	if (argc < 2) {
		/* little better than glob(3)... */
		execl("/bin/sh", "sh", "-c", "fq ${NQDIR:+$NQDIR/},*", (char *) 0);
		exit(111);
	}

#ifdef USE_INOTIFY
	ifd = inotify_init();
	if (ifd < 0)
		exit(111);
#endif

	for (i = 1; i < argc; i++) {
		loff = 0;

		fd = open(argv[i], O_RDONLY);
		if (fd < 0)
			continue;

		/* skip not running jobs, unless we did not output anything yet
		 * and are at the last argument.  */
		if (!islocked(fd) && (didsth || i != argc - 1))
			continue;

		write(1, "==> ", 4);
		write(1, argv[i], strlen(argv[i]));
		write(1, "\n", 1);

		didsth = 1;

#ifdef USE_INOTIFY
		wd = inotify_add_watch(ifd, argv[i], IN_MODIFY|IN_CLOSE_WRITE);
#endif

		while (1) {
			off = lseek(fd, 0, SEEK_END);

			if (off < loff)
				loff = off;               /* file truncated */

			if (off == loff) {
				if (flock(fd, LOCK_EX|LOCK_NB) == -1 &&
				    errno == EWOULDBLOCK) {
#ifdef USE_INOTIFY
					/* any inotify event is good */
					read(ifd, ibuf, sizeof ibuf);
#else
					/* poll for size change */
					while (off == lseek(fd, 0, SEEK_END))
						usleep(DELAY);
#endif
					continue;
				} else {
					flock(fd, LOCK_UN);
					break;
				}
			}

			if (off - loff > sizeof buf)
				off = loff + sizeof buf;

			rd = pread(fd, &buf, off - loff, loff);
			write(1, buf, rd);

			loff += rd;
		}

#ifdef USE_INOTIFY
		inotify_rm_watch(ifd, wd);
#endif
		close(fd);
	}

#ifdef USE_INOTIFY
	close(ifd);
#endif
	return 0;
}