2 * collectd - src/utils_tail.c
3 * Copyright (C) 2007-2008 C-Ware, Inc.
4 * Copyright (C) 2008 Florian Forster
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; only version 2 of the License is applicable.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 * Luke Heberling <lukeh at c-ware.com>
21 * Florian Forster <octo at verplant.org>
24 * Encapsulates useful code for plugins which must watch for appends to
30 #include "utils_tail.h"
39 static int cu_tail_reopen (cu_tail_t *obj)
46 memset (&stat_buf, 0, sizeof (stat_buf));
47 status = stat (obj->file, &stat_buf);
51 ERROR ("utils_tail: stat (%s) failed: %s", obj->file,
52 sstrerror (errno, errbuf, sizeof (errbuf)));
56 /* The file is already open.. */
57 if ((obj->fh != NULL) && (stat_buf.st_ino == obj->stat.st_ino))
59 /* Seek to the beginning if file was truncated */
60 if (stat_buf.st_size < obj->stat.st_size)
62 INFO ("utils_tail: File `%s' was truncated.", obj->file);
63 status = fseek (obj->fh, 0, SEEK_SET);
67 ERROR ("utils_tail: fseek (%s) failed: %s", obj->file,
68 sstrerror (errno, errbuf, sizeof (errbuf)));
74 memcpy (&obj->stat, &stat_buf, sizeof (struct stat));
78 /* Seek to the end if we re-open the same file again or the file opened
79 * is the first at all or the first after an error */
80 if ((obj->stat.st_ino == 0) || (obj->stat.st_ino == stat_buf.st_ino))
83 fh = fopen (obj->file, "r");
87 ERROR ("utils_tail: fopen (%s) failed: %s", obj->file,
88 sstrerror (errno, errbuf, sizeof (errbuf)));
94 status = fseek (fh, 0, SEEK_END);
98 ERROR ("utils_tail: fseek (%s) failed: %s", obj->file,
99 sstrerror (errno, errbuf, sizeof (errbuf)));
108 memcpy (&obj->stat, &stat_buf, sizeof (struct stat));
111 } /* int cu_tail_reopen */
113 cu_tail_t *cu_tail_create (const char *file)
117 obj = (cu_tail_t *) malloc (sizeof (cu_tail_t));
120 memset (obj, '\0', sizeof (cu_tail_t));
122 obj->file = strdup (file);
123 if (obj->file == NULL)
132 } /* cu_tail_t *cu_tail_create */
134 int cu_tail_destroy (cu_tail_t *obj)
142 } /* int cu_tail_destroy */
144 int cu_tail_readline (cu_tail_t *obj, char *buf, int buflen)
150 ERROR ("utils_tail: cu_tail_readline: buflen too small: %i bytes.",
157 status = cu_tail_reopen (obj);
161 assert (obj->fh != NULL);
163 /* Try to read from the filehandle. If that succeeds, everything appears to
164 * be fine and we can return. */
166 if (fgets (buf, buflen, obj->fh) != NULL)
172 /* Check if we encountered an error */
173 if (ferror (obj->fh) != 0)
175 /* Jupp, error. Force `cu_tail_reopen' to reopen the file.. */
179 /* else: eof -> check if the file was moved away and reopen the new file if
182 status = cu_tail_reopen (obj);
183 /* error -> return with error */
186 /* file end reached and file not reopened -> nothing more to read */
193 /* If we get here: file was re-opened and there may be more to read.. Let's
195 if (fgets (buf, buflen, obj->fh) != NULL)
201 if (ferror (obj->fh) != 0)
204 WARNING ("utils_tail: fgets (%s) returned an error: %s", obj->file,
205 sstrerror (errno, errbuf, sizeof (errbuf)));
211 /* EOf, well, apparently the new file is empty.. */
214 } /* int cu_tail_readline */
216 int cu_tail_read (cu_tail_t *obj, char *buf, int buflen, tailfunc_t *callback,
225 status = cu_tail_readline (obj, buf, buflen);
228 ERROR ("utils_tail: cu_tail_read: cu_tail_readline "
239 if (buf[len - 1] != '\n')
244 status = callback (data, buf, buflen);
247 ERROR ("utils_tail: cu_tail_read: callback returned "
248 "status %i.", status);
254 } /* int cu_tail_read */