интересная задачка для FreeBSD guru
Подцепиться дебаггером к демону, и execнуть это программу, дав ей дескриптор как аргумент. На случай если демон на свои декскрипторы ставит FD_CLOEXEC, то вероятно придётся сделать dup либо убрать CLOEXEC.
В Linux есть стандартный способ?
через /proc/<pid>/fd/<desc> можно доступ получить
Написать программу, которая вызывается с одним аргументом, который считает файловым дескриптором fd. Она делает lseek(fd,0 открывает новый файл и записывает в него всё содержимое fd.Тестовый демон:
Подцепиться дебаггером к демону, и execнуть это программу, дав ей дескриптор как аргумент. На случай если демон на свои декскрипторы ставит FD_CLOEXEC, то вероятно придётся сделать dup либо убрать CLOEXEC.
#include <sys/stat.h>
#include <err.h>
#include <fcntl.h>
#include <time.h>
#include <unistd.h>
#define BUFSZ 64
int
main(int argc, char **argv)
{
char buf[BUFSZ];
time_t tm;
int fd;
fd = open("a_file_to_be_unlinked", O_RDWR | O_TRUNC | O_CREAT,
DEFFILEMODE);
if (fd < 0)
err(1, "open: ");
for (;;) {
tm = time(NULL);
if (strftime(buf, BUFSZ, "%D %r\n", localtime(&tm == 0)
err(1, "strftime: ");
write(fd, buf, strlen(buf;
sleep(1);
}
}
Программка, которая восстанавливает файл:
#include <sys/stat.h>
#include <err.h>
#include <fcntl.h>
#include <unistd.h>
#define BUFSZ 64
int main(int argc, char **argv)
{
char buf[BUFSZ];
int fd, new;
int nread;
if (argc < 2)
errx(1, "Need argument");
fd = atoi(argv[1]);
printf("Working with fd=%d\n", fd);
new = open("a_new_file", O_WRONLY | O_TRUNC | O_CREAT,
DEFFILEMODE);
if (new < 0)
err(1, "open: ");
if (lseek(fd, 0, SEEK_SET) != 0)
err(1, "lseek: ");
printf("Writing\n");
whilenread = read(fd, buf, BUFSZ > 0) {
printf("Read %d bytes\n", nread);
if (write(new, buf, nread) != nread)
err(1, "write: ");
}
warn("nread %d; ", nread);
}
Тестовый "демон" скомпилен как qqq, программка как qqq2.
think:~:|>./qqq &
[1] 1835
think:~:|>cat a_file_to_be_unlinked
04/15/05 01:01:12 PM
04/15/05 01:01:13 PM
04/15/05 01:01:14 PM
04/15/05 01:01:15 PM
think:~:|>rm a_file_to_be_unlinked
think:~:|>ps auxww | grep qqq
1835 0,0 0,3 1304 676 p5 S 13:01 0:00,01 ./qqq
1839 0,0 0,4 1628 1076 p5 S+ 13:01 0:00,01 grep qqq
think:~:|>gdb qqq 1835
GNU gdb 6.1.1 [FreeBSD]
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-marcel-freebsd"...
Attaching to program: /usr/home//qqq, process 1835
Reading symbols from /lib/libc.so.6...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /libexec/ld-elf.so.1...done.
Loaded symbols for /libexec/ld-elf.so.1
0x280c737f in nanosleep from /lib/libc.so.6
(gdb) break time
Breakpoint 1 at 0x2812cf46
(gdb) cont
Continuing.
Breakpoint 1, 0x2812cf46 in time from /lib/libc.so.6
(gdb) next
Single stepping until exit from function time,
which has no line number information.
main (argc=1, argv=0xbfbfe8e8) at qqq.c:24
24 if (strftime(buf, BUFSZ, "%D %r\n", localtime(&tm == 0)
(gdb) p fd
$1 = 3
(gdb) call fcntl(3, 2, 0)
$2 = 0
(gdb) call execl("./qqq2", "qqq2", "3")
Program received signal SIGTRAP, Trace/breakpoint trap.
Cannot remove breakpoints because program is no longer writable.
It might be running in another process.
Further execution is probably impossible.
0x2804d450 in .rtld_start from /libexec/ld-elf.so.1
The program being debugged was signaled while in a function called from GDB.
GDB remains in the frame where the signal was received.
To change this behavior use "set unwindonsignal on"
Evaluation of the expression containing the function (execl) will be abandoned.
(gdb) quit
The program is running. Quit anyway (and detach it)? (y or n) y
Detaching from program: /usr/home//qqq, process 1835
think:~:|>Working with fd=3
Writing
Read 64 bytes
Read 64 bytes
Read 64 bytes
Read 64 bytes
Read 64 bytes
Read 16 bytes
qqq2: nread 0; : Unknown error: 0
[1]+ Exit 17 ./qqq
think:~:|>cat a_new_file
04/15/05 01:01:12 PM
04/15/05 01:01:13 PM
04/15/05 01:01:14 PM
04/15/05 01:01:15 PM
04/15/05 01:01:16 PM
04/15/05 01:01:17 PM
04/15/05 01:01:18 PM
04/15/05 01:01:19 PM
04/15/05 01:01:20 PM
04/15/05 01:01:21 PM
04/15/05 01:01:22 PM
04/15/05 01:01:23 PM
04/15/05 01:01:24 PM
04/15/05 01:01:25 PM
04/15/05 01:01:26 PM
04/15/05 01:01:27 PM
1) Если демон открывает файл как O_WRONLY, то я не знаю как изменить это на O_RDWR. С помощью fcntl не получается.
2) Если демон пострипан, то тяжело определить значение fd.
fhopen(2). Нужно знать номер иноды, generation, и fs id. Пока не могу придумать, как выяснить generation.
Есть вот такой интерфейс
я, честно говоря, надеялся что задачу можно под FreeBSD решить админскими методами...
А это фдибсд-way: админ обязан уметь программировать %)
Если бы задача была востребована, то существовал бы тул, на основе того же fthopen. Кстати у него ноги растут из NetBSD, может быть там такой тул имеется?
Оставить комментарий
TYU_2008
Есть демон, который пишет лог. Некий скрипт стирает этот лог, но демона перезапустить из-за ошибки забывает и этот демон продолжает писать свой лог. Как прочитать содержимое этого лога ? Для 2.6 linux решение знаю, интересует для FreeBSD 4.*