summaryrefslogtreecommitdiff
path: root/inotail-old.c
diff options
context:
space:
mode:
authorTobias Klauser <tklauser@xenon.tklauser.home>2006-08-13 18:13:14 +0200
committerTobias Klauser <tklauser@xenon.tklauser.home>2006-08-13 18:13:14 +0200
commit34c081433e21442af1e0f0ab336cd0d778d9d3ed (patch)
treeac992e056878cf61134aa6ddac7f253f9aa5e326 /inotail-old.c
parent2e402599bfb4c4e97a8f6f8b0910783c7a693aaf (diff)
Delete inotail-old.c
Diffstat (limited to 'inotail-old.c')
-rw-r--r--inotail-old.c389
1 files changed, 0 insertions, 389 deletions
diff --git a/inotail-old.c b/inotail-old.c
deleted file mode 100644
index 520a2ad..0000000
--- a/inotail-old.c
+++ /dev/null
@@ -1,389 +0,0 @@
-/*
- * inotail-old.c
- * A fast implementation of GNU tail which uses the inotify-API present in
- * recent Linux Kernels.
- *
- * Copyright (C) 2005-2006, Tobias Klauser <tklauser@distanz.ch>
- *
- * Parts of this program are based on GNU tail included in the GNU coreutils
- * which is:
- * Copyright (C) 1989, 90, 91, 1995-2005 Free Software Foundation, Inc.
- *
- * The idea and some code were taken from turbotail.
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 51
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#define _GNU_SOURCE
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <stdarg.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <inttypes.h>
-#include <string.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/syscall.h>
-
-#include "inotify.h"
-#include "inotify-syscalls.h"
-
-#include "inotail.h"
-
-#define VERSION "0.1"
-
-/* XXX: Move all global variables into a struct and use :1 */
-
-/* If !=0, read from the ends of all specified files until killed. */
-static unsigned short forever;
-
-/* Print header with filename before tailing the file? */
-static unsigned short print_headers = 0;
-
-/* Say my name! */
-static char *program_name = "inotail";
-
-static int dump_remainder(const char *filename, int fd, ssize_t n_bytes)
-{
- ssize_t written = 0;
-
- dprintf("==> dump_remainder()\n");
-
- if (n_bytes > SSIZE_MAX)
- n_bytes = SSIZE_MAX;
-
- return written;
-}
-
-static char *pretty_name(const struct file_struct *f)
-{
- return ((strcmp(f->name, "-") == 0) ? "standard input" : f->name);
-}
-
-static void write_header(const struct file_struct *f)
-{
- static unsigned short first_file = 1;
-
- fprintf (stdout, "%s==> %s <==\n", (first_file ? "" : "\n"), pretty_name(f));
- first_file = 0;
-}
-
-static int file_lines(struct file_struct *f, uintmax_t n_lines, off_t start_pos, off_t end_pos)
-{
- char buffer[BUFSIZ];
- size_t bytes_read;
- off_t pos = end_pos;
-
- dprintf("==> file_lines()\n");
-
- if (n_lines == 0)
- return 1;
-
- dprintf(" start_pos: %lld\n", (unsigned long long) start_pos);
- dprintf(" end_pos: %lld\n", (unsigned long long) end_pos);
-
- /* Set `bytes_read' to the size of the last, probably partial, buffer;
- * 0 < `bytes_read' <= `BUFSIZ'.
- */
- bytes_read = (pos - start_pos) % BUFSIZ;
- if (bytes_read == 0)
- bytes_read = BUFSIZ;
-
- dprintf(" bytes_read: %zd\n", bytes_read);
-
- /* Make `pos' a multiple of `BUFSIZ' (0 if the file is short), so that
- * all
- * reads will be on block boundaries, which might increase
- * efficiency. */
- pos -= bytes_read;
-
- dprintf(" pos: %lld\n", pos);
-
- lseek(f->fd, pos, SEEK_SET);
- bytes_read = read(f->fd, buffer, bytes_read);
-
- /* Count the incomplete line on files that don't end with a newline. */
- if (bytes_read && buffer[bytes_read - 1] != '\n')
- --n_lines;
-
- do {
- size_t n = bytes_read;
- while (n) {
- const char *nl;
- nl = memrchr(buffer, '\n', n);
- if (nl == NULL)
- break;
- }
-
- /* XXX XXX XXX XXX */
-
- /* Not enough newlines in that buffer. Just print everything */
- if (pos == start_pos) {
- lseek(f->fd, start_pos, SEEK_SET);
- return 1;
- }
- pos -= BUFSIZ;
- } while (bytes_read > 0);
-
- return 1;
-}
-
-static void check_file(struct file_struct *f)
-{
- struct stat new_stats;
-
- dprintf("==> check_file()\n");
-
- dprintf(" checking '%s'\n", f->name);
-}
-
-static int tail_forever(struct file_struct *f, int n_files)
-{
- int i_fd, len;
- unsigned int i;
- struct inotify_event *inev;
- char buf[1000];
-
- dprintf("==> tail_forever()\n");
-
- i_fd = inotify_init();
- if (i_fd < 0)
- return -1;
-
- for (i = 0; i < n_files; i++) {
- f[i].i_watch = inotify_add_watch(i_fd, f[i].name, IN_ALL_EVENTS | IN_UNMOUNT);
- dprintf(" Watch (%d) added to '%s' (%d)\n", f[i].i_watch, f[i].name, i);
- }
-
- memset(&buf, 0, sizeof(buf));
-
- while (1) {
- int fd;
- ssize_t bytes_tailed = 0;
-
- len = read(i_fd, buf, sizeof(buf));
- inev = (struct inotify_event *) &buf;
-
- while (len > 0) {
- struct file_struct *fil;
-
- /* Which file has produced the event? */
- for (i = 0; i < n_files; i++) {
- if (!f[i].ignore && f[i].fd >= 0 && f[i].i_watch == inev->wd) {
- fil = &f[i];
- break;
- }
- }
-
- /* We should at least catch the following
- * events:
- * - IN_MODIFY, thats what we hopefully get
- * most of the time
- * - IN_ATTRIB, still readable?
- * - IN_MOVE, reopen the file at the new
- * position?
- * - IN_DELETE_SELF, we need to check if the
- * file is still there or is really gone
- * - IN_MOVE_SELF, ditto
- * - IN_UNMOUNT, die gracefully
- */
- if (inev->mask & IN_MODIFY) {
- dprintf(" File '%s' modified.\n", fil->name);
- check_file(fil);
- /* Dump new content */
- } else if (inev->mask & IN_ATTRIB) {
- dprintf(" File '%s' attributes changed.\n", fil->name);
- check_file(fil);
- } else if (inev->mask & IN_MOVE) {
- } else if (inev->mask & IN_DELETE_SELF) {
- dprintf(" File '%s' possibly deleted.\n", fil->name);
- check_file(fil);
- } else {
- /* Ignore */
- }
-
- /* Shift one event forward */
- len -= sizeof(struct inotify_event) + inev->len;
- inev = (struct inotify_event *) ((char *) inev + sizeof(struct inotify_event) + inev->len);
- }
- }
-
- /* XXX: Never reached. Catch SIGINT and handle it there? */
- for (i = 0; i < n_files; i++)
- inotify_rm_watch(i_fd, f[i].i_watch);
-
- return 0;
-}
-
-static int tail_lines(struct file_struct *f, uintmax_t n_lines)
-{
- struct stat stats;
- off_t start_pos = -1;
- off_t end_pos;
-
- dprintf("==> tail_lines()\n");
-
- if (fstat(f->fd, &stats)) {
- perror("fstat()");
- exit(EXIT_FAILURE);
- }
-
- start_pos = lseek(f->fd, 0, SEEK_CUR);
- end_pos = lseek(f->fd, 0, SEEK_END);
-
- /* Use file_lines only if FD refers to a regular file for
- * which lseek(... SEEK_END) worked.
- */
- if (S_ISREG(stats.st_mode) && start_pos != -1 && start_pos < end_pos) {
- if (end_pos != 0 && !file_lines(f, n_lines, start_pos, end_pos))
- return -1;
- } else {
- /* Under very unlikely circumstances, it is possible to reach
- this point after positioning the file pointer to end of file
- via the `lseek (...SEEK_END)' above. In that case, reposition
- the file pointer back to start_pos before calling pipe_lines. */
-/* if (start_pos != -1)
- xlseek (fd, start_pos, SEEK_SET, pretty_filename);
-
- return pipe_lines (pretty_filename, fd, n_lines, read_pos);
-*/
- }
-
- return 0;
-}
-
-static int tail(struct file_struct *f, uintmax_t n_units)
-{
- dprintf("==> tail()\n");
-
- return tail_lines(f, n_units);
-}
-
-static int tail_file(struct file_struct *f, uintmax_t n_units)
-{
- int ret = 0;
-
- dprintf("==> tail_file()\n");
-
- if (strcmp(f->name, "-") == 0) {
- f->fd = STDIN_FILENO;
- } else {
- f->fd = open(f->name, O_RDONLY);
- }
-
- if (f->fd == -1) {
- perror("open()");
- } else {
- if (print_headers)
- write_header(f);
- ret = tail(f, n_units);
- }
-
- return ret;
-}
-
-static void usage(void)
-{
- dprintf("==> usage()\n");
-
- fprintf(stderr, "Usage: %s [OPTION]... [FILE]...\n", program_name);
-}
-
-static void parse_options(int argc, char *argv[], int *n_lines)
-{
- int c;
-
- dprintf("==> parse_options()\n");
-
- while ((c = getopt_long(argc, argv, "hfn:qvV", long_options, NULL)) != -1) {
- switch (c) {
- case 'f':
- forever = 1;
- break;
- case 'n':
- *n_lines = strtol(optarg, NULL, 0);
- if (*n_lines < 0)
- *n_lines = 0;
- break;
- case 'q':
- print_headers = 0;
- break;
- case 'v':
- print_headers = 1;
- break;
- case 'V':
- fprintf(stdout, "%s %s by Tobias Klauser <tklauser@distanz.ch>\n",
- program_name, VERSION);
- break;
- case 'h':
- default:
- usage();
- }
- }
-}
-
-int main(int argc, char *argv[])
-{
- int n_files = 0;
- int n_lines = DEFAULT_N_LINES;
- struct file_struct *files;
- char **filenames;
- unsigned int i;
-
- parse_options(argc, argv, &n_lines);
-
- /* Do we have some files to read from? */
- if (optind < argc) {
- n_files = argc - optind;
- filenames = argv + optind;
- } else { /* OK, we read from stdin */
- static char *dummy_stdin = "-";
-
- n_files = 1;
- filenames = &dummy_stdin;
-
- /*
- * POSIX says that -f is ignored if no file operand is specified
- * and standard input is a pipe.
- */
- if (forever) {
- struct stat stats;
- /* stdin might be a socket on some systems */
- if ((fstat(STDIN_FILENO, &stats) == 0)
- && (S_ISFIFO(stats.st_mode) || S_ISSOCK(stats.st_mode)))
- forever = 0;
- }
-
- fprintf(stderr, "Reading from stdin is currently not supported.\n");
- }
-
- files = malloc(n_files * sizeof(struct file_struct));
- for (i = 0; i < n_files; i++) {
- files[i].name = filenames[i];
- tail_file(&files[i], n_lines);
- }
-
- if (forever)
- tail_forever(files, n_files);
-
- free(files);
-
- exit(EXIT_SUCCESS);
-}