Интересным в этих восстановленных файлах является то, что первые 128 КБ или около того будут равны нулю после того, как вы обрежете файл, скопировав /dev/null
поверх него. Это происходит потому, что файл усекается до нулевой длины, но дескриптор файла в приложении по-прежнему указывает сразу после последней записи. Когда он записывает снова, файловая система рассматривает начало файла как все нулевые байты - без фактической записи нулей на диск.
В идеале вам следует попросить поставщика приложения открыть файл журнала с флагом O_APPEND
. Это означает, что после усечения файла при следующей записи неявным образом будет выполняться поиск конца файла (что означает возврат к нулевому смещению), а затем записываться новая информация.
Этот код настраивает стандартный вывод, поэтому он находится в режиме O_APPEND
, а затем вызывает команду, заданную его аргументами (скорее, как nice
запускает команду после настройки ее уровня nice, или nohup
запускает команду после исправления вещи, поэтому он игнорирует SIGHUP).
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
static char *arg0 = "<unknown>";
static void error(const char *fmt, ...)
{
va_list args;
int errnum = errno;
fprintf(stderr, "%s: ", arg0);
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
if (errnum != 0)
fprintf(stderr, " (%d: %s)", errnum, strerror(errnum));
putc('\n', stderr);
fflush(0);
exit(1);
}
int main(int argc, char **argv)
{
int attr;
arg0 = argv[0];
if (argc < 2)
error("Usage: %s cmd [arg ...]", arg0);
if ((attr = fcntl(1, F_GETFL, &attr)) < 0)
error("fcntl(F_GETFL) failed");
attr |= O_APPEND;
if (fcntl(1, F_SETFL, attr) != 0)
error("fcntl(F_SETFL) failed");
execvp(argv[1], &argv[1]);
error("failed to exec %s", argv[1]);
return(1);
}
Мое тестирование было несколько случайным, но едва достаточным, чтобы убедить меня, что это сработало.
Более простая альтернатива
Билли отмечает в своем ответе , что '>>
' является оператором добавления - и действительно, в Solaris 10 bash (версия 3.00.16 (1)) использует флаг O_APPEND
- что делает приведенный выше код ненужным, как показано («Black JL:» - это мое приглашение на этом компьютере):
Black JL: truss -o bash.truss bash -c "echo Hi >> x3.29"
Black JL: grep open bash.truss
open("/var/ld/ld.config", O_RDONLY) Err#2 ENOENT
open("/usr/lib/libcurses.so.1", O_RDONLY) = 3
open("/usr/lib/libsocket.so.1", O_RDONLY) = 3
open("/usr/lib/libnsl.so.1", O_RDONLY) = 3
open("/usr/lib/libdl.so.1", O_RDONLY) = 3
open("/usr/lib/libc.so.1", O_RDONLY) = 3
open("/platform/SUNW,Ultra-4/lib/libc_psr.so.1", O_RDONLY) = 3
open64("/dev/tty", O_RDWR|O_NONBLOCK) = 3
stat64("/usr/openssl/v0.9.8e/bin/bash", 0xFFBFF2A8) Err#2 ENOENT
open64("x3.29", O_WRONLY|O_APPEND|O_CREAT, 0666) = 3
Black JL:
Используйте перенаправление добавления, а не код обертки (' cantrip ') выше. Это просто говорит о том, что когда вы используете одну конкретную технику для других (допустимых) целей, адаптация ее к другой не обязательно является самым простым механизмом - даже если он работает.