Linux系统启动在inittab和rc里面添加启动程序问题
一般linux中,系统启动时,内核的启动的最后启动了用户空间的第一个进程init,这个进程的最后会执行/etc/inittab中的命令一般inittab命令如下console::sysinit:/etc/init.d/rcS#ttyS0::askfirst:-/bin/sh::respawn:-/bin/loginsysinit是启动时执行一次的程序respawn是启动这个进程,如
·
一般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"
#define START_LINUXSH 0
#define START_VTYSH 1
int execute_and_wait(int opt)
{
pid_t cpid;
int status;
if(START_LINUXSH == opt)
{
char *argv[]={BIN_LOGIN, NULL};
int ret =execv(BIN_LOGIN, argv);
_exit(1);
}
if(START_VTYSH == opt)
{
cpid = fork();
if(cpid == 0) //child
{
char *argv[]={HOME_BIN_VTYSH, NULL};
int ret =execv(HOME_BIN_VTYSH, argv);
_exit(1);
}
else //father
{
/*status 低8bits是信号,高8bits记录exit的返回值*/
/*当正常返回的时候,waitpid返回收集到的子进程的进程ID*/
int ret = waitpid(cpid,&status,0);
printf("\nvtysh exit,return code:[status=0x%x][pid=%d]\n", status, ret);
usleep(10000);
exit(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(START_VTYSH);
}
else
execute_and_wait(START_LINUXSH);
return 0;
}
上面的程序是针对我们产品的一下启动脚本和程序,如果使用还需适当修改
更多推荐
已为社区贡献8条内容
所有评论(0)