前言
前两天,在一台线上服务器准备安装 gcc 的时候,发现 glibc 包版本过低,遂天真的执行了 rpm -e --nodeps glibc,然后发现 Linux 基本命令除了 cd 之外几乎都用不了了。
客观原因是,glibc 是整个 Linux 系统底层的依赖库,一旦被删除,就会爆出 /lib64/ld-linux-x86-64.so.2: bad ELF interpreter: No such file or directory 的错误。
主观原因是,对 rpm 和 glibc 的了解不够深入,过于草率。
解决方案
我的解决方案是,上传 busybox 到服务器上,然后通过 Winscp 添加了 busybox 的执行权限,最后通过 busybox rpm -ivh glibc-2.17-317.el7.x86_64.rpm 将 glibc 重新装了回来,恢复成功。
这里能成功恢复,有四个点:
- 能上传静态编译的 busybox 到服务器。
- ssh 和 文件上传的连接没有断开(一旦重启或者 ssh 断开了,就彻底没法操作了,只能跑到物理机旁边了)。
- 可以给 busybox 可执行权限。
- 此时登录的是 root 用户。
一开始,我并没有想到能通过 winscp 可视化界面设置文件的执行权限(因为此时 chmod +x 也已经用不了了),所以搜到了下文:
https://zhuanlan.zhihu.com/p/20062978
思路是,cp 命令此时拥有执行位,所以将 busybox 的二进制内容写入到 /bin/cp,就像下面这样:
printf 'busybox 的所有二进制内容' > /bin/cp
问题是 busybox 有 898 KB,ssh 工具的命令行界面肯定没法一下子粘贴这么多内容(极容易挂掉 ssh 连接,而我们有仅有一次机会)。
所以,我还写了以下代码,去分割 busybox,每个文件 10000 字节,有 91 个文件,也就是说至少要复制粘贴 91 次。
package cn.korilweb;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public class Main {
public static void main(String[] args) throws IOException {
Path p1 = Paths.get("C:\\users\\dingj\\desktop\\busybox-x86_64");
Path p2 = Paths.get("C:\\users\\dingj\\desktop\\test\\");
int len = 10000;
byte[] buf = new byte[len];
try (InputStream inputStream = Files.newInputStream(p1)) {
int offset = 0;
int cnt = 0;
int readLen;
while ((readLen = inputStream.read(buf, offset, len)) != -1) {
OutputStream outputStream = Files.newOutputStream(p2.resolve(String.valueOf(cnt)));
outputStream.write(buf, 0, readLen);
cnt++;
}
}
}
}
就在这时候,同事提醒我能够用 winscp 直接改可执行权限,才免了这些复杂的操作。
下面这个贴子的操作和我的思路差不多,不过他的 ssh 连接最后还是断开了:
https://www.v2ex.com/t/356113
经验教训
- 谨慎操作 Linux 服务器。
- 了解 rpm 和其他安装方式的种种细节。