1 #define _POSIX_C_SOURCE 199309L
14 const int BUF_SIZE
= 1024;
16 const char PROMPT
[] = "\33[H" /* Move cursor 'home' */
17 "\33[J" /* Clear screen */
19 const char ACKNOWLEDGE
[] = "[OK]";
20 const char WAITING
[] = "[Waiting on lock...]\n";
21 const struct timespec ACKNOWLEDGE_DELAY
= {0, 300000000};
29 conf_t
parse_command_line(int argc
, char *argv
[]) {
35 for (int i
= 1; i
< argc
; i
++) {
36 if (strcmp(argv
[i
], "-i") == 0 && isatty(2))
38 if (strcmp(argv
[i
], "--no-fnctl-lock") == 0)
40 if (strcmp(argv
[i
], "--no-flock-lock") == 0)
47 static void read_line(conf_t
*conf
, char *buf
) {
48 if (conf
->interactive
)
49 if (fputs(PROMPT
, stderr
) == EOF
)
50 die("I/O error writing prompt");
51 if (fgets(buf
, BUF_SIZE
, stdin
) == NULL
) {
53 die("I/O error reading line");
55 buf
[0] = '\0'; /* Unclear if fgets does this already */
58 die("Unexpected error reading line");
62 static void write_line(const char *now
, FILE *f
, const char *line
) {
64 die_err("Error opening output file");
65 if (fputs(now
, f
) == EOF
)
66 die("Error writing to output file");
67 if (fputc(' ', f
) == EOF
)
68 die("Error writing to output file");
69 if (fputs(line
, f
) == EOF
)
70 die("Error writing to output file");
73 static void take_fcntl_lock(conf_t
*conf
, FILE *f
) {
74 if (!conf
->fcntl_lock
)
77 lock
.l_type
= F_WRLCK
;
78 lock
.l_whence
= SEEK_SET
;
83 die_err("Couldn't get file descriptor for locking");
84 if (fcntl(fd
, F_SETLK
, &lock
) == 0)
86 if (errno
!= EACCES
&& errno
!= EAGAIN
)
87 die_err("Couldn't take fcntl lock");
88 if (fputs(WAITING
, stderr
) == EOF
)
89 die("Error writing waiting message");
90 if (fcntl(fd
, F_SETLKW
, &lock
) == 0)
92 die_err("Couldn't take fcntl lock");
95 static void take_flock_lock(conf_t
*conf
, FILE *f
) {
96 if (!conf
->flock_lock
)
100 die_err("Couldn't get file descriptor for locking");
101 if (flock(fd
, LOCK_EX
| LOCK_NB
) == 0)
103 if (errno
!= EWOULDBLOCK
)
104 die_err("Couldn't take flock lock");
105 if (fputs(WAITING
, stderr
) == EOF
)
106 die("Error writing waiting message");
107 if (flock(fd
, LOCK_EX
) == 0)
109 die_err("Couldn't take flock lock");
112 static void take_lock(conf_t
*conf
, FILE *f
) {
113 take_fcntl_lock(conf
, f
);
114 take_flock_lock(conf
, f
);
117 static void write_acknowledgment(conf_t
*conf
) {
118 if (conf
->interactive
) {
119 if (fputs(ACKNOWLEDGE
, stderr
) == EOF
)
120 die("Error writing acknowledgment");
121 if (nanosleep(&ACKNOWLEDGE_DELAY
, NULL
) == -1 && errno
!= EINTR
)
122 die_err("Error sleeping");
126 static void lock_and_write_line(conf_t
*conf
, const char *line
) {
127 const char *now
= encode_time(time(NULL
));
128 FILE *f
= fopen(FILENAME
, "a");
131 write_line(now
, f
, line
);
134 die_err("Error closing output file");
136 write_acknowledgment(conf
);
139 int main(int argc
, char *argv
[]) {
140 conf_t conf
= parse_command_line(argc
, argv
);
142 for (read_line(&conf
, buf
); buf
[0]; read_line(&conf
, buf
)) {
143 lock_and_write_line(&conf
, buf
);