一般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;
}





上面的程序是针对我们产品的一下启动脚本和程序,如果使用还需适当修改







Logo

更多推荐