1 /* 2 * Copyright (c) 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Edward Sze-Tyan Wang. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 4. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 /* 34 * Copyright (c) 2013, Joyent, Inc. All rights reserved. 35 */ 36 37 #include <sys/param.h> 38 #include <sys/mount.h> 39 #include <sys/types.h> 40 #include <sys/stat.h> 41 #include <sys/statfs.h> 42 #include <sys/statvfs.h> 43 #include <sys/time.h> 44 #include <sys/mman.h> 45 #include <sys/poll.h> 46 #include <port.h> 47 #include <err.h> 48 #include <errno.h> 49 #include <fcntl.h> 50 #include <limits.h> 51 #include <stdio.h> 52 #include <stdlib.h> 53 #include <string.h> 54 #include <strings.h> 55 #include <unistd.h> 56 57 #include "extern.h" 58 59 static void rlines(FILE *, const char *fn, off_t, struct stat *); 60 static int show(file_info_t *); 61 static void set_events(file_info_t *files); 62 63 /* defines for inner loop actions */ 64 #define USE_SLEEP 0 65 #define USE_PORT 1 66 #define ADD_EVENTS 2 67 68 int port; 69 int action = USE_PORT; 70 71 static const file_info_t *last; 72 73 /* 74 * forward -- display the file, from an offset, forward. 75 * 76 * There are eight separate cases for this -- regular and non-regular 77 * files, by bytes or lines and from the beginning or end of the file. 78 * 79 * FBYTES byte offset from the beginning of the file 80 * REG seek 81 * NOREG read, counting bytes 82 * 83 * FLINES line offset from the beginning of the file 84 * REG read, counting lines 85 * NOREG read, counting lines 86 * 87 * RBYTES byte offset from the end of the file 88 * REG seek 89 * NOREG cyclically read characters into a wrap-around buffer 90 * 91 * RLINES 92 * REG mmap the file and step back until reach the correct offset. 93 * NOREG cyclically read lines into a wrap-around array of buffers 94 */ 95 void 96 forward(FILE *fp, const char *fn, enum STYLE style, off_t off, struct stat *sbp) 97 { 98 int ch; 99 100 switch (style) { 101 case FBYTES: 102 if (off == 0) 103 break; 104 if (S_ISREG(sbp->st_mode)) { 105 if (sbp->st_size < off) 106 off = sbp->st_size; 107 if (fseeko(fp, off, SEEK_SET) == -1) { 108 ierr(fn); 109 return; 110 } 111 } else while (off--) 112 if ((ch = getc(fp)) == EOF) { 113 if (ferror(fp)) { 114 ierr(fn); 115 return; 116 } 117 break; 118 } 119 break; 120 case FLINES: 121 if (off == 0) 122 break; 123 for (;;) { 124 if ((ch = getc(fp)) == EOF) { 125 if (ferror(fp)) { 126 ierr(fn); 127 return; 128 } 129 break; 130 } 131 if (ch == '\n' && !--off) 132 break; 133 } 134 break; 135 case RBYTES: 136 if (S_ISREG(sbp->st_mode)) { 137 if (sbp->st_size >= off && 138 fseeko(fp, -off, SEEK_END) == -1) { 139 ierr(fn); 140 return; 141 } 142 } else if (off == 0) { 143 while (getc(fp) != EOF) 144 ; 145 if (ferror(fp)) { 146 ierr(fn); 147 return; 148 } 149 } else 150 if (bytes(fp, fn, off)) 151 return; 152 break; 153 case RLINES: 154 if (S_ISREG(sbp->st_mode)) 155 if (!off) { 156 if (fseeko(fp, (off_t)0, SEEK_END) == -1) { 157 ierr(fn); 158 return; 159 } 160 } else 161 rlines(fp, fn, off, sbp); 162 else if (off == 0) { 163 while (getc(fp) != EOF) 164 ; 165 if (ferror(fp)) { 166 ierr(fn); 167 return; 168 } 169 } else 170 if (lines(fp, fn, off)) 171 return; 172 break; 173 default: 174 break; 175 } 176 177 while ((ch = getc(fp)) != EOF) 178 if (putchar(ch) == EOF) 179 oerr(); 180 if (ferror(fp)) { 181 ierr(fn); 182 return; 183 } 184 (void) fflush(stdout); 185 } 186 187 /* 188 * rlines -- display the last offset lines of the file. 189 */ 190 static void 191 rlines(FILE *fp, const char *fn, off_t off, struct stat *sbp) 192 { 193 struct mapinfo map; 194 off_t curoff, size; 195 int i; 196 197 if ((size = sbp->st_size) == 0) 198 return; 199 map.start = NULL; 200 map.fd = fileno(fp); 201 map.mapoff = map.maxoff = size; 202 203 /* 204 * Last char is special, ignore whether newline or not. Note that 205 * size == 0 is dealt with above, and size == 1 sets curoff to -1. 206 */ 207 curoff = size - 2; 208 while (curoff >= 0) { 209 if (curoff < map.mapoff && maparound(&map, curoff) != 0) { 210 ierr(fn); 211 return; 212 } 213 for (i = curoff - map.mapoff; i >= 0; i--) 214 if (map.start[i] == '\n' && --off == 0) 215 break; 216 /* `i' is either the map offset of a '\n', or -1. */ 217 curoff = map.mapoff + i; 218 if (i >= 0) 219 break; 220 } 221 curoff++; 222 if (mapprint(&map, curoff, size - curoff) != 0) { 223 ierr(fn); 224 exit(1); 225 } 226 227 /* Set the file pointer to reflect the length displayed. */ 228 if (fseeko(fp, sbp->st_size, SEEK_SET) == -1) { 229 ierr(fn); 230 return; 231 } 232 if (map.start != NULL && munmap(map.start, map.maplen)) { 233 ierr(fn); 234 return; 235 } 236 } 237 238 static int 239 show(file_info_t *file) 240 { 241 int ch; 242 243 while ((ch = getc(file->fp)) != EOF) { 244 if (last != file && no_files > 1) { 245 if (!qflag) 246 (void) printf("\n==> %s <==\n", 247 file->file_name); 248 last = file; 249 } 250 if (putchar(ch) == EOF) 251 oerr(); 252 } 253 (void) fflush(stdout); 254 if (ferror(file->fp)) { 255 (void) fclose(file->fp); 256 file->fp = NULL; 257 ierr(file->file_name); 258 return (0); 259 } 260 clearerr(file->fp); 261 return (1); 262 } 263 264 static void 265 associate(file_info_t *file, boolean_t assoc, port_event_t *ev) 266 { 267 char buf[64], *name; 268 int i; 269 270 if (action != USE_PORT || file->fp == NULL) 271 return; 272 273 if (!S_ISREG(file->st.st_mode)) { 274 /* 275 * For FIFOs, we use PORT_SOURCE_FD as our port event source. 276 */ 277 if (assoc) { 278 (void) port_associate(port, PORT_SOURCE_FD, 279 fileno(file->fp), POLLIN, file); 280 } else { 281 (void) port_dissociate(port, PORT_SOURCE_FD, 282 fileno(file->fp)); 283 } 284 285 return; 286 } 287 288 bzero(&file->fobj, sizeof (file->fobj)); 289 290 if (!Fflag) { 291 /* 292 * PORT_SOURCE_FILE only allows us to specify a file name, not 293 * a file descriptor. If we are following a specific file (as 294 * opposed to a file name) and we were to specify the name of 295 * the file to port_associate() and that file were moved 296 * aside, we would not be able to reassociate an event because 297 * we would not know a name that would resolve to the new file 298 * (indeed, there might not be such a name -- the file may 299 * have been unlinked). But there _is_ a name that we know 300 * maps to the file and doesn't change: the name of the 301 * representation of the open file descriptor in /proc. We 302 * therefore associate with this name (and the underlying 303 * file), not the name of the file as specified at the command 304 * line. This also has the (desirable) side-effect of 305 * insulating against FILE_RENAME_FROM and FILE_RENAME_TO 306 * events that we need to ignore to assure that we don't lose 307 * FILE_TRUNC events. 308 */ 309 (void) snprintf(buf, 310 sizeof (buf), "/proc/self/fd/%d", fileno(file->fp)); 311 name = buf; 312 } else { 313 name = file->file_name; 314 } 315 316 /* 317 * Note that portfs uses the address of the specified file_obj_t to 318 * tag an association; if one creates a different association with a 319 * (different) file_obj_t that happens to be at the same address, 320 * the first association will be implicitly removed. To assure that 321 * each association has a disjoint file_obj_t, we allocate the memory 322 * for each in the file_info, not on the stack. 323 */ 324 file->fobj[0].fo_name = name; 325 file->fobj[1].fo_name = name; 326 327 if (assoc) { 328 /* 329 * To assure that we cannot possibly drop a FILE_TRUNC event, 330 * we have two different PORT_SOURCE_FILE associations with the 331 * port: one to get only FILE_MODIFIED events and another to 332 * get only FILE_TRUNC events. This assures that we always 333 * have an active association for FILE_TRUNC events when the 334 * seek offset is non-zero. Note that the association order 335 * _must_ be FILE_TRUNC followed by FILE_MODIFIED: if a single 336 * event induces both a FILE_TRUNC and a FILE_MODIFIED (as 337 * a VE_CREATE vnode event does), we must process the 338 * FILE_TRUNC before FILE_MODIFIED -- and the order in which 339 * these are processed will be the association order. So 340 * if we see a FILE_TRUNC, we dissociate/reassociate the 341 * FILE_MODIFIED association. 342 */ 343 if (ev == NULL || (ev->portev_events & FILE_TRUNC) || 344 !(ev->portev_events & (FILE_MODIFIED | FILE_TRUNC))) { 345 (void) port_associate(port, PORT_SOURCE_FILE, 346 (uintptr_t)&file->fobj[0], FILE_TRUNC, file); 347 (void) port_dissociate(port, PORT_SOURCE_FILE, 348 (uintptr_t)&file->fobj[1]); 349 ev = NULL; 350 } 351 352 if (ev == NULL || (ev->portev_events & FILE_MODIFIED) || 353 !(ev->portev_events & (FILE_MODIFIED | FILE_TRUNC))) { 354 (void) port_associate(port, PORT_SOURCE_FILE, 355 (uintptr_t)&file->fobj[1], FILE_MODIFIED, file); 356 } 357 } else { 358 for (i = 0; i <= 1; i++) { 359 (void) port_dissociate(port, PORT_SOURCE_FILE, 360 (uintptr_t)&file->fobj[i]); 361 } 362 } 363 } 364 365 static void 366 set_events(file_info_t *files) 367 { 368 int i; 369 file_info_t *file; 370 371 for (i = 0, file = files; i < no_files; i++, file++) { 372 if (! file->fp) 373 continue; 374 375 (void) fstat(fileno(file->fp), &file->st); 376 377 associate(file, B_TRUE, NULL); 378 } 379 } 380 381 /* 382 * follow -- display the file, from an offset, forward. 383 * 384 */ 385 void 386 follow(file_info_t *files, enum STYLE style, off_t off) 387 { 388 int active, ev_change, i, n = -1; 389 struct stat sb2; 390 file_info_t *file; 391 struct timespec ts; 392 port_event_t ev; 393 394 /* Position each of the files */ 395 396 file = files; 397 active = 0; 398 n = 0; 399 for (i = 0; i < no_files; i++, file++) { 400 if (file->fp) { 401 active = 1; 402 n++; 403 if (no_files > 1 && !qflag) 404 (void) printf("\n==> %s <==\n", 405 file->file_name); 406 forward(file->fp, file->file_name, style, off, 407 &file->st); 408 if (Fflag && fileno(file->fp) != STDIN_FILENO) 409 n++; 410 } 411 } 412 if (!Fflag && !active) 413 return; 414 415 last = --file; 416 417 if (action == USE_PORT && 418 (stat("/proc/self/fd", &sb2) == -1 || !S_ISDIR(sb2.st_mode) || 419 (port = port_create()) == -1)) 420 action = USE_SLEEP; 421 422 set_events(files); 423 424 for (;;) { 425 ev_change = 0; 426 if (Fflag) { 427 for (i = 0, file = files; i < no_files; i++, file++) { 428 if (!file->fp) { 429 file->fp = fopen(file->file_name, "r"); 430 if (file->fp != NULL && 431 fstat(fileno(file->fp), &file->st) 432 == -1) { 433 (void) fclose(file->fp); 434 file->fp = NULL; 435 } 436 if (file->fp != NULL) 437 ev_change++; 438 continue; 439 } 440 if (fileno(file->fp) == STDIN_FILENO) 441 continue; 442 if (stat(file->file_name, &sb2) == -1) { 443 if (errno != ENOENT) 444 ierr(file->file_name); 445 (void) show(file); 446 (void) fclose(file->fp); 447 file->fp = NULL; 448 ev_change++; 449 continue; 450 } 451 452 if (sb2.st_ino != file->st.st_ino || 453 sb2.st_dev != file->st.st_dev || 454 sb2.st_nlink == 0) { 455 (void) show(file); 456 associate(file, B_FALSE, NULL); 457 file->fp = freopen(file->file_name, "r", 458 file->fp); 459 if (file->fp != NULL) { 460 (void) memcpy(&file->st, &sb2, 461 sizeof (struct stat)); 462 } else if (errno != ENOENT) 463 ierr(file->file_name); 464 ev_change++; 465 } 466 } 467 } 468 469 for (i = 0, file = files; i < no_files; i++, file++) 470 if (file->fp && !show(file)) 471 ev_change++; 472 473 if (ev_change) 474 set_events(files); 475 476 switch (action) { 477 case USE_PORT: 478 ts.tv_sec = 1; 479 ts.tv_nsec = 0; 480 481 /* 482 * In the -F case we set a timeout to ensure that 483 * we re-stat the file at least once every second. 484 */ 485 n = port_get(port, &ev, Fflag ? &ts : NULL); 486 487 if (n == 0) { 488 file = (file_info_t *)ev.portev_user; 489 associate(file, B_TRUE, &ev); 490 491 if (ev.portev_events & FILE_TRUNC) 492 (void) fseek(file->fp, 0, SEEK_SET); 493 } 494 495 break; 496 497 case USE_SLEEP: 498 (void) usleep(250000); 499 break; 500 } 501 } 502 } 503