Пример #1
0
int
ttyslot()
{
	register struct ttyent *ttyp;
	register int slot;
	register char *p;
	int cnt;
	size_t buflen = __sysconf (_SC_TTY_NAME_MAX) + 1;
	char *name;

	if (buflen == 0)
	  /* This should be enough if no fixed value is given.  */
	  buflen = 32;

	name = __alloca (buflen);

	setttyent();
	for (cnt = 0; cnt < 3; ++cnt)
		if (__ttyname_r (cnt, name, buflen) == 0) {
			if ((p = rindex(name, '/')))
				++p;
			else
				p = name;
			for (slot = 1; (ttyp = getttyent()); ++slot)
				if (!strcmp(ttyp->ty_name, p)) {
					endttyent();
					return(slot);
				}
			break;
		}
	endttyent();
	return(0);
}
Пример #2
0
int
ttyslot()
{
    register struct ttyent *ttyp;
    register int slot;
    register char *p;
    int cnt;
    char *name;

    setttyent();
    for (cnt = 0; cnt < 3; ++cnt)
        if ((name = ttyname(cnt))) {
            if ((p = strrchr(name, '/')))
                ++p;
            else
                p = name;
            for (slot = 1; (ttyp = getttyent()); ++slot)
                if (!strcmp(ttyp->ty_name, p)) {
                    endttyent();
                    return(slot);
                }
            break;
        }
    endttyent();
    return(0);
}
Пример #3
0
struct ttyent *getttynam(const char *name)
/* Return the ttytab file entry for a given tty. */
{
	struct ttyent *tty;

	endttyent();
	while ((tty= getttyent()) != nil && strcmp(tty->ty_name, name) != 0) {}
	endttyent();
	return tty;
}
Пример #4
0
int
ttyslot(void)
{
	struct ttyent *ttyp;
	int slot = 0, ispty = 0;
	char *p;
	int cnt;
	char *name;
#ifndef __minix
	struct ptmget ptm;
#endif

	setttyent();
	for (cnt = 0; cnt < 3; ++cnt) {
#ifndef __minix
		if (ioctl(cnt, TIOCPTSNAME, &ptm) != -1) {
			ispty = 1;
			name = ptm.sn;
		} else if ((name = ttyname(cnt)) != NULL) {
#else
		if ((name = ttyname(cnt)) != NULL) {
#endif
			ispty = 0;
		} else
			continue;

		if ((p = strstr(name, "/pts/")) != NULL)
			++p;
		else if ((p = strrchr(name, '/')) != NULL)
			++p;
		else
			p = name;

		for (slot = 1; (ttyp = getttyent()) != NULL; ++slot)
			if (!strcmp(ttyp->ty_name, p)) {
				endttyent();
				return slot;
			}
		break;
	}
	endttyent();
	if (ispty) {
		struct stat st;
		if (fstat(cnt, &st) == -1)
			return 0;
		return slot + (int)minor(st.st_rdev) + 1;
	}
	return 0;
}
Пример #5
0
/* This is a slightly modification of code in OpenBSD's login.c */
static int
utmp_write_direct(struct logininfo *li, struct utmp *ut)
{
	return 1;
#if 0
	struct utmp old_ut;
	register int fd;
	int tty;

	/* FIXME: (ATL) ttyslot() needs local implementation */

#if defined(HAVE_GETTTYENT)
	register struct ttyent *ty;

	tty=0;

	setttyent();
	while ((struct ttyent *)0 != (ty = getttyent())) {
		tty++;
		if (!strncmp(ty->ty_name, ut->ut_line, sizeof(ut->ut_line)))
			break;
	}
	endttyent();

	if((struct ttyent *)0 == ty) {
		dropbear_log(LOG_WARNING, "utmp_write_entry: tty not found");
		return(1);
	}
#else /* FIXME */

	tty = ttyslot(); /* seems only to work for /dev/ttyp? style names */

#endif /* HAVE_GETTTYENT */

	if (tty > 0 && (fd = open(UTMP_FILE, O_RDWR|O_CREAT, 0644)) >= 0) {
		(void)lseek(fd, (off_t)(tty * sizeof(struct utmp)), SEEK_SET);
		/*
		 * Prevent luser from zero'ing out ut_host.
		 * If the new ut_line is empty but the old one is not
		 * and ut_line and ut_name match, preserve the old ut_line.
		 */
		if (atomicio(read, fd, &old_ut, sizeof(old_ut)) == sizeof(old_ut) &&
			(ut->ut_host[0] == '\0') && (old_ut.ut_host[0] != '\0') &&
			(strncmp(old_ut.ut_line, ut->ut_line, sizeof(ut->ut_line)) == 0) &&
			(strncmp(old_ut.ut_name, ut->ut_name, sizeof(ut->ut_name)) == 0)) {
			(void)memcpy(ut->ut_host, old_ut.ut_host, sizeof(ut->ut_host));
		}

		(void)lseek(fd, (off_t)(tty * sizeof(struct utmp)), SEEK_SET);
		if (atomicio(write, fd, ut, sizeof(*ut)) != sizeof(*ut))
			dropbear_log(LOG_WARNING, "utmp_write_direct: error writing %s: %s",
			    UTMP_FILE, strerror(errno));

		(void)close(fd);
		return 1;
	} else {
		return 0;
	}
#endif
}
Пример #6
0
gboolean
ck_get_max_num_consoles (guint *num)
{
        int      max_consoles;
        int      res;
        gboolean ret;
        struct ttyent *t;

        ret = FALSE;
        max_consoles = 0;

        res = setttyent ();
        if (res == 0) {
                goto done;
        }

        while ((t = getttyent ()) != NULL) {
                if (t->ty_status & TTY_ON && strncmp (t->ty_name, "ttyE", 4) == 0)
                        max_consoles++;
        }

        ret = TRUE;

        endttyent ();

done:
        if (num != NULL) {
                *num = max_consoles;
        }

        return ret;
}
Пример #7
0
int setttyent(void)
/* Open the ttytab file. */
{
	if (ttfd >= 0) endttyent();

	if ((ttfd= open(TTYTAB, O_RDONLY)) < 0) return -1;
	(void) fcntl(ttfd, F_SETFD, fcntl(ttfd, F_GETFD) | FD_CLOEXEC);
	return 0;
}
Пример #8
0
struct ttyent *
getttynam(const char *tty)
{
	struct ttyent *t;

	if (strncmp(tty, "/dev/", 5) == 0)
		tty += 5;
	setttyent();
	while ( (t = getttyent()) )
		if (!strcmp(tty, t->ty_name))
			break;
	endttyent();
	return (t);
}
Пример #9
0
static void
free_ttytab (struct ttytablist *t)
{
	struct ttytablist *u;

	/* free all that malloced stuff */
	endttyent ();
	do {
		u = t->next;
		free (t->dev);
		free (t->getty);
		free (t);
	} while (t = u);
}
Пример #10
0
int
ttyslot()
{
	struct ttyent *ttyp;
	int slot;
	int cnt;
	char *name;

	setttyent();
	for (cnt = 0; cnt < 3; ++cnt)
		if ( (name = ttyname(cnt)) ) {
			if (strncmp(name, _PATH_DEV, sizeof _PATH_DEV - 1) != 0)
				break;
			name += sizeof _PATH_DEV - 1;
			for (slot = 1; (ttyp = getttyent()); ++slot)
				if (!strcmp(ttyp->ty_name, name)) {
					endttyent();
					return(slot);
				}
			break;
		}
	endttyent();
	return(0);
}
Пример #11
0
static void
read_ttytab ()
{
	tablist0 = (struct ttytablist *)malloc (sizeof (struct ttytablist));
	if (!tablist0) {
		printf ("Malloc failed in init\n\r");
		_exit (0);
	}
	tablist0->next = (struct ttytablist *)0;
	tablist = tablist0;
	ent = getttyent ();
	if (!ent) {
		printf ("Getttyent failed in init, check /etc/ttytab\n\r");
		/* should probably enter single-user mode */
		_exit (0);
	}

	/* assume first entry is on, if it's off, waste some memory */
	tablist->pid = 0;
	for (;;) {
		tablist->next = (struct ttytablist *)0;
		tablist->dev = (char *)malloc (5 + strlen (ent->ty_name));
		strcpy (tablist->dev, "/dev/");
		strcat (tablist->dev, ent->ty_name);
		tablist->getty = (char *)malloc (strlen (ent->ty_getty));
		strcpy (tablist->getty, ent->ty_getty);
		if (ent->ty_status & TTY_ON) tablist->pid = -1;
		else tablist->pid = 0;

		/* don't waste memory to store off entries */
		do {
			ent = getttyent ();
			if (!ent) {
				endttyent ();
				break;
			}
		} while (ent->ty_status & TTY_ON);
		if (!ent) break;

		tablist->next = (struct ttytablist *)malloc (sizeof (struct ttytablist));
		tablist = tablist->next;
	}
}
Пример #12
0
/*
 * Ttyflags sets the device-specific tty flags, based on the contents
 * of /etc/ttys.  It can either set all of the ttys' flags, or set
 * the flags of the ttys specified on the command line.
 */
int
main(int argc, char *argv[])
{
	int aflag, ch, rval;

	aflag = nflag = vflag = 0;
	while ((ch = getopt(argc, argv, "anv")) != -1)
		switch (ch) {
		case 'a':
			aflag = 1;
			break;
		case 'n':		/* undocumented */
			nflag = 1;
			break;
		case 'v':
			vflag = 1;
			break;
		case '?':
		default:
			usage();
		}
	argc -= optind;
	argv += optind;

	if (aflag && argc != 0)
		usage();

	rval = 0;

	if (setttyent() == 0)
		err(1, "setttyent");

	if (aflag)
		rval = change_all();
	else
		rval = change_ttys(argv);

	if (endttyent() == 0)
		warn("endttyent");

	exit(rval);
}
Пример #13
0
void
login(struct utmp *ut)
{
	struct ttyent *ty;
	int fd;
	int tty;

	setttyent();
	for (tty = 1; (ty = getttyent()) != NULL; ++tty)
		if (strcmp(ty->ty_name, ut->ut_line) == 0)
			break;
	endttyent();
	if (tty > 0 && (fd = open(_PATH_UTMP, O_WRONLY|O_CREAT, 0644)) >= 0) {
		(void)lseek(fd, (off_t)(tty * sizeof(struct utmp)), L_SET);
		(void)write(fd, ut, sizeof(struct utmp));
		(void)close(fd);
	}
	if ((fd = open(_PATH_WTMP, O_WRONLY|O_APPEND, 0)) >= 0) {
		(void)write(fd, ut, sizeof(struct utmp));
		(void)close(fd);
	}
}
Пример #14
0
gboolean
ck_get_max_num_consoles (guint *num)
{
        int      max_consoles;
        int      res;
        gboolean ret;
        struct ttyent *t;

        ret = FALSE;
        max_consoles = 0;

        res = setttyent ();
        if (res == 0) {
                goto done;
        }

        while ((t = getttyent ()) != NULL) {
                if (t->ty_status & TTY_ON && strncmp (t->ty_name, "ttyC", 4) == 0)
                        max_consoles++;
        }

        /* Increment one more so that all consoles are properly counted
         * this is arguable a bug in vt_add_watches().
         */
        max_consoles++;

        ret = TRUE;

        endttyent ();

done:
         if (num != NULL) {
                *num = max_consoles;
         }

        return ret;
}
Пример #15
0
struct ttyent *
getttyent(void)
{
	static struct ttyent tty;
	static char devpts_name[] = "pts/9999999999";
	char *p;
	int c;
	size_t i;

	if (!tf && !setttyent())
		return (NULL);
	for (;;) {
		if (!fgets(p = line, lbsize, tf)) {
			if (curpts <= maxpts) {
				sprintf(devpts_name, "pts/%d", curpts++);
				tty.ty_name = devpts_name;
				tty.ty_getty = NULL;
				tty.ty_type = NULL;
				tty.ty_status = TTY_NETWORK;
				tty.ty_window = NULL;
				tty.ty_comment = NULL;
				tty.ty_group = _TTYS_NOGROUP;
				return (&tty);
			}
			return (NULL);
		}
		/* extend buffer if line was too big, and retry */
		while (!index(p, '\n') && !feof(tf)) {
			i = strlen(p);
			lbsize += MALLOCCHUNK;
			if ((p = realloc(line, lbsize)) == NULL) {
				endttyent();
				return (NULL);
			}
			line = p;
			if (!fgets(&line[i], lbsize - i, tf))
				return (NULL);
		}
		while (isspace((unsigned char)*p))
			++p;
		if (*p && *p != '#')
			break;
	}

#define scmp(e) !strncmp(p, e, sizeof(e) - 1) && isspace((unsigned char)p[sizeof(e) - 1])
#define	vcmp(e)	!strncmp(p, e, sizeof(e) - 1) && p[sizeof(e) - 1] == '='

	zapchar = 0;
	tty.ty_name = p;
	tty.ty_status = 0;
	tty.ty_window = NULL;
	tty.ty_group  = _TTYS_NOGROUP;

	p = skip(p);
	if (!*(tty.ty_getty = p))
		tty.ty_getty = tty.ty_type = NULL;
	else {
		p = skip(p);
		if (!*(tty.ty_type = p))
			tty.ty_type = NULL;
		else {
			/* compatibility kludge: handle network/dialup specially */
			if (scmp(_TTYS_DIALUP))
				tty.ty_status |= TTY_DIALUP;
			else if (scmp(_TTYS_NETWORK))
				tty.ty_status |= TTY_NETWORK;
			p = skip(p);
		}
	}

	for (; *p; p = skip(p)) {
		if (scmp(_TTYS_OFF))
			tty.ty_status &= ~TTY_ON;
		else if (scmp(_TTYS_ON))
			tty.ty_status |= TTY_ON;
		else if (scmp(_TTYS_SECURE))
			tty.ty_status |= TTY_SECURE;
		else if (scmp(_TTYS_INSECURE))
			tty.ty_status &= ~TTY_SECURE;
		else if (scmp(_TTYS_DIALUP))
			tty.ty_status |= TTY_DIALUP;
		else if (scmp(_TTYS_NETWORK))
			tty.ty_status |= TTY_NETWORK;
		else if (vcmp(_TTYS_WINDOW))
			tty.ty_window = value(p);
		else if (vcmp(_TTYS_GROUP))
			tty.ty_group = value(p);
		else
			break;
	}

	if (zapchar == '#' || *p == '#')
		while ((c = *++p) == ' ' || c == '\t')
			;
	tty.ty_comment = p;
	if (*p == 0)
		tty.ty_comment = 0;
	if ( (p = index(p, '\n')) )
		*p = '\0';
	return (&tty);
}
Пример #16
0
int main(void)
{
  pid_t pid;			/* pid of child process */
  int fd;			/* generally useful */
  int linenr;			/* loop variable */
  int check;			/* check if a new process must be spawned */
  int sn;			/* signal number */
  struct slotent *slotp;	/* slots[] pointer */
  struct ttyent *ttyp;		/* ttytab entry */
  struct sigaction sa;
  struct stat stb;

#define OPENFDS						\
  if (fstat(0, &stb) < 0) {				\
	/* Open standard input, output & error. */	\
	(void) open("/dev/null", O_RDONLY);		\
	(void) open("/dev/log", O_WRONLY);		\
	dup(1);						\
  }

  sigemptyset(&sa.sa_mask);
  sa.sa_flags = 0;

  /* Default: Ignore every signal (except those that follow). */
  sa.sa_handler = SIG_IGN;
  for (sn = 1; sn < _NSIG; sn++) {
      sigaction(sn, &sa, NULL);
  }

  /* Hangup: Reexamine /etc/ttytab for newly enabled terminal lines. */
  sa.sa_handler = onhup;
  sigaction(SIGHUP, &sa, NULL);

  /* Terminate: Stop spawning login processes, shutdown is near. */
  sa.sa_handler = onterm;
  sigaction(SIGTERM, &sa, NULL);

  /* Abort: Sent by the kernel on CTRL-ALT-DEL; shut the system down. */
  sa.sa_handler = onabrt;
  sigaction(SIGABRT, &sa, NULL);

  /* Execute the /etc/rc file. */
  if ((pid = fork()) != 0) {
	/* Parent just waits. */
	while (wait(NULL) != pid) {
		if (gotabrt) reboot(RBT_HALT);
	}
  } else {
#if ! SYS_GETKENV
	struct sysgetenv sysgetenv;
#endif
	char bootopts[16];
	static char *rc_command[] = { "sh", "/etc/rc", NULL, NULL, NULL };
	char **rcp = rc_command + 2;

	/* Get the boot options from the boot environment. */
	sysgetenv.key = "bootopts";
	sysgetenv.keylen = 8+1;
	sysgetenv.val = bootopts;
	sysgetenv.vallen = sizeof(bootopts);
	if (svrctl(PMGETPARAM, &sysgetenv) == 0) *rcp++ = bootopts;
	*rcp = "start";

	execute(rc_command);
	report(2, "sh /etc/rc");
	_exit(1);	/* impossible, we hope */
  }

  OPENFDS;

  /* Clear /etc/utmp if it exists. */
  if ((fd = open(PATH_UTMP, O_WRONLY | O_TRUNC)) >= 0) close(fd);

  /* Log system reboot. */
  wtmp(BOOT_TIME, 0, NULL, 0);

  /* Main loop. If login processes have already been started up, wait for one
   * to terminate, or for a HUP signal to arrive. Start up new login processes
   * for all ttys which don't have them. Note that wait() also returns when
   * somebody's orphan dies, in which case ignore it.  If the TERM signal is
   * sent then stop spawning processes, shutdown time is near.
   */

  check = 1;
  while (1) {
	while ((pid = waitpid(-1, NULL, check ? WNOHANG : 0)) > 0) {
		/* Search to see which line terminated. */
		for (linenr = 0; linenr < PIDSLOTS; linenr++) {
			slotp = &slots[linenr];
			if (slotp->pid == pid) {
				/* Record process exiting. */
				wtmp(DEAD_PROCESS, linenr, NULL, pid);
				slotp->pid = NO_PID;
				check = 1;
			}
		}
	}

	/* If a signal 1 (SIGHUP) is received, simply reset error counts. */
	if (gothup) {
		gothup = 0;
		for (linenr = 0; linenr < PIDSLOTS; linenr++) {
			slots[linenr].errct = 0;
		}
		check = 1;
	}

	/* Shut down on signal 6 (SIGABRT). */
	if (gotabrt) {
		gotabrt = 0;
		startup(0, &TT_REBOOT);
	}

	if (spawn && check) {
		/* See which lines need a login process started up. */
		for (linenr = 0; linenr < PIDSLOTS; linenr++) {
			slotp = &slots[linenr];
			if ((ttyp = getttyent()) == NULL) break;

			if (ttyp->ty_getty != NULL
				/* ty_getty is a string, and TTY_ON is
				 * the way to check for enabled ternimanls. */
				&& (ttyp->ty_status & TTY_ON)
				&& slotp->pid == NO_PID
				&& slotp->errct < ERRCT_DISABLE)
			{
				startup(linenr, ttyp);
			}
		}
		endttyent();
	}
	check = 0;
  }
}
Пример #17
0
/*
 * Write a utmp entry direct to the file
 * This is a slightly modification of code in OpenBSD's login.c
 */
static int
utmp_write_direct(struct logininfo *li, struct utmp *ut)
{
	struct utmp old_ut;
	register int fd;
	int tty;

	/* FIXME: (ATL) ttyslot() needs local implementation */

#if defined(HAVE_GETTTYENT)
	struct ttyent *ty;

	tty=0;
	setttyent();
	while (NULL != (ty = getttyent())) {
		tty++;
		if (!strncmp(ty->ty_name, ut->ut_line, sizeof(ut->ut_line)))
			break;
	}
	endttyent();

	if (NULL == ty) {
		logit("%s: tty not found", __func__);
		return (0);
	}
#else /* FIXME */

	tty = ttyslot(); /* seems only to work for /dev/ttyp? style names */

#endif /* HAVE_GETTTYENT */

	if (tty > 0 && (fd = open(UTMP_FILE, O_RDWR|O_CREAT, 0644)) >= 0) {
		off_t pos, ret;

		pos = (off_t)tty * sizeof(struct utmp);
		if ((ret = lseek(fd, pos, SEEK_SET)) == -1) {
			logit("%s: lseek: %s", __func__, strerror(errno));
			return (0);
		}
		if (ret != pos) {
			logit("%s: Couldn't seek to tty %d slot in %s",
			    __func__, tty, UTMP_FILE);
			return (0);
		}
		/*
		 * Prevent luser from zero'ing out ut_host.
		 * If the new ut_line is empty but the old one is not
		 * and ut_line and ut_name match, preserve the old ut_line.
		 */
		if (atomicio(read, fd, &old_ut, sizeof(old_ut)) == sizeof(old_ut) &&
		    (ut->ut_host[0] == '\0') && (old_ut.ut_host[0] != '\0') &&
		    (strncmp(old_ut.ut_line, ut->ut_line, sizeof(ut->ut_line)) == 0) &&
		    (strncmp(old_ut.ut_name, ut->ut_name, sizeof(ut->ut_name)) == 0))
			memcpy(ut->ut_host, old_ut.ut_host, sizeof(ut->ut_host));

		if ((ret = lseek(fd, pos, SEEK_SET)) == -1) {
			logit("%s: lseek: %s", __func__, strerror(errno));
			return (0);
		}
		if (ret != pos) {
			logit("%s: Couldn't seek to tty %d slot in %s",
			    __func__, tty, UTMP_FILE);
			return (0);
		}
		if (atomicio(vwrite, fd, ut, sizeof(*ut)) != sizeof(*ut)) {
			logit("%s: error writing %s: %s", __func__,
			    UTMP_FILE, strerror(errno));
		}

		close(fd);
		return (1);
	} else {
		return (0);
	}
}
Пример #18
0
/*
 * Bring the system up single user.
 */
static state_func_t
single_user(void)
{
	pid_t pid, wpid;
	int status;
	sigset_t mask;
	const char *shell;
	char *argv[2];
#ifdef SECURE
	struct ttyent *typ;
	struct passwd *pp;
	static const char banner[] =
		"Enter root password, or ^D to go multi-user\n";
	char *clear, *password;
#endif
#ifdef DEBUGSHELL
	char altshell[128];
#endif

	if (Reboot) {
		/* Instead of going single user, let's reboot the machine */
		sync();
		reboot(howto);
		_exit(0);
	}

	shell = get_shell();

	if ((pid = fork()) == 0) {
		/*
		 * Start the single user session.
		 */
		open_console();

#ifdef SECURE
		/*
		 * Check the root password.
		 * We don't care if the console is 'on' by default;
		 * it's the only tty that can be 'off' and 'secure'.
		 */
		typ = getttynam("console");
		pp = getpwnam("root");
		if (typ && (typ->ty_status & TTY_SECURE) == 0 &&
		    pp && *pp->pw_passwd) {
			write_stderr(banner);
			for (;;) {
				clear = getpass("Password:"******"single-user login failed\n");
			}
		}
		endttyent();
		endpwent();
#endif /* SECURE */

#ifdef DEBUGSHELL
		{
			char *cp = altshell;
			int num;

#define	SHREQUEST "Enter full pathname of shell or RETURN for "
			write_stderr(SHREQUEST);
			write_stderr(shell);
			write_stderr(": ");
			while ((num = read(STDIN_FILENO, cp, 1)) != -1 &&
			    num != 0 && *cp != '\n' && cp < &altshell[127])
				cp++;
			*cp = '\0';
			if (altshell[0] != '\0')
				shell = altshell;
		}
#endif /* DEBUGSHELL */

		/*
		 * Unblock signals.
		 * We catch all the interesting ones,
		 * and those are reset to SIG_DFL on exec.
		 */
		sigemptyset(&mask);
		sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0);

		/*
		 * Fire off a shell.
		 * If the default one doesn't work, try the Bourne shell.
		 */

		char name[] = "-sh";

		argv[0] = name;
		argv[1] = 0;
		execv(shell, argv);
		emergency("can't exec %s for single user: %m", shell);
		execv(_PATH_BSHELL, argv);
		emergency("can't exec %s for single user: %m", _PATH_BSHELL);
		sleep(STALL_TIMEOUT);
		_exit(1);
	}

	if (pid == -1) {
		/*
		 * We are seriously hosed.  Do our best.
		 */
		emergency("can't fork single-user shell, trying again");
		while (waitpid(-1, (int *) 0, WNOHANG) > 0)
			continue;
		return (state_func_t) single_user;
	}

	requested_transition = 0;
	do {
		if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1)
			collect_child(wpid);
		if (wpid == -1) {
			if (errno == EINTR)
				continue;
			warning("wait for single-user shell failed: %m; restarting");
			return (state_func_t) single_user;
		}
		if (wpid == pid && WIFSTOPPED(status)) {
			warning("init: shell stopped, restarting\n");
			kill(pid, SIGCONT);
			wpid = -1;
		}
	} while (wpid != pid && !requested_transition);

	if (requested_transition)
		return (state_func_t) requested_transition;

	if (!WIFEXITED(status)) {
		if (WTERMSIG(status) == SIGKILL) {
			/*
			 *  reboot(8) killed shell?
			 */
			warning("single user shell terminated.");
			sleep(STALL_TIMEOUT);
			_exit(0);
		} else {
			warning("single user shell terminated, restarting");
			return (state_func_t) single_user;
		}
	}

	runcom_mode = FASTBOOT;
	return (state_func_t) runcom;
}
Пример #19
0
int main(void)
{
  pid_t pid;			/* pid of child process */
  int fd;			/* generally useful */
  int linenr;			/* loop variable */
  int check;			/* check if a new process must be spawned */
  struct slotent *slotp;	/* slots[] pointer */
  struct ttyent *ttyp;		/* ttytab entry */
  struct sigaction sa;
  struct stat stb;

  if (fstat(0, &stb) < 0) {
	/* Open standard input, output & error. */
	(void) open("/dev/null", O_RDONLY);
	(void) open("/dev/log", O_WRONLY);
	dup(1);
  }

  sigemptyset(&sa.sa_mask);
  sa.sa_flags = 0;

  /* Hangup: Reexamine /etc/ttytab for newly enabled terminal lines. */
  sa.sa_handler = onhup;
  sigaction(SIGHUP, &sa, NULL);

  /* Terminate: Stop spawning login processes, shutdown is near. */
  sa.sa_handler = onterm;
  sigaction(SIGTERM, &sa, NULL);

  /* Abort: Sent by the kernel on CTRL-ALT-DEL; shut the system down. */
  sa.sa_handler = onabrt;
  sigaction(SIGABRT, &sa, NULL);

  /* Execute the /etc/rc file. */
  if ((pid = fork()) != 0) {
	/* Parent just waits. */
	while (wait(NULL) != pid) {
		if (gotabrt) reboot(RBT_HALT);
	}
  } else {
	static char *rc_command[] = { "sh", "/etc/rc", NULL, NULL };

#if __minix_vmd
	/* Minix-vmd: Get the boot options from the boot environment. */
	rc_command[2] = getenv("bootopts");
#else
	/* Minix: Input from the console. */
	close(0);
	(void) open("/dev/console", O_RDONLY);
#endif

	execute(rc_command);
	report(2, "sh /etc/rc");
	_exit(1);	/* impossible, we hope */
  }

  /* Clear /etc/utmp if it exists. */
  if ((fd = open(PATH_UTMP, O_WRONLY | O_TRUNC)) >= 0) close(fd);

  /* Log system reboot. */
  wtmp(BOOT_TIME, 0, NULL, 0);

  /* Main loop. If login processes have already been started up, wait for one
   * to terminate, or for a HUP signal to arrive. Start up new login processes
   * for all ttys which don't have them. Note that wait() also returns when
   * somebody's orphan dies, in which case ignore it.  If the TERM signal is
   * sent then stop spawning processes, shutdown time is near.
   */

  check = 1;
  while (1) {
	while ((pid = waitpid(-1, NULL, check ? WNOHANG : 0)) > 0) {
		/* Search to see which line terminated. */
		for (linenr = 0; linenr < PIDSLOTS; linenr++) {
			slotp = &slots[linenr];
			if (slotp->pid == pid) {
				/* Record process exiting. */
				wtmp(DEAD_PROCESS, linenr, NULL, pid);
				slotp->pid = NO_PID;
				check = 1;
			}
		}
	}

	/* If a signal 1 (SIGHUP) is received, simply reset error counts. */
	if (gothup) {
		gothup = 0;
		for (linenr = 0; linenr < PIDSLOTS; linenr++) {
			slots[linenr].errct = 0;
		}
		check = 1;
	}

	/* Shut down on signal 6 (SIGABRT). */
	if (gotabrt) {
		gotabrt = 0;
		startup(0, &TT_REBOOT);
	}

	if (spawn && check) {
		/* See which lines need a login process started up. */
		for (linenr = 0; linenr < PIDSLOTS; linenr++) {
			slotp = &slots[linenr];
			if ((ttyp = getttyent()) == NULL) break;

			if (ttyp->ty_getty != NULL
				&& ttyp->ty_getty[0] != NULL
				&& slotp->pid == NO_PID
				&& slotp->errct < ERRCT_DISABLE)
			{
				startup(linenr, ttyp);
			}
		}
		endttyent();
	}
	check = 0;
  }
}
Пример #20
0
/*
 * Bring the system up single user.
 */
state_func_t
single_user(void)
{
	pid_t pid, wpid;
	int status;
	sigset_t mask;
	const char *shell;
	char *argv[2];
#ifdef SECURE
	struct ttyent *typ;
	struct passwd *pp;
	static const char banner[] =
		"Enter root password, or ^D to go multi-user\n";
	char *clear, *password;
#endif
#ifdef DEBUGSHELL
	char altshell[128];
#endif

	if (Reboot) {
		/* Instead of going single user, let's reboot the machine */
		sync();
		alarm(2);
		pause();
		reboot(howto);
		_exit(0);
	}

	shell = get_shell();

	if ((pid = fork()) == 0) {
		/*
		 * Start the single user session.
		 */
		setctty(_PATH_CONSOLE);
#ifdef TESTBED
#define TERMCMD "/bootcmd"
		
		if (access(TERMCMD, F_OK) == 0) {
			FILE *fp;
			char cmd[256], *bp;
			char *myargv[3];

			/*
			 * Very simple; the file contains the path of a
			 * command to run. No arguments supported, sorry.
			 */
			if ((fp = fopen(TERMCMD, "r")) == NULL) {
				/* Lets avoid loops! */
				unlink(TERMCMD);
				goto skip;
			}
			
			if (fgets(cmd, sizeof(cmd), fp) == NULL) {
				fclose(fp);
				/* Lets avoid loops! */
				unlink(TERMCMD);
				goto skip;
			}
			fclose(fp);

			/* Lets avoid loops! */
			unlink(TERMCMD);

			if ((bp = rindex(cmd, '\n')))
				*bp = '\0';
			
			if (access(cmd, X_OK) != 0) {
				emergency("%s does not exist!", cmd);
				goto skip;
			}

			/* See comment below */
			sigemptyset(&mask);
			sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0);

			char name[] = "-sh";
			
			myargv[0] = name;
			myargv[1] = cmd;
			myargv[2] = 0;
			
			execv(_PATH_BSHELL, myargv);
			stall("can't exec %s for %s: %m", _PATH_BSHELL, cmd);
		}
		/*
		 * If something goes wrong, we want to sit in single user mode
		 * so that we might catch the error. Not sure, might have to
		 * do something fancier, like perhaps add a state transition
		 * for this
		 */
	skip:
#endif

#ifdef SECURE
		/*
		 * Check the root password.
		 * We don't care if the console is 'on' by default;
		 * it's the only tty that can be 'off' and 'secure'.
		 */
		typ = getttynam("console");
		pp = getpwnam("root");
		if (typ && (typ->ty_status & TTY_SECURE) == 0 &&
		    pp && *pp->pw_passwd) {
			write_stderr(banner);
			for (;;) {
				clear = getpass("Password:"******"single-user login failed\n");
			}
		}
		endttyent();
		endpwent();
#endif /* SECURE */

#ifdef DEBUGSHELL
		{
			char *cp = altshell;
			int num;

#define	SHREQUEST "Enter full pathname of shell or RETURN for "
			write_stderr(SHREQUEST);
			write_stderr(shell);
			write_stderr(": ");
			while ((num = read(STDIN_FILENO, cp, 1)) != -1 &&
			    num != 0 && *cp != '\n' && cp < &altshell[127])
				cp++;
			*cp = '\0';
			if (altshell[0] != '\0')
				shell = altshell;
		}
#endif /* DEBUGSHELL */

		/*
		 * Unblock signals.
		 * We catch all the interesting ones,
		 * and those are reset to SIG_DFL on exec.
		 */
		sigemptyset(&mask);
		sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0);

		/*
		 * Fire off a shell.
		 * If the default one doesn't work, try the Bourne shell.
		 */

		char name[] = "-sh";

		argv[0] = name;
		argv[1] = 0;
		execv(shell, argv);
		emergency("can't exec %s for single user: %m", shell);
		execv(_PATH_BSHELL, argv);
		emergency("can't exec %s for single user: %m", _PATH_BSHELL);
		sleep(STALL_TIMEOUT);
		_exit(1);
	}

	if (pid == -1) {
		/*
		 * We are seriously hosed.  Do our best.
		 */
		emergency("can't fork single-user shell, trying again");
		while (waitpid(-1, (int *) 0, WNOHANG) > 0)
			continue;
		return (state_func_t) single_user;
	}

	requested_transition = 0;
	do {
		if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1)
			collect_child(wpid);
		if (wpid == -1) {
			if (errno == EINTR)
				continue;
			warning("wait for single-user shell failed: %m; restarting");
			return (state_func_t) single_user;
		}
		if (wpid == pid && WIFSTOPPED(status)) {
			warning("init: shell stopped, restarting\n");
			kill(pid, SIGCONT);
			wpid = -1;
		}
	} while (wpid != pid && !requested_transition);

	if (requested_transition)
		return (state_func_t) requested_transition;

	if (!WIFEXITED(status)) {
		if (WTERMSIG(status) == SIGKILL) {
			/*
			 *  reboot(8) killed shell?
			 */
			warning("single user shell terminated.");
			sleep(STALL_TIMEOUT);
			_exit(0);
		} else {
			warning("single user shell terminated, restarting");
			return (state_func_t) single_user;
		}
	}

	runcom_mode = FASTBOOT;
	return (state_func_t) runcom;
}