[gull] Tronquer des fichiers log

Marc Mongenet marc at mongenet.ch
Wed Jan 5 02:22:08 CET 2011


Le 4 janvier 2011 07:57, Frédéric Benninger <benninger at sunrise.ch> a écrit :
> Car il s’agit bien de garder une certaine quantité de données (ko ou
> nb lignes)  à partir de la fin d’un fichier en s’arrêtant à un saut de
> ligne.

Oui bien sûr, j'étais à coté de la plaque.
Du coup le programme en C devient plus compliqué...
J'ai fait ça:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

void usage(const char *argv0)
{
	fprintf(stderr, "%s lines files...\n", argv0);
	exit(1);
}

int get_prev_char(int fd, char *pc)
{
	if (lseek(fd, -1, SEEK_CUR) == -1) return -1;
	if (read(fd, pc, 1) == -1) return -1;
	if (lseek(fd, -1, SEEK_CUR) == -1) return -1;
	return 0;
}

int copy_end_to_start(int fd, off_t read_pos)
{
	off_t write_pos = 0;
	char c;
	ssize_t read_ret;
	while ((read_ret = read(fd, &c, 1)) == 1) {
		++read_pos;
		if (lseek(fd, write_pos, SEEK_SET) == -1) return -1;
		if (write(fd, &c, 1) != 1) return -1;
		++write_pos;
		if (lseek(fd, read_pos, SEEK_SET) == -1) return -1;
	}
	if (read_ret != 0) return -1;
	return 0;
}

void shrink(const char *fn, long lines)
{
	const int fd = open(fn, O_RDWR);
	if (fd == -1) goto error;
	const off_t fsize = lseek(fd, 0, SEEK_END);
	if (fsize == -1) goto error;
	off_t fpos = fsize;
	long count_lines = 0;
	while (fpos > 0 && count_lines <= lines) {
		char c;
		if (get_prev_char(fd, &c) == -1) goto error;
		--fpos;
		if (c == '\n' || count_lines == 0) ++count_lines;
	}
	if (fpos > 0) {
		if (lseek(fd, 1, SEEK_CUR) == -1) goto error;
		if (copy_end_to_start(fd, fpos + 1) == -1) goto error;
		if (ftruncate(fd, fsize - fpos - 1) == -1) goto error;
	}
	close(fd);
	return;
error:
	perror(fn);
	if (fd != -1) close(fd);
}

int main(int argc, char **argv)
{
	if (argc < 3) usage(argv[0]);
	
	char *endptr;
	const long lines = strtol(argv[1], &endptr, 10);
	if (*argv[1] == '\0' || *endptr != '\0' || lines < 0)
		usage(argv[0]);

	for (int i = 2; i < argc; ++i)
		shrink(argv[i], lines);

	return 0;
}


More information about the gull mailing list