红联Linux门户
Linux帮助

Linux系统启动在inittab和rc里面添加启动程序问题

发布时间:2016-11-16 15:59:23来源:linux网站作者:Kevin_Smart
一般Linux中,系统启动时,内核的启动的最后启动了用户空间的第一个进程init,这个进程的最后会执行/etc/inittab中的命令。
一般inittab命令如下:
console::sysinit:/etc/init.d/rcS  
#ttyS0::askfirst:-/bin/sh  
::respawn:-/bin/login  
sysinit是启动时执行一次的程序
respawn是启动这个进程,如果这个进程挂了,重新启动它。
 
看一下init进程最后对inittab的处理:
/* Now run everything that needs to be run */  
/* First run the sysinit command */  
run_actions(SYSINIT);  
check_delayed_sigs();  
/* Next run anything that wants to block */  
run_actions(WAIT);  
check_delayed_sigs();  
/* Next run anything to be run only once */  
run_actions(ONCE);
/* Now run the looping stuff for the rest of forever. 
*/  
while (1) {  
int maybe_WNOHANG;
maybe_WNOHANG = check_delayed_sigs();
/* (Re)run the respawn/askfirst stuff */  
run_actions(RESPAWN | ASKFIRST);  
maybe_WNOHANG |= check_delayed_sigs();
/* Don't consume all CPU time - sleep a bit */  
sleep(1);  
maybe_WNOHANG |= check_delayed_sigs();
/* Wait for any child process(es) to exit. 
* If check_delayed_sigs above reported that a signal 
* was caught, wait will be nonblocking. This ensures 
* that if SIGHUP has reloaded inittab, respawn and askfirst 
* actions will not be delayed until next child death. 
*/  
if (maybe_WNOHANG)  
maybe_WNOHANG = WNOHANG;  
while (1) {  
pid_t wpid;  
struct init_action *a;
/* If signals happen _in_ the wait, they interrupt it, 
* bb_signals_recursive_norestart set them up that way 
*/  
wpid = waitpid(-1, NULL, maybe_WNOHANG);  
if (wpid <= 0)  
break;
a = mark_terminated(wpid);  
if (a) {  
message(L_LOG, "process '%s' (pid %d) exited. "  
"Scheduling for restart.",  
a->command, wpid);  
}  
/* See if anyone else is waiting to be reaped */  
maybe_WNOHANG = WNOHANG;  
}  
} /* while (1) */  
}
 
可以看到程序只启动一次SYSINIT,RESPAWN则放到了while(1)中。
/* Run all commands of a particular type */  
static void run_actions(int action_type)  
{  
struct init_action *a;
for (a = init_action_list; a; a = a->next) {  
if (!(a->action_type & action_type))  
continue;
if (a->action_type & (SYSINIT | WAIT | ONCE | CTRLALTDEL | SHUTDOWN)) {  
pid_t pid = run(a);  
if (a->action_type & (SYSINIT | WAIT | CTRLALTDEL | SHUTDOWN))  
waitfor(pid);  
}  
if (a->action_type & (RESPAWN | ASKFIRST)) {  
/* Only run stuff with pid == 0. If pid != 0, 
* it is already running 
*/  
if (a->pid == 0)  
a->pid = run(a);  
}  
}  
}
 
需要注意一个细节,当执行SYSINIT时,父进程会waitfor(pid),等待子进程执行完成。
如果系统启动时需要启动自己程序,一般在/etc/init.d/rcS里面添加一个脚本,通过脚本启动程序。
而启动程序的最后启动一个命令行程序,而这个程序是不会退出的。
 
那就有问题了,从上面init进程的启动顺序,while(1)里面就执行不到了,无法检查信号和进行子进程的资源回收。
所以在/etc/init.d/rcS里面执行不退出的启动程序是不靠谱的。
 
那就需要在后面的RESPAWN命令做工作了,修改inittab
::respawn:-/bin/HHlogin  
改为自己的HHlogin,在HHlogin中判断是否有启动程序,如果有则执行,如果没有则启动自己的/bin/login
 
程序如下:
/* 
*  COPYRIGHT NOTICE 
*  Copyright (C) 2016 HuaHuan Electronics Corporation, Inc. All rights reserved 
*  Author   :Kevin_fzs 
*  File Name:/home/kevin/works/projects/IPRAN/drivers/inittab/HHlogin.c 
*  Create Date  :2016/08/11 17:37 
*  Last Modified:2016/08/11 17:37 
*  Description  : 
*/ 
#include <stdio.h>  
#include <stdlib.h>  
#include <unistd.h>  
#include <signal.h>
#define HOME_BIN_AUTORUN "/home/bin/autorun.sh"  
#define HOME_BIN_VTYSH  "/home/bin/vtysh"  
#define BIN_LOGIN   "/bin/login"  
#define BIN_SH  "/bin/sh"
int execute_and_wait(int opt)  
{  
pid_t cpid;  
int status;
cpid = fork();
if(cpid == 0) //child   
{  
if(1 == opt)  
{  
char *argv[]={BIN_SH, HOME_BIN_AUTORUN,NULL};  
int ret =execv(BIN_SH, argv);
_exit(1);  
/* 
*  COPYRIGHT NOTICE 
*  Copyright (C) 2016 HuaHuan Electronics Corporation, Inc. All rights reserved 
*  Author   :Kevin_fzs 
*  File Name:/home/kevin/works/projects/IPRAN/drivers/inittab/HHlogin.c 
*  Create Date  :2016/08/11 17:37 
*  Last Modified:2016/08/11 17:37 
*  Description  : 
*/
#include <stdio.h>  
#include <stdlib.h>  
#include <unistd.h>  
#include <signal.h>
#define HOME_BIN_AUTORUN "/home/bin/autorun.sh"  
#define HOME_BIN_VTYSH  "/home/bin/vtysh"  
#define BIN_LOGIN   "/bin/login"  
#define BIN_SH  "/bin/sh"
int execute_and_wait(int opt)  
{  
pid_t cpid;  
int status;
cpid = fork();
if(cpid == 0) //child   
{  
if(1 == opt)  
{  
char *argv[]={BIN_SH, HOME_BIN_AUTORUN,NULL};  
int ret =execv(BIN_SH, argv);
_exit(1);  
}  
else if(0 == opt)  
{  
char *argv[]={BIN_LOGIN, NULL};  
int ret =execv(BIN_LOGIN, argv);
_exit(1);
}  
else  
_exit(1);
}  
else //father   
{  
waitpid(cpid,&status,0);  
}  
}
static void  
vtysh_signal_set (int signo, void (*func)(int))  
{  
struct sigaction sig;  
struct sigaction osig;  
sig.sa_handler = func;  
sigemptyset (&sig.sa_mask);  
sig.sa_flags = 0;  
#ifdef SA_RESTART  
sig.sa_flags |= SA_RESTART;  
#endif /* SA_RESTART */  
sigaction (signo, &sig, &osig);  
}
void vtysh_signal_init ()  
{  
vtysh_signal_set (SIGINT, SIG_IGN);  
vtysh_signal_set (SIGTERM, SIG_IGN);  
vtysh_signal_set (SIGQUIT, SIG_IGN);  
}
int main()  
{  
char *argv[]={NULL};
/*we must ignor SIGINT*/  
vtysh_signal_init ();  
if((!access(HOME_BIN_AUTORUN, 0))&&(!access(HOME_BIN_VTYSH, 0)))  
{  
printf("App is existent, startup...\n");  
//  signal(SIGINT, SIG_DFL);  
execute_and_wait(1);  
printf("App execute stop, start Linux Shell\n");  
}  
execute_and_wait(0);
}
 
上面的程序是针对我们产品的一下启动脚本和程序,如果使用还需适当修改。
 
本文永久更新地址:http://www.linuxdiyf.com/linux/26057.html