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.3 2005/12/05 01:04:00 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(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 235