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 * Solaris porting notes: the original FreeBSD version made use of the
35 * BSD kqueue event notification framework; this
36 * was changed to use usleep()
37 */
38
39 #include <sys/param.h>
40 #include <sys/mount.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <sys/statfs.h>
44 #include <sys/statvfs.h>
45 #include <sys/time.h>
46 #include <sys/mman.h>
47 #include <sys/poll.h>
48 #include <port.h>
49 #include <err.h>
50 #include <errno.h>
51 #include <fcntl.h>
52 #include <limits.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include <unistd.h>
57
58 #include "extern.h"
59
60 static void rlines(FILE *, const char *fn, off_t, struct stat *);
61 static int show(file_info_t *);
62 static void set_events(file_info_t *files);
63
64 /* defines for inner loop actions */
65 #define USE_SLEEP 0
66 #define ADD_EVENTS 2
67
68 int action = USE_SLEEP;
69
70 static const file_info_t *last;
71
72 /*
73 * forward -- display the file, from an offset, forward.
74 *
75 * There are eight separate cases for this -- regular and non-regular
76 * files, by bytes or lines and from the beginning or end of the file.
77 *
78 * FBYTES byte offset from the beginning of the file
79 * REG seek
80 * NOREG read, counting bytes
81 *
82 * FLINES line offset from the beginning of the file
83 * REG read, counting lines
84 * NOREG read, counting lines
85 *
86 * RBYTES byte offset from the end of the file
87 * REG seek
88 * NOREG cyclically read characters into a wrap-around buffer
244 if (!qflag)
245 (void) printf("\n==> %s <==\n",
246 file->file_name);
247 last = file;
248 }
249 if (putchar(ch) == EOF)
250 oerr();
251 }
252 (void) fflush(stdout);
253 if (ferror(file->fp)) {
254 (void) fclose(file->fp);
255 file->fp = NULL;
256 ierr(file->file_name);
257 return (0);
258 }
259 clearerr(file->fp);
260 return (1);
261 }
262
263 static void
264 set_events(file_info_t *files)
265 {
266 int i;
267 file_info_t *file;
268
269 for (i = 0, file = files; i < no_files; i++, file++) {
270 if (! file->fp)
271 continue;
272
273 (void) fstat(fileno(file->fp), &file->st);
274 }
275 }
276
277 /*
278 * follow -- display the file, from an offset, forward.
279 *
280 */
281 void
282 follow(file_info_t *files, enum STYLE style, off_t off)
283 {
284 int active, ev_change, i, n = -1;
285 struct stat sb2;
286 file_info_t *file;
287
288 /* Position each of the files */
289
290 file = files;
291 active = 0;
292 n = 0;
293 for (i = 0; i < no_files; i++, file++) {
294 if (file->fp) {
295 active = 1;
296 n++;
297 if (no_files > 1 && !qflag)
298 (void) printf("\n==> %s <==\n",
299 file->file_name);
300 forward(file->fp, file->file_name, style, off,
301 &file->st);
302 if (Fflag && fileno(file->fp) != STDIN_FILENO)
303 n++;
304 }
305 }
306 if (!Fflag && !active)
307 return;
308
309 last = --file;
310 set_events(files);
311
312 for (;;) {
313 ev_change = 0;
314 if (Fflag) {
315 for (i = 0, file = files; i < no_files; i++, file++) {
316 if (!file->fp) {
317 file->fp = fopen(file->file_name, "r");
318 if (file->fp != NULL &&
319 fstat(fileno(file->fp), &file->st)
320 == -1) {
321 (void) fclose(file->fp);
322 file->fp = NULL;
323 }
324 if (file->fp != NULL)
325 ev_change++;
326 continue;
327 }
328 if (fileno(file->fp) == STDIN_FILENO)
329 continue;
330 if (stat(file->file_name, &sb2) == -1) {
331 if (errno != ENOENT)
332 ierr(file->file_name);
333 (void) show(file);
334 (void) fclose(file->fp);
335 file->fp = NULL;
336 ev_change++;
337 continue;
338 }
339
340 if (sb2.st_ino != file->st.st_ino ||
341 sb2.st_dev != file->st.st_dev ||
342 sb2.st_nlink == 0) {
343 (void) show(file);
344 file->fp = freopen(file->file_name, "r",
345 file->fp);
346 if (file->fp != NULL)
347 (void) memcpy(&file->st, &sb2,
348 sizeof (struct stat));
349 else if (errno != ENOENT)
350 ierr(file->file_name);
351 ev_change++;
352 }
353 }
354 }
355
356 for (i = 0, file = files; i < no_files; i++, file++)
357 if (file->fp && !show(file))
358 ev_change++;
359
360 if (ev_change)
361 set_events(files);
362
363 switch (action) {
364 case USE_SLEEP:
365 (void) usleep(250000);
366 break;
367 }
368 }
369 }
|
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
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)
266 {
267 char buf[64];
268
269 if (action != USE_PORT || file->fp == NULL)
270 return;
271
272 if (!S_ISREG(file->st.st_mode)) {
273 /*
274 * For FIFOs, we use PORT_SOURCE_FD as our port event source.
275 */
276 if (assoc) {
277 (void) port_associate(port, PORT_SOURCE_FD,
278 fileno(file->fp), POLLIN, file);
279 } else {
280 (void) port_dissociate(port, PORT_SOURCE_FD,
281 fileno(file->fp));
282 }
283
284 return;
285 }
286
287 bzero(&file->fobj, sizeof (file->fobj));
288
289 /*
290 * We pull a bit of a stunt here. PORT_SOURCE_FILE only allows us to
291 * specify a file name -- not a file descriptor. If we were to specify
292 * the name of the file to port_associate() and that file were moved
293 * aside, we would not be able to reassociate an event because we would
294 * not know a name that would resolve to the new file (indeed, there
295 * might not be such a name -- the file may have been unlinked). But
296 * there _is_ a name that we know maps to the file and doesn't change:
297 * the name of the representation of the open file descriptor in /proc.
298 * We therefore associate with this name (and the underlying file),
299 * not the name of the file as specified at the command line.
300 */
301 (void) snprintf(buf,
302 sizeof (buf), "/proc/self/fd/%d", fileno(file->fp));
303
304 /*
305 * Note that portfs uses the address of the specified file_obj_t to
306 * tag an association; if one creates a different association with a
307 * (different) file_ob_t that happens to be at the same address,
308 * the first association will be implicitly removed. To assure that
309 * each file has a disjoint file_obj_t, we allocate the memory for it
310 * in the file_info, not on the stack.
311 */
312 file->fobj.fo_name = buf;
313
314 if (assoc) {
315 (void) port_associate(port, PORT_SOURCE_FILE,
316 (uintptr_t)&file->fobj, FILE_MODIFIED | FILE_TRUNC, file);
317 } else {
318 (void) port_dissociate(port, PORT_SOURCE_FILE,
319 (uintptr_t)&file->fobj);
320 }
321 }
322
323 static void
324 set_events(file_info_t *files)
325 {
326 int i;
327 file_info_t *file;
328
329 for (i = 0, file = files; i < no_files; i++, file++) {
330 if (! file->fp)
331 continue;
332
333 (void) fstat(fileno(file->fp), &file->st);
334
335 associate(file, B_TRUE);
336 }
337 }
338
339 /*
340 * follow -- display the file, from an offset, forward.
341 *
342 */
343 void
344 follow(file_info_t *files, enum STYLE style, off_t off)
345 {
346 int active, ev_change, i, n = -1;
347 struct stat sb2;
348 file_info_t *file;
349 struct timespec ts;
350 port_event_t ev;
351
352 /* Position each of the files */
353
354 file = files;
355 active = 0;
356 n = 0;
357 for (i = 0; i < no_files; i++, file++) {
358 if (file->fp) {
359 active = 1;
360 n++;
361 if (no_files > 1 && !qflag)
362 (void) printf("\n==> %s <==\n",
363 file->file_name);
364 forward(file->fp, file->file_name, style, off,
365 &file->st);
366 if (Fflag && fileno(file->fp) != STDIN_FILENO)
367 n++;
368 }
369 }
370 if (!Fflag && !active)
371 return;
372
373 last = --file;
374
375 if (action == USE_PORT &&
376 (stat("/proc/self/fd", &sb2) == -1 || !S_ISDIR(sb2.st_mode) ||
377 (port = port_create()) == -1))
378 action = USE_SLEEP;
379
380 set_events(files);
381
382 for (;;) {
383 ev_change = 0;
384 if (Fflag) {
385 for (i = 0, file = files; i < no_files; i++, file++) {
386 if (!file->fp) {
387 file->fp = fopen(file->file_name, "r");
388 if (file->fp != NULL &&
389 fstat(fileno(file->fp), &file->st)
390 == -1) {
391 (void) fclose(file->fp);
392 file->fp = NULL;
393 }
394 if (file->fp != NULL)
395 ev_change++;
396 continue;
397 }
398 if (fileno(file->fp) == STDIN_FILENO)
399 continue;
400 if (stat(file->file_name, &sb2) == -1) {
401 if (errno != ENOENT)
402 ierr(file->file_name);
403 (void) show(file);
404 (void) fclose(file->fp);
405 file->fp = NULL;
406 ev_change++;
407 continue;
408 }
409
410 if (sb2.st_ino != file->st.st_ino ||
411 sb2.st_dev != file->st.st_dev ||
412 sb2.st_nlink == 0) {
413 (void) show(file);
414 associate(file, B_FALSE);
415 file->fp = freopen(file->file_name, "r",
416 file->fp);
417 if (file->fp != NULL) {
418 (void) memcpy(&file->st, &sb2,
419 sizeof (struct stat));
420 } else if (errno != ENOENT)
421 ierr(file->file_name);
422 ev_change++;
423 }
424 }
425 }
426
427 for (i = 0, file = files; i < no_files; i++, file++)
428 if (file->fp && !show(file))
429 ev_change++;
430
431 if (ev_change)
432 set_events(files);
433
434 switch (action) {
435 case USE_PORT:
436 ts.tv_sec = 1;
437 ts.tv_nsec = 0;
438
439 /*
440 * In the -F case we set a timeout to ensure that
441 * we re-stat the file at least once every second.
442 */
443 n = port_get(port, &ev, Fflag ? &ts : NULL);
444
445 if (n == 0) {
446 file = (file_info_t *)ev.portev_user;
447 associate(file, B_TRUE);
448
449 if (ev.portev_events & FILE_TRUNC)
450 (void) fseek(file->fp, 0, SEEK_SET);
451 }
452
453 break;
454
455 case USE_SLEEP:
456 (void) usleep(250000);
457 break;
458 }
459 }
460 }
|