Linux中/etc/passwd文件误删导致无法开机?教你一键解决

鑫软Linux日常问题解决–001

之前在做Linux实验的视时候本是cp操作将root/etc/passwd进行再操作到别的目录,到底那个目录我也确实是忘了,不然就可以直接找回了,哪想我太粗心大意,将cp命令换成了mv命令,一下子将passwd文件移动走了,导致关机以后再也开不开机。。。。。。Linux中/etc/passwd文件误删导致无法开机?教你一键解决_第1张图片

其实到这里都不用慌,因为文件并不是被删除了,也只是被我自己移动走了而已,所以,要想我们恢复正常开机,其实很简单,也就只用将原来的被移动的文件移动回来就可以了!怎么找?全磁盘检索一次就哦了。。。。但是把,有点麻烦,hhhhh,好,我就当他删了,删了,怎么办?别慌,问题不大!不信?来,上画面!
以下为启动后出现的情况:
停留界面:
如果删除文件后救就会一直停留在这个centos启动界面,不会动,按下ESC或者F2后你会发现下图的错误代码(见图二)Linux中/etc/passwd文件误删导致无法开机?教你一键解决_第2张图片Linux中/etc/passwd文件误删导致无法开机?教你一键解决_第3张图片

删除了当前用户底下的 etc/passwd文件,怎么办呢?怎么做呢?

Linux中/etc/passwd文件误删导致无法开机?教你一键解决_第4张图片

(1)第一步:将虚拟机设置为开机进入bois界面:
Linux中/etc/passwd文件误删导致无法开机?教你一键解决_第5张图片
(2)第二步:在Boot选项中调整启动项,将“CD-ROM Drive”调整到启动默认第一项,切记最后F10保存退出

详细操作步骤:使用和键盘上的左右的方向键,将光标移动到Bios界面的Boot选项,然后更改将cd -ROM drive 即cd驱动加载至首位,只用将光标移动到cd drive然后按下键盘上的+即可,一定要记住最后按下F10保存退出!
Linux中/etc/passwd文件误删导致无法开机?教你一键解决_第6张图片
(3)第三步重启虚拟机,开机后画面如下,进入Rescue installed system 救援模式
重启后进入安装菜单,选中Rescue install system 后回车
Linux中/etc/passwd文件误删导致无法开机?教你一键解决_第7张图片
Linux中/etc/passwd文件误删导致无法开机?教你一键解决_第8张图片
(4)它会进入一个等待界面,然后进入设置界面:
Linux中/etc/passwd文件误删导致无法开机?教你一键解决_第9张图片

下面的界面里选择默认的就可以,英文English然后进入下一步:

Linux中/etc/passwd文件误删导致无法开机?教你一键解决_第10张图片

ok以后选择默认的US即可,点击ok进入下一步:

Linux中/etc/passwd文件误删导致无法开机?教你一键解决_第11张图片

然后在下面的界面选择NO:(这个根据需要而定吧,我不需要远程所以不需要开启系统网络接口服务所以直接NO)

Linux中/etc/passwd文件误删导致无法开机?教你一键解决_第12张图片

然后进入下一界面直接continue继续即可:

Linux中/etc/passwd文件误删导致无法开机?教你一键解决_第13张图片

在点击OK下一步:

Linux中/etc/passwd文件误删导致无法开机?教你一键解决_第14张图片

直到来到Shell命令界面:

Linux中/etc/passwd文件误删导致无法开机?教你一键解决_第15张图片

选择ok,进入shell终端,第一件事就是切换操作用户身份,输入命令:chroot /mnt/sysimage 意思就是切换到root用户身份将系统挂载

Linux中/etc/passwd文件误删导致无法开机?教你一键解决_第16张图片

这个时候系统提示符切换到sh-4.1# 即shell脚本模式:

在系统被挂载的情况下我们可以直接输入命令:cp /etc/passwd- /etc/passwd ,

注意,我这里由于已经修复了,我没写,但是你一定要注意不能少了通配符" - ",并且在执行本操作之前你应该首先查询一下你的linux的root/etc/目录下有没有passwd的缓存文件,有的话,这条命令不会报错,没有的话金会报错copy一个bak文件过来,完事后回车,在输入命令,cat /etc/passwd 回车,这条命令的目的是为了检测当前etc/passwd文件到底有没有内容!
Linux中/etc/passwd文件误删导致无法开机?教你一键解决_第17张图片

到这一步就ok了,查看到/etc/passwd文件内部有内容,然后直接输入exit退出当前shell,然后回退到bash模式下

Linux中/etc/passwd文件误删导致无法开机?教你一键解决_第18张图片

最后输入reboot重启系统即可,以下是救援模式的系统修复界面!

Linux中/etc/passwd文件误删导致无法开机?教你一键解决_第19张图片

最后修复完成后你手动重启虚拟机,就大功告成!

到这里,修复就基本结束了!

之后耐心等待几分钟即可,不过大家别忘了奥,你设置的cd-rom drive 还没有还原,你启动后还是会进入一个boot选项选择界面,这样会影响你使用虚拟机,所以一定别忘了再次进入bois改回来奥!
更改回原始的从本地启动:
你如果没有更改就是下面的界面:这个时候你只需要移动光标到Boot from local drive即可,意思就是从本地磁盘驱动器启动!
Linux中/etc/passwd文件误删导致无法开机?教你一键解决_第20张图片
更改回来后是这样的:(别忘了F10保存退奥!)
Linux中/etc/passwd文件误删导致无法开机?教你一键解决_第21张图片

最后重启你的虚拟机!看:

Linux中/etc/passwd文件误删导致无法开机?教你一键解决_第22张图片
Linux中/etc/passwd文件误删导致无法开机?教你一键解决_第23张图片
(想必很多人会有疑问,为什么会有缓存文件?)
借助Linux系统的busybox框架,我来给大家解释一下:
busybox想必大家都在安卓手机上玩过不少,busyBox 是一个集成了三百多个最常用Linux命令和工具的软件。BusyBox 包含了一些简单的工具,例如ls、cat和echo等等,还包含了一些更大、更复杂的工具,例grep、find、mount以及telnet。有些人将 BusyBox 称为 Linux 工具里的瑞士军刀。简单的说BusyBox就好像是个大工具箱,它集成压缩了 Linux 的许多工具和命令,也包含了 Android 系统的自带的shell。以下是代码说明:

在busybox中,这些命令都会调用以下函数,红色部分为其创建/etc/passwd-/etc/shadow-代码:

int FAST_FUNC update_passwd(const char *filename,
const char *name,
const char *new_passwd,
const char *member)
{
#if !(ENABLE_FEATURE_ADDUSER_TO_GROUP || ENABLE_FEATURE_DEL_USER_FROM_GROUP)
#define member NULL
#endif
struct stat sb;
struct flock lock;
FILE *old_fp;
FILE *new_fp;
char *fnamesfx;
char *sfx_char;
char *name_colon;
unsigned user_len;
int old_fd;
int new_fd;
int i;
int changed_lines;
int ret = -1; /* failure */
/* used as a bool: "are we modifying /etc/shadow?" */
#if ENABLE_FEATURE_SHADOWPASSWDS
const char *shadow = strstr(filename, "shadow");
#else
# define shadow NULL
#endif

filename = xmalloc_follow_symlinks(filename);
if (filename == NULL)
return ret;

check_selinux_update_passwd(name);

/* New passwd file, "/etc/passwd+" for now */
fnamesfx = xasprintf("%s+", filename);
sfx_char = &fnamesfx[strlen(fnamesfx)-1];
name_colon = xasprintf("%s:", name);
user_len = strlen(name_colon);

if (shadow)
old_fp = fopen(filename, "r+");
else
old_fp = fopen_or_warn(filename, "r+");
if (!old_fp) {
if (shadow)
ret = 0; /* missing shadow is not an error */
goto free_mem;
}
old_fd = fileno(old_fp);

selinux_preserve_fcontext(old_fd);

/* Try to create "/etc/passwd+". Wait if it exists. */
i = 30;
do {
// FIXME: on last iteration try w/o O_EXCL but with O_TRUNC?
new_fd = open(fnamesfx, O_WRONLY|O_CREAT|O_EXCL, 0600);
if (new_fd >= 0) goto created;
if (errno != EEXIST) break;
usleep(100000); /* 0.1 sec */
} while (--i);
bb_perror_msg("can't create '%s'", fnamesfx);
goto close_old_fp;

created:
if (!fstat(old_fd, &sb)) {
fchmod(new_fd, sb.st_mode & 0777); /* ignore errors */
fchown(new_fd, sb.st_uid, sb.st_gid);
}
errno = 0;
new_fp = xfdopen_for_write(new_fd);
==========================================================
以下代码会创建backup备份的缓存文件
==========================================================
/* Backup file is "/etc/passwd-" */
*sfx_char = '-';
/* Delete old backup */
i = (unlink(fnamesfx) && errno != ENOENT);
/* Create backup as a hardlink to current */
if (i || link(filename, fnamesfx))
bb_perror_msg("warning: can't create backup copy '%s'",
fnamesfx);
*sfx_char = '+';
===========================================================
/* Lock the password file before updating */
lock.l_type = F_WRLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
if (fcntl(old_fd, F_SETLK, &lock) < 0)
bb_perror_msg("warning: can't lock '%s'", filename);
lock.l_type = F_UNLCK;

/* Read current password file, write updated /etc/passwd+ */
changed_lines = 0;
while (1) {
char *cp, *line;

line = xmalloc_fgetline(old_fp);
if (!line) /* EOF/error */
break;
if (strncmp(name_colon, line, user_len) != 0) {
fprintf(new_fp, "%s\n", line);
goto next;
}

/* We have a match with "name:"... */
cp = line + user_len; /* move past name: */

#if ENABLE_FEATURE_ADDUSER_TO_GROUP || ENABLE_FEATURE_DEL_USER_FROM_GROUP
if (member) {
/* It's actually /etc/group+, not /etc/passwd+ */
if (ENABLE_FEATURE_ADDUSER_TO_GROUP
&& applet_name[0] == 'a'
) {
/* Add user to group */
fprintf(new_fp, "%s%s%s\n", line,
last_char_is(line, ':') ? "" : ",",
member);
changed_lines++;
} else if (ENABLE_FEATURE_DEL_USER_FROM_GROUP
/* && applet_name[0] == 'd' */
) {
/* Delete user from group */
char *tmp;
const char *fmt = "%s";

/* find the start of the member list: last ':' */
cp = strrchr(line, ':');
/* cut it */
*cp++ = '\0';
/* write the cut line name:passwd:gid:
* or name:!:: */
fprintf(new_fp, "%s:", line);
/* parse the tokens of the member list */
tmp = cp;
while ((cp = strsep(&tmp, ",")) != NULL) {
if (strcmp(member, cp) != 0) {
fprintf(new_fp, fmt, cp);
fmt = ",%s";
} else {
/* found member, skip it */
changed_lines++;
}
}
fprintf(new_fp, "\n");
}
} else
#endif
if ((ENABLE_PASSWD && applet_name[0] == 'p')
|| (ENABLE_CHPASSWD && applet_name[0] == 'c')
) {
/* Change passwd */
cp = strchrnul(cp, ':'); /* move past old passwd */

if (shadow && *cp == ':') {
/* /etc/shadow's field 3 (passwd change date) needs updating */
/* move past old change date */
cp = strchrnul(cp + 1, ':');
/* "name:" + "new_passwd" + ":" + "change date" + ":rest of line" */
fprintf(new_fp, "%s%s:%u%s\n", name_colon, new_passwd,
(unsigned)(time(NULL)) / (24*60*60), cp);
} else {
/* "name:" + "new_passwd" + ":rest of line" */
fprintf(new_fp, "%s%s%s\n", name_colon, new_passwd, cp);
}
changed_lines++;
} /* else delete user or group: skip the line */
next:
free(line);
}

if (changed_lines == 0) {
#if ENABLE_FEATURE_ADDUSER_TO_GROUP || ENABLE_FEATURE_DEL_USER_FROM_GROUP
if (member) {
if (ENABLE_ADDGROUP && applet_name[0] == 'a')
bb_error_msg("can't find %s in %s", name, filename);
if (ENABLE_DELGROUP && applet_name[0] == 'd')
bb_error_msg("can't find %s in %s", member, filename);
}
#endif
if ((ENABLE_ADDUSER || ENABLE_ADDGROUP)
&& applet_name[0] == 'a' && !member
) {
/* add user or group */
fprintf(new_fp, "%s%s\n", name_colon, new_passwd);
changed_lines++;
}
}

fcntl(old_fd, F_SETLK, &lock);

/* We do want all of them to execute, thus | instead of || */
errno = 0;
if ((ferror(old_fp) | fflush(new_fp) | fsync(new_fd) | fclose(new_fp))
|| rename(fnamesfx, filename)
) {
/* At least one of those failed */
bb_perror_nomsg();
goto unlink_new;
}
/* Success: ret >= 0 */
ret = changed_lines;

unlink_new:
if (ret < 0)
unlink(fnamesfx);

close_old_fp:
fclose(old_fp);

free_mem:
free(fnamesfx);
free((char *)filename);
free(name_colon);
return ret;
}

好啦!本期鑫软教程到此结束啦!感谢大家耐心观看!笔者fntp-----QQ358566760欢迎加我交流讨论技术!

你可能感兴趣的:(Linux问题分析,教程)