Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/coreutils/tail.c
- Timestamp:
- Feb 25, 2011, 9:26:54 PM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/2.2.9/mindi-busybox/coreutils/tail.c
r1772 r2725 5 5 * Copyright (C) 2001 by Matt Kraai <kraai@alumni.carnegiemellon.edu> 6 6 * 7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.7 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 8 8 */ 9 9 … … 31 31 { "k", 1024 }, 32 32 { "m", 1024*1024 }, 33 { }33 { "", 0 } 34 34 }; 35 35 36 36 struct globals { 37 37 bool status; 38 } ;38 } FIX_ALIASING; 39 39 #define G (*(struct globals*)&bb_common_bufsiz1) 40 40 … … 51 51 struct stat sbuf; 52 52 53 /* (A good comment is missing here) */54 current = lseek(fd, 0, SEEK_CUR);55 53 /* /proc files report zero st_size, don't lseek them. */ 56 if (fstat(fd, &sbuf) == 0 && sbuf.st_size) 54 if (fstat(fd, &sbuf) == 0 && sbuf.st_size > 0) { 55 current = lseek(fd, 0, SEEK_CUR); 57 56 if (sbuf.st_size < current) 58 lseek(fd, 0, SEEK_SET); 59 60 r = safe_read(fd, buf, count); 57 xlseek(fd, 0, SEEK_SET); 58 } 59 60 r = full_read(fd, buf, count); 61 61 if (r < 0) { 62 62 bb_perror_msg(bb_msg_read_error); … … 67 67 } 68 68 69 static const char header_fmt[] ALIGN1 = "\n==> %s <==\n"; 69 #define header_fmt_str "\n==> %s <==\n" 70 70 71 71 static unsigned eat_num(const char *p) … … 75 75 else if (*p == '+') { 76 76 p++; 77 G.status = EXIT_FAILURE;77 G.status = 1; /* mark that we saw "+" */ 78 78 } 79 79 return xatou_sfx(p, tail_suffixes); 80 80 } 81 81 82 int tail_main(int argc, char **argv) ;82 int tail_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 83 83 int tail_main(int argc, char **argv) 84 84 { … … 86 86 unsigned sleep_period = 1; 87 87 bool from_top; 88 int header_threshhold = 1;89 88 const char *str_c, *str_n; 90 USE_FEATURE_FANCY_TAIL(const char *str_s;)91 89 92 90 char *tailbuf; 93 91 size_t tailbufsize; 94 int taillen = 0;95 int newline = 0;96 int nfiles, nread, nwrite, seen,i, opt;92 unsigned header_threshhold = 1; 93 unsigned nfiles; 94 int i, opt; 97 95 98 96 int *fds; 99 char *s, *buf;100 97 const char *fmt; 101 98 102 99 #if ENABLE_INCLUDE_SUSv2 || ENABLE_FEATURE_FANCY_TAIL 103 100 /* Allow legacy syntax of an initial numeric option without -n. */ 104 if (arg c >= 2&& (argv[1][0] == '+' || argv[1][0] == '-')101 if (argv[1] && (argv[1][0] == '+' || argv[1][0] == '-') 105 102 && isdigit(argv[1][1]) 106 103 ) { 107 /* replacing arg[0] with "-n" can segfault, so... */ 108 argv[1] = xasprintf("-n%s", argv[1]); 109 #if 0 /* If we ever decide to make tail NOFORK */ 110 char *s = alloca(strlen(argv[1]) + 3); 111 sprintf(s, "-n%s", argv[1]); 112 argv[1] = s; 104 count = eat_num(argv[1]); 105 argv++; 106 argc--; 107 } 113 108 #endif 114 } 115 #endif 116 117 opt = getopt32(argv, "fc:n:" USE_FEATURE_FANCY_TAIL("qs:v"),118 &str_c, &str_n USE_FEATURE_FANCY_TAIL(,&str_s));109 110 /* -s NUM, -F imlies -f */ 111 IF_FEATURE_FANCY_TAIL(opt_complementary = "s+:Ff";) 112 opt = getopt32(argv, "fc:n:" IF_FEATURE_FANCY_TAIL("qs:vF"), 113 &str_c, &str_n IF_FEATURE_FANCY_TAIL(,&sleep_period)); 119 114 #define FOLLOW (opt & 0x1) 120 115 #define COUNT_BYTES (opt & 0x2) … … 123 118 if (opt & 0x4) count = eat_num(str_n); // -n 124 119 #if ENABLE_FEATURE_FANCY_TAIL 125 if (opt & 0x8) header_threshhold = INT_MAX; // -q 126 if (opt & 0x10) sleep_period = xatou(str_s); // -s 120 /* q: make it impossible for nfiles to be > header_threshhold */ 121 if (opt & 0x8) header_threshhold = UINT_MAX; // -q 122 //if (opt & 0x10) // -s 127 123 if (opt & 0x20) header_threshhold = 0; // -v 124 # define FOLLOW_RETRY (opt & 0x40) 125 #else 126 # define FOLLOW_RETRY 0 128 127 #endif 129 128 argc -= optind; 130 129 argv += optind; 131 from_top = G.status; 130 from_top = G.status; /* 1 if there was "-c +N" or "-n +N" */ 131 G.status = EXIT_SUCCESS; 132 132 133 133 /* open all the files */ 134 fds = xmalloc(sizeof(int) * (argc + 1)); 134 fds = xmalloc(sizeof(fds[0]) * (argc + 1)); 135 if (!argv[0]) { 136 struct stat statbuf; 137 138 if (fstat(STDIN_FILENO, &statbuf) == 0 139 && S_ISFIFO(statbuf.st_mode) 140 ) { 141 opt &= ~1; /* clear FOLLOW */ 142 } 143 argv[0] = (char *) bb_msg_standard_input; 144 } 135 145 nfiles = i = 0; 136 G.status = EXIT_SUCCESS;137 if (argc == 0) {138 struct stat statbuf;139 140 if (!fstat(STDIN_FILENO, &statbuf) && S_ISFIFO(statbuf.st_mode)) {141 opt &= ~1; /* clear FOLLOW */142 }143 *argv = (char *) bb_msg_standard_input;144 }145 146 do { 146 FILE* fil = fopen_or_warn_stdin(argv[i]);147 if ( !fil) {147 int fd = open_or_warn_stdin(argv[i]); 148 if (fd < 0 && !FOLLOW_RETRY) { 148 149 G.status = EXIT_FAILURE; 149 150 continue; 150 151 } 151 fds[nfiles] = f ileno(fil);152 fds[nfiles] = fd; 152 153 argv[nfiles++] = argv[i]; 153 154 } while (++i < argc); … … 156 157 bb_error_msg_and_die("no files"); 157 158 159 /* prepare the buffer */ 158 160 tailbufsize = BUFSIZ; 161 if (!from_top && COUNT_BYTES) { 162 if (tailbufsize < count + BUFSIZ) { 163 tailbufsize = count + BUFSIZ; 164 } 165 } 166 tailbuf = xmalloc(tailbufsize); 159 167 160 168 /* tail the files */ 161 if (!from_top && COUNT_BYTES) { 162 if (tailbufsize < count) { 163 tailbufsize = count + BUFSIZ; 164 } 165 } 166 167 buf = tailbuf = xmalloc(tailbufsize); 168 169 fmt = header_fmt + 1; /* Skip header leading newline on first output. */ 169 fmt = header_fmt_str + 1; /* skip header leading newline on first output */ 170 170 i = 0; 171 171 do { 172 /* Be careful. It would be possible to optimize the count-bytes 173 * case if the file is seekable. If you do though, remember that 174 * starting file position may not be the beginning of the file. 175 * Beware of backing up too far. See example in wc.c. 176 */ 177 if (!(count | from_top) && lseek(fds[i], 0, SEEK_END) >= 0) { 178 continue; 179 } 172 char *buf; 173 int taillen; 174 int newlines_seen; 175 unsigned seen; 176 int nread; 177 int fd = fds[i]; 178 179 if (ENABLE_FEATURE_FANCY_TAIL && fd < 0) 180 continue; /* may happen with -E */ 180 181 181 182 if (nfiles > header_threshhold) { 182 183 tail_xprint_header(fmt, argv[i]); 183 fmt = header_fmt; 184 fmt = header_fmt_str; 185 } 186 187 if (!from_top) { 188 off_t current = lseek(fd, 0, SEEK_END); 189 if (current > 0) { 190 unsigned off; 191 if (COUNT_BYTES) { 192 /* Optimizing count-bytes case if the file is seekable. 193 * Beware of backing up too far. 194 * Also we exclude files with size 0 (because of /proc/xxx) */ 195 if (count == 0) 196 continue; /* showing zero bytes is easy :) */ 197 current -= count; 198 if (current < 0) 199 current = 0; 200 xlseek(fd, current, SEEK_SET); 201 bb_copyfd_size(fd, STDOUT_FILENO, count); 202 continue; 203 } 204 #if 1 /* This is technically incorrect for *LONG* strings, but very useful */ 205 /* Optimizing count-lines case if the file is seekable. 206 * We assume the lines are <64k. 207 * (Users complain that tail takes too long 208 * on multi-gigabyte files) */ 209 off = (count | 0xf); /* for small counts, be more paranoid */ 210 if (off > (INT_MAX / (64*1024))) 211 off = (INT_MAX / (64*1024)); 212 current -= off * (64*1024); 213 if (current < 0) 214 current = 0; 215 xlseek(fd, current, SEEK_SET); 216 #endif 217 } 184 218 } 185 219 186 220 buf = tailbuf; 187 221 taillen = 0; 222 /* "We saw 1st line/byte". 223 * Used only by +N code ("start from Nth", 1-based): */ 188 224 seen = 1; 189 newline = 0; 190 191 while ((nread = tail_read(fds[i], buf, tailbufsize-taillen)) > 0) { 225 newlines_seen = 0; 226 while ((nread = tail_read(fd, buf, tailbufsize-taillen)) > 0) { 192 227 if (from_top) { 193 nwrite = nread;228 int nwrite = nread; 194 229 if (seen < count) { 230 /* We need to skip a few more bytes/lines */ 195 231 if (COUNT_BYTES) { 196 232 nwrite -= (count - seen); 197 233 seen = count; 198 234 } else { 199 s = buf;235 char *s = buf; 200 236 do { 201 237 --nwrite; … … 206 242 } 207 243 } 208 xwrite(STDOUT_FILENO, buf + nread - nwrite, nwrite); 244 if (nwrite > 0) 245 xwrite(STDOUT_FILENO, buf + nread - nwrite, nwrite); 209 246 } else if (count) { 210 247 if (COUNT_BYTES) { 211 248 taillen += nread; 212 if (taillen > count) {249 if (taillen > (int)count) { 213 250 memmove(tailbuf, tailbuf + taillen - count, count); 214 251 taillen = count; … … 216 253 } else { 217 254 int k = nread; 218 int n buf = 0;219 220 while (k) {221 --k;255 int newlines_in_buf = 0; 256 257 do { /* count '\n' in last read */ 258 k--; 222 259 if (buf[k] == '\n') { 223 ++nbuf;260 newlines_in_buf++; 224 261 } 225 } 226 227 if (newline + nbuf <count) {228 newline += nbuf;262 } while (k); 263 264 if (newlines_seen + newlines_in_buf < (int)count) { 265 newlines_seen += newlines_in_buf; 229 266 taillen += nread; 230 267 } else { 231 int extra = 0; 232 233 if (buf[nread-1] != '\n') 234 extra = 1; 235 k = newline + nbuf + extra - count; 268 int extra = (buf[nread-1] != '\n'); 269 char *s; 270 271 k = newlines_seen + newlines_in_buf + extra - count; 236 272 s = tailbuf; 237 273 while (k) { 238 274 if (*s == '\n') { 239 --k;275 k--; 240 276 } 241 ++s;277 s++; 242 278 } 243 279 taillen += nread - (s - tailbuf); 244 280 memmove(tailbuf, s, taillen); 245 newline = count - extra;246 } 247 if (tailbufsize < taillen + BUFSIZ) {281 newlines_seen = count - extra; 282 } 283 if (tailbufsize < (size_t)taillen + BUFSIZ) { 248 284 tailbufsize = taillen + BUFSIZ; 249 285 tailbuf = xrealloc(tailbuf, tailbufsize); … … 252 288 buf = tailbuf + taillen; 253 289 } 254 } 255 290 } /* while (tail_read() > 0) */ 256 291 if (!from_top) { 257 292 xwrite(STDOUT_FILENO, tailbuf, taillen); 258 293 } 259 260 taillen = 0;261 294 } while (++i < nfiles); 262 295 263 buf = xrealloc(tailbuf, BUFSIZ);296 tailbuf = xrealloc(tailbuf, BUFSIZ); 264 297 265 298 fmt = NULL; … … 267 300 if (FOLLOW) while (1) { 268 301 sleep(sleep_period); 302 269 303 i = 0; 270 304 do { 305 int nread; 306 const char *filename = argv[i]; 307 int fd = fds[i]; 308 309 if (FOLLOW_RETRY) { 310 struct stat sbuf, fsbuf; 311 312 if (fd < 0 313 || fstat(fd, &fsbuf) < 0 314 || stat(filename, &sbuf) < 0 315 || fsbuf.st_dev != sbuf.st_dev 316 || fsbuf.st_ino != sbuf.st_ino 317 ) { 318 int new_fd; 319 320 if (fd >= 0) 321 close(fd); 322 new_fd = open(filename, O_RDONLY); 323 if (new_fd >= 0) { 324 bb_error_msg("%s has %s; following end of new file", 325 filename, (fd < 0) ? "appeared" : "been replaced" 326 ); 327 } else if (fd >= 0) { 328 bb_perror_msg("%s has become inaccessible", filename); 329 } 330 fds[i] = fd = new_fd; 331 } 332 } 333 if (ENABLE_FEATURE_FANCY_TAIL && fd < 0) 334 continue; 271 335 if (nfiles > header_threshhold) { 272 fmt = header_fmt ;273 } 274 while ((nread = tail_read(fd s[i], buf, sizeof(buf))) > 0) {336 fmt = header_fmt_str; 337 } 338 while ((nread = tail_read(fd, tailbuf, BUFSIZ)) > 0) { 275 339 if (fmt) { 276 tail_xprint_header(fmt, argv[i]);340 tail_xprint_header(fmt, filename); 277 341 fmt = NULL; 278 342 } 279 xwrite(STDOUT_FILENO, buf, nread);343 xwrite(STDOUT_FILENO, tailbuf, nread); 280 344 } 281 345 } while (++i < nfiles); … … 283 347 if (ENABLE_FEATURE_CLEAN_UP) { 284 348 free(fds); 349 free(tailbuf); 285 350 } 286 351 return G.status;
Note:
See TracChangeset
for help on using the changeset viewer.