在网上看到了这篇文章,真的时很不错,这是系统管理员的胜利。
简单的说,作者6个月前,在一个screen session里面起了一个很长很长的命令,
由于时间太久且HIST_SIZE
变量不够大,这个命令已经在命令历史文件里面找不到了。同样的,6个月的命令行输出足够把最开始发送命令的那一行从screen的scroll back buffer里面顶出去。好像是在所有的地方都没有这条命令记录了一样,但是这条命令又非常重要,怎么办?
看过《少数派报告》电影的也许还记得,即使所有的地方都找不到记录了,当初产生这条记录的precrime还记得。在这里,命令最初是在哪个bash进程里执行的,这个进程还是知道的,即使HIST_FILE
里已经没有了记录。那么怎么弄到这条命令记录呢?….
思路是去看bash的源代码,看看bash怎么处理历史记录的:
$ find . -iname \*.c | grep hist
./lib/readline/history.c
./lib/readline/examples/histexamp.c
./lib/readline/histexpand.c
./lib/readline/histsearch.c
./lib/readline/histfile.c
./bashhist.c
翻开histfile.c
找到了这样几行
int write_history (filename)
const char *filename;
{
return (history_do_write (filename, history_length, HISTORY_OVERWRITE));
}
显然write_history
这个函数有点用处….
$ gdb --pid 8909
...
Loaded symbols for /lib/i386-linux-gnu/i686/cmov/libnss_files.so.2
0xb76e7424 in __kernel_vsyscall ()
(gdb) call write_history("/tmp/foo")
$1 = 0
(gdb) detach
(gdb) q
$ tail -1 /tmp/foo
while true ; do echo 1 ; echo 2>/dev/null ; sleep 30 ; done
不错,这样就找回来那条运行的命令了。
不过慢着,如果…仅仅是如果,6个月以内对bash升过级,原本的/bin/bash
文件已经被新版本替换,怎么办?
$ ssh IamInHell
[ttsiod@IamInHell] su -
....
[root@IAmInHell ~] gdb --pid 53165
GNU gdb (GDB) Red Hat Enterprise Linux (7.2-60.el6_4.1)
...
Attaching to process 53165
/bin/bash (deleted): No such file or directory
不用担心,其实proc
文件系统对每个运行的程序都有备份。
[root@IamInHell] lsof +L1 | grep bash | grep 53165
bash 53165 root txt REG 253,0 938832 0 791023 /bin/bash (deleted)
[root@IamInHell] cat /proc/53165/exe > /tmp/oldBash
于是你可以用下面的命令找回那条珍贵的历史记录了。
[root@IamInHell] gdb --pid 53165 /tmp/oldBash
...
Loaded symbols for /lib64/libnss_files.so.2
0x0000003d37aac8be in waitpid () from /lib64/libc.so.6
...
(gdb) call write_history("/tmp/foo")
$1 = 0
(gdb) detach
Detaching from program: /tmp/oldBash, process 53165
(gdb) q
[root@IamInHell] tail -1 /tmp/foo
while true ; do ...
或许我一辈子也用不上这样的技巧。