1 /*
2  * Copyright 2001, 2002, 2003, 2013 Adam Sampson <ats@offog.org>
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #include <unistd.h>
18 #include <signal.h>
19 #include <time.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <fcntl.h>
25 #include "iolib.h"
26 #include "freedt.h"
27 #include "config.h"
28 const char *progname = "dumblog";
29 const char *proghelp =
30 	"Usage: dumblog [OPTIONS] logfile\n"
31 	"Log standard input to a file.\n\n"
32 	"-c        Prepend a timestamp to each line\n";
33 
34 int stamp_ctime = 0;
35 char *logfile_name;
36 int logfile;
37 int return_code = 0;
38 buffer line = BUFFER;
39 buffer overflow = BUFFER;
40 
flush_line()41 void flush_line() {
42 	if (blength(&line) > 0) {
43 		buffer out = BUFFER;
44 
45 		if (stamp_ctime) {
46 			time_t t = time(NULL);
47 			const char *s = ctime(&t);
48 			bappendm(&out, s, strlen(s) - 1);
49 			bappendc(&out, ' ');
50 		}
51 		bappend(&out, &line);
52 		bappendc(&out, '\n');
53 
54 		while (1) {
55 			if (writeba(logfile, &out) >= 0)
56 				break;
57 
58 			warn2(logfile_name, "unable to write to logfile");
59 			reliable_sleep(5);
60 		}
61 
62 		bfree(&out);
63 	}
64 	bfree(&line);
65 }
66 
open_logfile()67 void open_logfile() {
68 	logfile = open(logfile_name, O_WRONLY | O_APPEND | O_CREAT | O_SYNC,
69 		0644);
70 	if (logfile < 0)
71 		die2(logfile_name, "unable to open logfile");
72 }
73 
close_logfile()74 void close_logfile() {
75 	flush_line();
76 
77 	while (1) {
78 		if (close(logfile) >= 0)
79 			break;
80 
81 		warn2(logfile_name, "unable to close logfile");
82 		reliable_sleep(5);
83 	}
84 }
85 
roll_handler(int dummy)86 void roll_handler(int dummy) {
87 	close_logfile();
88 	open_logfile();
89 }
90 
quit_handler(int dummy)91 void quit_handler(int dummy) {
92 	flush_line();
93 	bappend(&line, &overflow);
94 	close_logfile();
95 	exit(return_code);
96 }
97 
main(int argc,char ** argv)98 int main(int argc, char **argv) {
99 	struct sigaction sa;
100 
101 	while (1) {
102 		int c = getopt(argc, argv, "V?c");
103 		if (c == -1)
104 			break;
105 		switch (c) {
106 		case 'c':
107 			stamp_ctime = 1;
108 			break;
109 		case 'V':
110 			version();
111 		default:
112 			help();
113 		}
114 	}
115 
116 	if ((argc - optind) != 1)
117 		help();
118 	logfile_name = argv[optind];
119 
120 	sigemptyset(&sa.sa_mask);
121 	sa.sa_flags = 0;
122 
123 	sa.sa_handler = roll_handler;
124 	if (sigaction(SIGHUP, &sa, NULL) < 0)
125 		die("unable to install sighup handler");
126 	sa.sa_handler = quit_handler;
127 	if (sigaction(SIGTERM, &sa, NULL) < 0)
128 		die("unable to install sigterm handler");
129 
130 	open_logfile();
131 
132 	while (1) {
133 		int rc = readlineb(fd_in, &line, 0, &overflow);
134 		if (rc < 0) {
135 			warn("unable to read from stdin");
136 			return_code = 1;
137 			quit_handler(0);
138 		}
139 		if (rc == 0)
140 			break;
141 
142 		flush_line();
143 	}
144 
145 	quit_handler(0);
146 	return 0; /* NOTREACHED */
147 }
148 
149