1534b2416SMatthew Dillon /*-
2534b2416SMatthew Dillon * Copyright (c) 2001
3534b2416SMatthew Dillon * Jeff Wheelhouse (jdw@wwwi.com)
4534b2416SMatthew Dillon *
5534b2416SMatthew Dillon * This code was originally developed by Jeff Wheelhouse (jdw@wwwi.com).
6534b2416SMatthew Dillon *
7534b2416SMatthew Dillon * Redistribution and use in source and binary forms, with or without
8534b2416SMatthew Dillon * modification, are permitted provided that the following conditions
9534b2416SMatthew Dillon * are met:
10534b2416SMatthew Dillon * 1. Redistribution of source code must retail the above copyright
11534b2416SMatthew Dillon * notice, this list of conditions and the following disclaimer.
12534b2416SMatthew Dillon * 2. Redistributions in binary form must reproduce the above copyright
13534b2416SMatthew Dillon * notice, this list of conditions and the following disclaimer in the
14534b2416SMatthew Dillon * documentation and/or other materials provided with the distribution.
15534b2416SMatthew Dillon *
16534b2416SMatthew Dillon * THIS SOFTWARE IS PROVIDED BY JEFF WHEELHOUSE ``AS IS'' AND ANY EXPRESS OR
17534b2416SMatthew Dillon * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18534b2416SMatthew Dillon * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
19534b2416SMatthew Dillon * NO EVENT SHALL JEFF WHEELHOUSE BE LIABLE FOR ANY DIRECT, INDIRECT,
20534b2416SMatthew Dillon * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING BUT NOT
21534b2416SMatthew Dillon * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
22534b2416SMatthew Dillon * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23534b2416SMatthew Dillon * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24534b2416SMatthew Dillon * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
25534b2416SMatthew Dillon * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26534b2416SMatthew Dillon *
27534b2416SMatthew Dillon * $Id: clog.c,v 1.3 2001/10/02 18:51:26 jdw Exp $
28534b2416SMatthew Dillon */
29534b2416SMatthew Dillon
30534b2416SMatthew Dillon
31534b2416SMatthew Dillon #include <assert.h>
32534b2416SMatthew Dillon #include <errno.h>
33534b2416SMatthew Dillon #include <fcntl.h>
34534b2416SMatthew Dillon #include <poll.h>
35534b2416SMatthew Dillon #include <signal.h>
36534b2416SMatthew Dillon #include <stdio.h>
37534b2416SMatthew Dillon #include <stdlib.h>
38534b2416SMatthew Dillon #include <string.h>
39534b2416SMatthew Dillon #include <unistd.h>
40534b2416SMatthew Dillon
41534b2416SMatthew Dillon #include <sys/mman.h>
42c4dd4100SJoe Talbott #include <sys/sched.h>
43534b2416SMatthew Dillon #include <sys/stat.h>
44534b2416SMatthew Dillon #include <sys/uio.h>
45534b2416SMatthew Dillon
46534b2416SMatthew Dillon
47534b2416SMatthew Dillon #include "clog.h"
48534b2416SMatthew Dillon
49534b2416SMatthew Dillon
50534b2416SMatthew Dillon /*
51534b2416SMatthew Dillon * The BUFFER_SIZE value is just used to allocate a buffer full of NULLs
52534b2416SMatthew Dillon * so that a new logfile can be extended to its full size.
53534b2416SMatthew Dillon *
54534b2416SMatthew Dillon * Compiling with -pedantic complains when the buffer array is declared
55534b2416SMatthew Dillon * if I declare this as a const instead of a #define.
56534b2416SMatthew Dillon */
57534b2416SMatthew Dillon #define BUFFER_SIZE 16384
58534b2416SMatthew Dillon
59*fe08e20dSSascha Wildner static void init_log(const char *lname, size_t size) __dead2;
60*fe08e20dSSascha Wildner static void read_log(const char *lname, int optf) __dead2;
61*fe08e20dSSascha Wildner static void usage(void) __dead2;
62534b2416SMatthew Dillon
63bf3beda6SSascha Wildner static const char *pname;
64534b2416SMatthew Dillon
65a4c90f86SSascha Wildner int
main(int argc,char ** argv)66a4c90f86SSascha Wildner main(int argc, char **argv)
67a4c90f86SSascha Wildner {
68534b2416SMatthew Dillon int ch;
69534b2416SMatthew Dillon int init = 0;
70534b2416SMatthew Dillon int size = 0;
71534b2416SMatthew Dillon int optf = 0;
72534b2416SMatthew Dillon
73534b2416SMatthew Dillon pname = argv[0];
74534b2416SMatthew Dillon
75534b2416SMatthew Dillon while ((ch = getopt(argc, argv, "fis:")) != -1)
76534b2416SMatthew Dillon switch(ch) {
77534b2416SMatthew Dillon case 'i':
78534b2416SMatthew Dillon init = 1;
79534b2416SMatthew Dillon break;
80534b2416SMatthew Dillon case 's':
81534b2416SMatthew Dillon size = atol(optarg);
82534b2416SMatthew Dillon if (size==0) usage();
83534b2416SMatthew Dillon break;
84534b2416SMatthew Dillon case 'f':
85534b2416SMatthew Dillon optf = 1;
86534b2416SMatthew Dillon }
87534b2416SMatthew Dillon
88534b2416SMatthew Dillon if ((size>0)&&(init==0)) {
89534b2416SMatthew Dillon fprintf(stderr,"%s: WARNING: -s argument ignored without -i.\n",pname);
90534b2416SMatthew Dillon size = 0;
91534b2416SMatthew Dillon }
92534b2416SMatthew Dillon if (argv[optind]==NULL) {
93534b2416SMatthew Dillon fprintf(stderr,"%s: ERROR: log_file argument must be specified.\n",pname);
94534b2416SMatthew Dillon usage();
95534b2416SMatthew Dillon }
96534b2416SMatthew Dillon if ((init==1)&&(size==0)) {
97534b2416SMatthew Dillon fprintf(stderr,"%s: ERROR: -i argument requires -s.\n",pname);
98534b2416SMatthew Dillon usage();
99534b2416SMatthew Dillon }
100534b2416SMatthew Dillon if ((init==1)&&(optf==1)) {
101534b2416SMatthew Dillon fprintf(stderr,"%s: ERROR: flags -f and -i are incompatible.\n",pname);
102534b2416SMatthew Dillon usage();
103534b2416SMatthew Dillon }
104534b2416SMatthew Dillon
105534b2416SMatthew Dillon if (init==1) init_log(argv[optind],size);
106534b2416SMatthew Dillon /* if (optf==1) follow_log(artv[optind]); */
107534b2416SMatthew Dillon read_log(argv[optind],optf);
108534b2416SMatthew Dillon
109534b2416SMatthew Dillon return 0;
110534b2416SMatthew Dillon }
111534b2416SMatthew Dillon
112534b2416SMatthew Dillon
113bf3beda6SSascha Wildner static void
usage(void)114a4c90f86SSascha Wildner usage(void)
115a4c90f86SSascha Wildner {
116534b2416SMatthew Dillon fprintf(stderr,"usage: %s [-i -s log_size] [ -f ] log_file\n",pname);
117534b2416SMatthew Dillon exit(1);
118534b2416SMatthew Dillon }
119534b2416SMatthew Dillon
120534b2416SMatthew Dillon
121bf3beda6SSascha Wildner static void
read_log(const char * lname,int optf)122a4c90f86SSascha Wildner read_log(const char *lname, int optf)
123a4c90f86SSascha Wildner {
124534b2416SMatthew Dillon int fd;
125534b2416SMatthew Dillon struct stat sb;
126534b2416SMatthew Dillon struct clog_footer *pcf;
127534b2416SMatthew Dillon char *pbuffer;
128534b2416SMatthew Dillon struct iovec iov[2];
129534b2416SMatthew Dillon int iovcnt = 0;
130534b2416SMatthew Dillon uint32_t start = 0;
131534b2416SMatthew Dillon uint32_t next;
132534b2416SMatthew Dillon struct pollfd pfd;
133534b2416SMatthew Dillon
134534b2416SMatthew Dillon pfd.fd = -1;
135534b2416SMatthew Dillon
136534b2416SMatthew Dillon fd = open(lname,O_RDONLY);
137534b2416SMatthew Dillon if (fd==-1) {
138534b2416SMatthew Dillon fprintf(stderr,"%s: ERROR: could not open %s (%s)\n",pname,lname,strerror(errno));
139534b2416SMatthew Dillon exit(11);
140534b2416SMatthew Dillon }
141534b2416SMatthew Dillon
142534b2416SMatthew Dillon if (fstat(fd,&sb)==-1) {
143534b2416SMatthew Dillon fprintf(stderr,"%s: ERROR: could not stat %s (%s)\n",pname,lname,strerror(errno));
144534b2416SMatthew Dillon exit(13);
145534b2416SMatthew Dillon }
146534b2416SMatthew Dillon pbuffer = mmap(NULL,sb.st_size,PROT_READ,MAP_SHARED,fd,0);
147534b2416SMatthew Dillon if (pbuffer==NULL) {
148534b2416SMatthew Dillon fprintf(stderr,"%s: ERROR: could not mmap %s body (%s)\n",pname,lname,strerror(errno));
149534b2416SMatthew Dillon exit(14);
150534b2416SMatthew Dillon }
151534b2416SMatthew Dillon pcf = (struct clog_footer*)(pbuffer + sb.st_size - sizeof(struct clog_footer));
152534b2416SMatthew Dillon
153534b2416SMatthew Dillon if (pcf->cf_wrap==1) start = pcf->cf_next + 1;
154534b2416SMatthew Dillon while(1) {
155534b2416SMatthew Dillon while(pcf->cf_lock==1) sched_yield();
156534b2416SMatthew Dillon next = pcf->cf_next;
157534b2416SMatthew Dillon iovcnt = 0;
158534b2416SMatthew Dillon if (start>next) {
159534b2416SMatthew Dillon iov[iovcnt].iov_base = pbuffer + start;
160534b2416SMatthew Dillon iov[iovcnt++].iov_len = pcf->cf_max - start;
161534b2416SMatthew Dillon start = 0;
162534b2416SMatthew Dillon }
163534b2416SMatthew Dillon iov[iovcnt].iov_base = pbuffer + start;
164534b2416SMatthew Dillon iov[iovcnt++].iov_len = next - start;
165534b2416SMatthew Dillon if (writev(1,iov,iovcnt)==-1) {
166534b2416SMatthew Dillon fprintf(stderr,"%s: ERROR: could not write output (%s)\n",pname,strerror(errno));
167534b2416SMatthew Dillon exit(15);
168534b2416SMatthew Dillon }
169534b2416SMatthew Dillon start = next;
170534b2416SMatthew Dillon if (optf==0) break;
171534b2416SMatthew Dillon if (poll(&pfd,1,50)==-1) {
172534b2416SMatthew Dillon fprintf(stderr,"%s: ERROR: could not poll (%s)\n",pname,strerror(errno));
173534b2416SMatthew Dillon exit(16);
174534b2416SMatthew Dillon }
175534b2416SMatthew Dillon }
176534b2416SMatthew Dillon
17771126e33SSascha Wildner munmap(pbuffer,sb.st_size);
17871126e33SSascha Wildner close(fd);
179534b2416SMatthew Dillon
180534b2416SMatthew Dillon exit(0);
181534b2416SMatthew Dillon }
182534b2416SMatthew Dillon
183534b2416SMatthew Dillon
184bf3beda6SSascha Wildner static void
init_log(const char * lname,size_t size)185a4c90f86SSascha Wildner init_log(const char *lname, size_t size)
186a4c90f86SSascha Wildner {
187534b2416SMatthew Dillon int fd;
188534b2416SMatthew Dillon size_t fill = size;
189534b2416SMatthew Dillon char buffer[BUFFER_SIZE];
190534b2416SMatthew Dillon struct clog_footer cf;
191534b2416SMatthew Dillon
192534b2416SMatthew Dillon memcpy(&cf.cf_magic,MAGIC_CONST,4);
193534b2416SMatthew Dillon cf.cf_max = size - sizeof(struct clog_footer);
194534b2416SMatthew Dillon
19571126e33SSascha Wildner memset(buffer,0,BUFFER_SIZE);
196534b2416SMatthew Dillon
197534b2416SMatthew Dillon fd = open(lname,O_RDWR|O_CREAT,0666);
198534b2416SMatthew Dillon if (fd==-1) {
199534b2416SMatthew Dillon fprintf(stderr,"%s: ERROR: could not open %s (%s)\n",pname,lname,strerror(errno));
200534b2416SMatthew Dillon exit(2);
201534b2416SMatthew Dillon }
202534b2416SMatthew Dillon if (ftruncate(fd,(off_t)0)==-1) {
203534b2416SMatthew Dillon fprintf(stderr,"%s: ERROR: could not truncate %s (%s)\n",pname,lname,strerror(errno));
204534b2416SMatthew Dillon exit(3);
205534b2416SMatthew Dillon }
206534b2416SMatthew Dillon
207534b2416SMatthew Dillon while(fill>BUFFER_SIZE) {
208534b2416SMatthew Dillon if (write(fd,buffer,BUFFER_SIZE)==-1){
209534b2416SMatthew Dillon fprintf(stderr,"%s: ERROR: could not write %s (%s)\n",pname,lname,strerror(errno));
210534b2416SMatthew Dillon exit(4);
211534b2416SMatthew Dillon }
212534b2416SMatthew Dillon fill -= BUFFER_SIZE;
213534b2416SMatthew Dillon }
214534b2416SMatthew Dillon assert(fill<=BUFFER_SIZE);
215534b2416SMatthew Dillon if (fill>0) {
216534b2416SMatthew Dillon if (write(fd,buffer,fill)==-1) {
217534b2416SMatthew Dillon fprintf(stderr,"%s: ERROR: could not write %s (%s)\n",pname,lname,strerror(errno));
218534b2416SMatthew Dillon exit(5);
219534b2416SMatthew Dillon }
220534b2416SMatthew Dillon }
221534b2416SMatthew Dillon if (lseek(fd,-(off_t)(sizeof(struct clog_footer)),SEEK_END)==-1) {
222534b2416SMatthew Dillon fprintf(stderr,"%s: ERROR: could not seek in %s (%s)\n",pname,lname,strerror(errno));
223534b2416SMatthew Dillon exit(6);
224534b2416SMatthew Dillon }
225534b2416SMatthew Dillon if (write(fd,&cf,sizeof(cf))==-1) {
226534b2416SMatthew Dillon fprintf(stderr,"%s: ERROR: could not write magic in %s (%s)\n",pname,lname,strerror(errno));
227534b2416SMatthew Dillon exit(7);
228534b2416SMatthew Dillon }
22971126e33SSascha Wildner close(fd);
230534b2416SMatthew Dillon exit(0);
231534b2416SMatthew Dillon }
232