xref: /dragonfly/usr.sbin/clog/clog.c (revision 1bf4b486)
1 /*-
2  * Copyright (c) 2001
3  *     Jeff Wheelhouse (jdw@wwwi.com)
4  *
5  * This code was originally developed by Jeff Wheelhouse (jdw@wwwi.com).
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistribution of source code must retail the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY JEFF WHEELHOUSE ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
19  * NO EVENT SHALL JEFF WHEELHOUSE BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING BUT NOT
21  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
22  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
25  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  * $Id: clog.c,v 1.3 2001/10/02 18:51:26 jdw Exp $
28  * $DragonFly: src/usr.sbin/clog/clog.c,v 1.2 2004/12/18 22:48:03 swildner Exp $
29  */
30 
31 
32 #include <assert.h>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <poll.h>
36 #include <sched.h>
37 #include <signal.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42 
43 #include <sys/mman.h>
44 #include <sys/stat.h>
45 #include <sys/uio.h>
46 
47 
48 #include "clog.h"
49 
50 
51 /*
52  *  The BUFFER_SIZE value is just used to allocate a buffer full of NULLs
53  *  so that a new logfile can be extended to its full size.
54  *
55  *  Compiling with -pedantic complains when the buffer array is declared
56  *  if I declare this as a const instead of a #define.
57  */
58 #define BUFFER_SIZE 16384
59 
60 void init_log __P((const char *lname, size_t size));
61 void read_log __P((const char *lname, int optf));
62 void usage __P((void));
63 
64 const char *pname;
65 
66 int main(int argc, char **argv) {
67 	int ch;
68 	int init = 0;
69 	int size = 0;
70 	int optf = 0;
71 
72 	pname = argv[0];
73 
74 	while ((ch = getopt(argc, argv, "fis:")) != -1)
75 		switch(ch) {
76 		case 'i':
77 			init = 1;
78 			break;
79 		case 's':
80 			size = atol(optarg);
81 			if (size==0) usage();
82 			break;
83 		case 'f':
84 			optf = 1;
85 		}
86 
87 	if ((size>0)&&(init==0)) {
88 		fprintf(stderr,"%s: WARNING: -s argument ignored without -i.\n",pname);
89 		size = 0;
90 	}
91 	if (argv[optind]==NULL) {
92 		fprintf(stderr,"%s: ERROR: log_file argument must be specified.\n",pname);
93 		usage();
94 	}
95 	if ((init==1)&&(size==0)) {
96 		fprintf(stderr,"%s: ERROR: -i argument requires -s.\n",pname);
97 		usage();
98 	}
99 	if ((init==1)&&(optf==1)) {
100 		fprintf(stderr,"%s: ERROR: flags -f and -i are incompatible.\n",pname);
101 		usage();
102 	}
103 
104 	if (init==1) init_log(argv[optind],size);
105 	/* if (optf==1) follow_log(artv[optind]); */
106 	read_log(argv[optind],optf);
107 
108 	return 0;
109 }
110 
111 
112 void usage() {
113   fprintf(stderr,"usage: %s [-i -s log_size] [ -f ] log_file\n",pname);
114   exit(1);
115 }
116 
117 
118 void read_log(const char *lname, int optf) {
119 	int fd;
120 	struct stat sb;
121 	struct clog_footer *pcf;
122 	char *pbuffer;
123 	struct iovec iov[2];
124 	int iovcnt = 0;
125 	uint32_t start = 0;
126 	uint32_t next;
127 	struct pollfd pfd;
128 
129 	pfd.fd = -1;
130 
131 	fd = open(lname,O_RDONLY);
132 	if (fd==-1) {
133 		fprintf(stderr,"%s: ERROR: could not open %s (%s)\n",pname,lname,strerror(errno));
134 		exit(11);
135 	}
136 
137 	if (fstat(fd,&sb)==-1) {
138 		fprintf(stderr,"%s: ERROR: could not stat %s (%s)\n",pname,lname,strerror(errno));
139 		exit(13);
140 	}
141 	pbuffer = mmap(NULL,sb.st_size,PROT_READ,MAP_SHARED,fd,0);
142 	if (pbuffer==NULL) {
143 		fprintf(stderr,"%s: ERROR: could not mmap %s body (%s)\n",pname,lname,strerror(errno));
144 		exit(14);
145 	}
146 	pcf = (struct clog_footer*)(pbuffer + sb.st_size - sizeof(struct clog_footer));
147 
148 	if (pcf->cf_wrap==1) start = pcf->cf_next + 1;
149 	while(1) {
150 		while(pcf->cf_lock==1) sched_yield();
151 		next = pcf->cf_next;
152 		iovcnt = 0;
153 		if (start>next) {
154 			iov[iovcnt].iov_base = pbuffer + start;
155 			iov[iovcnt++].iov_len = pcf->cf_max - start;
156 			start = 0;
157 		}
158 		iov[iovcnt].iov_base = pbuffer + start;
159 		iov[iovcnt++].iov_len = next - start;
160 		if (writev(1,iov,iovcnt)==-1) {
161 			fprintf(stderr,"%s: ERROR: could not write output (%s)\n",pname,strerror(errno));
162 			exit(15);
163 		}
164 		start = next;
165 		if (optf==0) break;
166 		if (poll(&pfd,1,50)==-1) {
167 			fprintf(stderr,"%s: ERROR: could not poll (%s)\n",pname,strerror(errno));
168 			exit(16);
169 		}
170 	}
171 
172 	munmap(pbuffer,sb.st_size);
173 	close(fd);
174 
175 	exit(0);
176 }
177 
178 
179 void init_log(const char *lname, size_t size) {
180 	int fd;
181 	size_t fill = size;
182 	char buffer[BUFFER_SIZE];
183 	struct clog_footer cf;
184 
185 	memcpy(&cf.cf_magic,MAGIC_CONST,4);
186 	cf.cf_max = size - sizeof(struct clog_footer);
187 
188 	memset(buffer,0,BUFFER_SIZE);
189 
190 	fd = open(lname,O_RDWR|O_CREAT,0666);
191 	if (fd==-1) {
192 		fprintf(stderr,"%s: ERROR: could not open %s (%s)\n",pname,lname,strerror(errno));
193 		exit(2);
194 	}
195 	if (ftruncate(fd,(off_t)0)==-1) {
196 		fprintf(stderr,"%s: ERROR: could not truncate %s (%s)\n",pname,lname,strerror(errno));
197 		exit(3);
198 	}
199 
200 	while(fill>BUFFER_SIZE) {
201 		if (write(fd,buffer,BUFFER_SIZE)==-1){
202 			fprintf(stderr,"%s: ERROR: could not write %s (%s)\n",pname,lname,strerror(errno));
203 			exit(4);
204 		}
205 		fill -= BUFFER_SIZE;
206 	}
207 	assert(fill<=BUFFER_SIZE);
208 	if (fill>0) {
209 		if (write(fd,buffer,fill)==-1) {
210 			fprintf(stderr,"%s: ERROR: could not write %s (%s)\n",pname,lname,strerror(errno));
211 			exit(5);
212 		}
213 	}
214 	if (lseek(fd,-(off_t)(sizeof(struct clog_footer)),SEEK_END)==-1) {
215 		fprintf(stderr,"%s: ERROR: could not seek in %s (%s)\n",pname,lname,strerror(errno));
216 		exit(6);
217 	}
218 	if (write(fd,&cf,sizeof(cf))==-1) {
219 		fprintf(stderr,"%s: ERROR: could not write magic in %s (%s)\n",pname,lname,strerror(errno));
220 		exit(7);
221 	}
222 	close(fd);
223 	exit(0);
224 }
225 
226 
227