Here's a little program I've extracted from the code to init that demonstrates the problem.

(To build sabotage just "cc -o sabotage sabotage.c").

Whooops, forgot to attach prog, here it is:

/*
 * Init		A System-V Init Clone.
 *
 * Usage:	/sbin/init
 *		     init [0123456SsQqAaBbCc]
 *		  telinit [0123456SsQqAaBbCc]
 *
 * Version:	@(#)init.c  2.86  30-Jul-2004  [EMAIL PROTECTED]
 */
#define VERSION "2.86"
#define DATE    "31-Jul-2004"
/*
 *		This file is part of the sysvinit suite,
 *		Copyright 1991-2004 Miquel van Smoorenburg.
 *
 *		This program is free software; you can redistribute it and/or
 *		modify it under the terms of the GNU General Public License
 *		as published by the Free Software Foundation; either version
 *		2 of the License, or (at your option) any later version.
 *
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#ifdef __linux__
#include <sys/kd.h>
#endif
#include <sys/resource.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <time.h>
#include <fcntl.h>
#include <string.h>
#include <signal.h>
#include <termios.h>
#include <utmp.h>
#include <ctype.h>
#include <stdarg.h>
#include <sys/syslog.h>
#include <sys/time.h>
#include <sys/reboot.h>

#define PATH_DFL   "PATH=/bin:/usr/bin:/sbin:/usr/sbin"
#define VT_MASTER	"/dev/tty0"		/* Virtual console master */
#define CONSOLE		"/dev/console"		/* Logical system console */



/* Version information */
char *Version = "@(#) init " VERSION "  " DATE "  [EMAIL PROTECTED]";
char *bootmsg = "version " VERSION " %s";
#define E_VERSION "INIT_VERSION=sysvinit-" VERSION


char runlevel = 'S';		/* The current run level */
char thislevel = 'S';		/* The current runlevel */
char prevlevel = 'N';		/* Previous runlevel */
int dfl_level = 0;		/* Default runlevel */
sig_atomic_t got_cont = 0;	/* Set if we received the SIGCONT signal */
sig_atomic_t got_signals;	/* Set if we received a signal. */
int emerg_shell = 0;		/* Start emergency shell? */
int wrote_wtmp_reboot = 1;	/* Set when we wrote the reboot record */
int wrote_utmp_reboot = 1;	/* Set when we wrote the reboot record */
int sltime = 5;			/* Sleep time between TERM and KILL */
char *argv0;			/* First arguments; show up in ps listing */
int maxproclen;			/* Maximal length of argv[0] with \0 */
struct utmp utproto;		/* Only used for sizeof(utproto.ut_id) */
char *user_console = NULL;	/* User console device */
char *console_dev;		/* Console device. */
int pipe_fd = -1;		/* /dev/initctl */
int did_boot = 0;		/* Did we already do BOOT* stuff? */

/*	Used by re-exec part */
int reload = 0;			/* Should we do initialization stuff? */
char *myname="/sbin/init";	/* What should we exec */
int oops_error;			/* Used by some of the re-exec code. */
const char *Signature = "12567362";	/* Signature for re-exec fd */


#ifdef __GNUC__
__attribute__ ((format (printf, 2, 3)))
#endif
void initlog(int loglevel, char *s, ...);

/*
 *	Sleep a number of seconds.
 *
 *	This only works correctly because the linux select updates
 *	the elapsed time in the struct timeval passed to select!
 */
void do_sleep(int sec)
{
	struct timeval tv;

	tv.tv_sec = sec;
	tv.tv_usec = 0;

	while(select(0, NULL, NULL, NULL, &tv) < 0 && errno == EINTR)
		;
}


/*
 *	Non-failing allocation routines (init cannot fail).
 */
void *imalloc(size_t size)
{
	void	*m;

	while ((m = malloc(size)) == NULL) {
		initlog(0, "out of memory");
		do_sleep(5);
	}
	memset(m, 0, size);
	return m;
}


char *istrdup(char *s)
{
	char	*m;
	int	l;

	l = strlen(s) + 1;
	m = imalloc(l);
	memcpy(m, s, l);
	return m;
}

/*
 *	Set console_dev to a working console.
 */
void console_init(void)
{
	int fd;
	int tried_devcons = 0;
	int tried_vtmaster = 0;
	char *s;

	if (user_console) {
		console_dev = user_console;
	} else if ((s = getenv("CONSOLE")) != NULL)
		console_dev = s;
	else {
		console_dev = CONSOLE;
		tried_devcons++;
	}

	while ((fd = open(console_dev, O_RDONLY|O_NONBLOCK)) < 0) {
		if (!tried_devcons) {
			tried_devcons++;
			console_dev = CONSOLE;
			continue;
		}
		if (!tried_vtmaster) {
			tried_vtmaster++;
			console_dev = VT_MASTER;
			continue;
		}
		break;
	}
	if (fd < 0)
		console_dev = "/dev/null";
	else
		close(fd);
}


/*
 *	Open the console with retries.
 */
int console_open(int mode)
{
	int f, fd = -1;
	int m;

	/*
	 *	Open device in nonblocking mode.
	 */
	m = mode | O_NONBLOCK;

	/*
	 *	Retry the open five times.
	 */
	for(f = 0; f < 5; f++)
		if ((fd = open(console_dev, m)) >= 0) break;

	if (fd < 0) return fd;

	/*
	 *	Set original flags.
	 */
	if (m != mode)
  		fcntl(fd, F_SETFL, mode);
	return fd;
}


/*
 *	Set terminal settings to reasonable defaults
 */
void console_stty(void)
{
	struct termios tty;
	int fd;

	if ((fd = console_open(O_RDWR|O_NOCTTY)) < 0) {
		initlog(0, "can't open %s", console_dev);
		return;
	}

	(void) tcgetattr(fd, &tty);

	tty.c_cflag &= CBAUD|CBAUDEX|CSIZE|CSTOPB|PARENB|PARODD;
	tty.c_cflag |= HUPCL|CLOCAL|CREAD;

	tty.c_cc[VINTR]  = 3;	/* ctrl('c') */
	tty.c_cc[VQUIT]  = 28;	/* ctrl('\\') */
	tty.c_cc[VERASE] = 127;
	tty.c_cc[VKILL]  = 24;	/* ctrl('x') */
	tty.c_cc[VEOF]   = 4;	/* ctrl('d') */
	tty.c_cc[VTIME]  = 0;
	tty.c_cc[VMIN]   = 1;
	tty.c_cc[VSTART] = 17;	/* ctrl('q') */
	tty.c_cc[VSTOP]  = 19;	/* ctrl('s') */
	tty.c_cc[VSUSP]  = 26;	/* ctrl('z') */

	/*
	 *	Set pre and post processing
	 */
	tty.c_iflag = IGNPAR|ICRNL|IXON|IXANY;
	tty.c_oflag = OPOST|ONLCR;
	tty.c_lflag = ISIG|ICANON|ECHO|ECHOCTL|ECHOPRT|ECHOKE;

	/*
	 *	Now set the terminal line.
	 *	We don't care about non-transmitted output data
	 *	and non-read input data.
	 */
	(void) tcsetattr(fd, TCSANOW, &tty);
	(void) tcflush(fd, TCIOFLUSH);
	(void) close(fd);
}

/*
 *	Print to the system console
 */
void print(char *s)
{
	int fd;

	if ((fd = console_open(O_WRONLY|O_NOCTTY|O_NDELAY)) >= 0) {
		write(fd, s, strlen(s));
		close(fd);
	}
}

/*
 *	Log something to a logfile and the console.
 */
#ifdef __GNUC__
__attribute__ ((format (printf, 2, 3)))
#endif
void initlog(int loglevel, char *s, ...)
{
	va_list va_alist;
	char buf[256];

	va_start(va_alist, s);
	vsnprintf(buf, sizeof(buf), s, va_alist);
	va_end(va_alist);

	/*
	 *	And log to the console.
	 */
		print("\rINIT: ");
		print(buf);
		print("\r\n");
}


/*
 *	The main loop
 */ 
int main()
{
  int f;

  if (!reload) {

	/*
	 *	Tell the kernel to send us SIGINT when CTRL-ALT-DEL
	 *	is pressed, and that we want to handle keyboard signals.
	 */
	reboot(RB_DISABLE_CAD);
	if ((f = open(VT_MASTER, O_RDWR | O_NOCTTY)) >= 0) {
		(void) ioctl(f, KDSIGACCEPT, SIGWINCH);
		close(f);
	} else
		(void) ioctl(0, KDSIGACCEPT, SIGWINCH);

  }

  console_init();

  if (!reload) {

  	/* Close whatever files are open, and reset the console. */
	close(0);
	close(1);
	close(2);
  	console_stty();
  	setsid();

  	/*
	 *	Set default PATH variable.
	 */
  	putenv(PATH_DFL);

  	/*
	 *	Say hello to the world
	 */
  	initlog(0, bootmsg, "booting");

  	/*
	 *	Start normal boot procedure.
	 */
	sleep (10000000);
  
  } 
  /*NOTREACHED*/
  abort ();
}

Reply via email to