Merge branch 'vendor/OPENSSL'
[dragonfly.git] / usr.sbin / clog / clog.c
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.4 2007/06/26 23:30:05 josepht Exp $
29  */
30
31
32 #include <assert.h>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <poll.h>
36 #include <signal.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <unistd.h>
41
42 #include <sys/mman.h>
43 #include <sys/sched.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(const char *lname, size_t size);
61 void read_log(const char *lname, int optf);
62 void usage(void);
63
64 const char *pname;
65
66 int
67 main(int argc, char **argv)
68 {
69         int ch;
70         int init = 0;
71         int size = 0;
72         int optf = 0;
73
74         pname = argv[0];
75
76         while ((ch = getopt(argc, argv, "fis:")) != -1)
77                 switch(ch) {
78                 case 'i':
79                         init = 1;
80                         break;
81                 case 's':
82                         size = atol(optarg);
83                         if (size==0) usage();
84                         break;
85                 case 'f':
86                         optf = 1;
87                 }
88
89         if ((size>0)&&(init==0)) {
90                 fprintf(stderr,"%s: WARNING: -s argument ignored without -i.\n",pname);
91                 size = 0;
92         }
93         if (argv[optind]==NULL) {
94                 fprintf(stderr,"%s: ERROR: log_file argument must be specified.\n",pname);
95                 usage();
96         }
97         if ((init==1)&&(size==0)) {
98                 fprintf(stderr,"%s: ERROR: -i argument requires -s.\n",pname);
99                 usage();
100         }
101         if ((init==1)&&(optf==1)) {
102                 fprintf(stderr,"%s: ERROR: flags -f and -i are incompatible.\n",pname);
103                 usage();
104         }
105
106         if (init==1) init_log(argv[optind],size);
107         /* if (optf==1) follow_log(artv[optind]); */
108         read_log(argv[optind],optf);
109                 
110         return 0;
111 }
112
113
114 void
115 usage(void)
116 {
117   fprintf(stderr,"usage: %s [-i -s log_size] [ -f ] log_file\n",pname);
118   exit(1);
119 }
120
121
122 void
123 read_log(const char *lname, int optf)
124 {
125         int fd;
126         struct stat sb;
127         struct clog_footer *pcf;
128         char *pbuffer;
129         struct iovec iov[2];
130         int iovcnt = 0;
131         uint32_t start = 0;
132         uint32_t next;
133         struct pollfd pfd;
134
135         pfd.fd = -1;
136
137         fd = open(lname,O_RDONLY);
138         if (fd==-1) {
139                 fprintf(stderr,"%s: ERROR: could not open %s (%s)\n",pname,lname,strerror(errno));
140                 exit(11);
141         }
142
143         if (fstat(fd,&sb)==-1) {
144                 fprintf(stderr,"%s: ERROR: could not stat %s (%s)\n",pname,lname,strerror(errno));
145                 exit(13);
146         }
147         pbuffer = mmap(NULL,sb.st_size,PROT_READ,MAP_SHARED,fd,0);
148         if (pbuffer==NULL) {
149                 fprintf(stderr,"%s: ERROR: could not mmap %s body (%s)\n",pname,lname,strerror(errno));
150                 exit(14);
151         }
152         pcf = (struct clog_footer*)(pbuffer + sb.st_size - sizeof(struct clog_footer));
153
154         if (pcf->cf_wrap==1) start = pcf->cf_next + 1;
155         while(1) {
156                 while(pcf->cf_lock==1) sched_yield();
157                 next = pcf->cf_next;
158                 iovcnt = 0;
159                 if (start>next) {
160                         iov[iovcnt].iov_base = pbuffer + start;
161                         iov[iovcnt++].iov_len = pcf->cf_max - start;
162                         start = 0;
163                 }
164                 iov[iovcnt].iov_base = pbuffer + start;
165                 iov[iovcnt++].iov_len = next - start;
166                 if (writev(1,iov,iovcnt)==-1) {
167                         fprintf(stderr,"%s: ERROR: could not write output (%s)\n",pname,strerror(errno));
168                         exit(15);
169                 }
170                 start = next;
171                 if (optf==0) break;
172                 if (poll(&pfd,1,50)==-1) {
173                         fprintf(stderr,"%s: ERROR: could not poll (%s)\n",pname,strerror(errno));
174                         exit(16);
175                 }
176         }
177         
178         munmap(pbuffer,sb.st_size);
179         close(fd);
180
181         exit(0);
182 }
183
184
185 void
186 init_log(const char *lname, size_t size)
187 {
188         int fd;
189         size_t fill = size;
190         char buffer[BUFFER_SIZE];
191         struct clog_footer cf;
192
193         memcpy(&cf.cf_magic,MAGIC_CONST,4);
194         cf.cf_max = size - sizeof(struct clog_footer);
195
196         memset(buffer,0,BUFFER_SIZE);
197
198         fd = open(lname,O_RDWR|O_CREAT,0666); 
199         if (fd==-1) {
200                 fprintf(stderr,"%s: ERROR: could not open %s (%s)\n",pname,lname,strerror(errno));
201                 exit(2);
202         }
203         if (ftruncate(fd,(off_t)0)==-1) {
204                 fprintf(stderr,"%s: ERROR: could not truncate %s (%s)\n",pname,lname,strerror(errno));
205                 exit(3);
206         }
207         
208         while(fill>BUFFER_SIZE) {
209                 if (write(fd,buffer,BUFFER_SIZE)==-1){
210                         fprintf(stderr,"%s: ERROR: could not write %s (%s)\n",pname,lname,strerror(errno));
211                         exit(4);
212                 }
213                 fill -= BUFFER_SIZE;
214         }
215         assert(fill<=BUFFER_SIZE);
216         if (fill>0) {
217                 if (write(fd,buffer,fill)==-1) {
218                         fprintf(stderr,"%s: ERROR: could not write %s (%s)\n",pname,lname,strerror(errno));
219                         exit(5);
220                 }
221         }
222         if (lseek(fd,-(off_t)(sizeof(struct clog_footer)),SEEK_END)==-1) {
223                 fprintf(stderr,"%s: ERROR: could not seek in %s (%s)\n",pname,lname,strerror(errno));
224                 exit(6);
225         }
226         if (write(fd,&cf,sizeof(cf))==-1) {
227                 fprintf(stderr,"%s: ERROR: could not write magic in %s (%s)\n",pname,lname,strerror(errno));
228                 exit(7);
229         }
230         close(fd);
231         exit(0);
232 }
233
234