Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 10 Apr 1999 23:15:00 +0100
From:      Ben Smithurst <ben@scientia.demon.co.uk>
To:        Sue Blake <sue@welearn.com.au>
Cc:        david mankins <dm@k12-nis-2.bbn.com>, freebsd-questions@FreeBSD.ORG
Subject:   Re: login shell selection prompt
Message-ID:  <19990410231500.A81602@scientia.demon.co.uk>
In-Reply-To: <19990410222804.05084@welearn.com.au>
References:  <19990410045140.50124@welearn.com.au> <199904092352.TAA12362@k12-nis-2.bbn.com> <19990410222804.05084@welearn.com.au>

next in thread | previous in thread | raw e-mail | index | archive | help
Sue Blake wrote:

> Yep, thanks, but a login is required before chsh can be run, and that
> login will be with the default bloated shell. That's no good:
> If the machine did have enough life left in it to run the normal bloated
> shell and chsh, then there wouldn't be any need to temporarily change the
> shell to something tiny.
> If the machine did not have enough life left in it to run the bloated
> shell and chsh, it'd be dead before I got a second chance to login with
> the lighter shell.

Why can't root's shell be /bin/sh? That's surely pretty light shell?

> The user will most likely be me or root. Not switch to a shell, but
> elect to use the substitute shell _before_ the regular bloated shell
> has a chance to load up and suck the last bit of life from the machine.

Hmm... you might try a small C program as your login shell.

> chsh is not a solution, and exec isn't either. Neither can prevent a
> superfluous few hundred Kb being compulsarily gobbled up just to get to
> a command prompt of any kind. Those are already part of the current
> range of alternatives that do not offer any particular benefits in time
> of crisis.
> 
> I'm looking for a way to be asked for a shell decision at login BEFORE
> any shell is run. Yes, this is an unusual question and I don't imagine
> it'll budge with the usual answers.

Even with a shell script, as Crist suggested, or a small C program, you're
going to need to load something. Anyway, here's a C program you might try.
Disclaimer: I am no C guru, etc, etc, but this seems to work. Nitpick as
much as you like, I'm still learning C, so feedback on anything I'm doing
wrong would be useful so I don't get into bad habits :-)

/*
 * shell.c: choose a shell at login
 */

#include <sys/types.h>

#include <err.h>
#include <pwd.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

void do_shell(char *);

int
main() {
	struct passwd *user;
	char newshell[128];
	int tried_defaults = 0;

	if ((user = getpwuid(getuid())) == NULL) {
		/* eek! getpwuid failed, try default shells, fall through
		   to choose another if they fail */
		warn("getpwuid");

		execl("/bin/sh", "-sh", NULL);
		warn("exec: sh");

		execl("/bin/csh", "-csh", NULL);
		warn("exec: csh");

		printf("neither sh or csh worked, "
			"you got any bright ideas?\n");

		tried_defaults = 1;
	}

	printf("Please choose a shell [%s]: ",
	  user ? user->pw_shell : "no default");
	fflush(stdout);

	if (fgets(newshell, sizeof newshell, stdin) == NULL ||
	  strcmp(newshell, "\n") == 0)
	{
		/* EOF or empty line enteted */
		if (user) {
			do_shell(user->pw_shell);
			warn("exec: %s", user->pw_shell);
		}

		if (!tried_defaults) {
			execl("/bin/sh", "-sh", NULL);
			warn("exec: sh");

			execl("/bin/csh", "-csh", NULL);
			warn("exec: csh");

			tried_defaults = 1;
		}
	}

	newshell[strlen(newshell)-1] = '\0';
	do_shell(newshell);

	if (!tried_defaults) {
		execl("/bin/sh", "-sh", NULL);
		warn("exec: sh");

		execl("/bin/csh", "-csh", NULL);
		warn("exec: csh");
	}

	return (0);
}

void
do_shell(char *shell) {
	char argv0[128];
	char *slash, *slash_prev = NULL;

	/* argv[0] for login shells start with "-" */
	argv0[0] = '-';

	/* find the start of the last componenet of the path */
	for (slash = strchr(shell, '/');
	  slash != NULL;
	  slash = strchr(slash + 1, '/'))
		slash_prev = slash;

	strncpy(argv0 + 1, slash_prev ? (slash_prev + 1) : shell, 126);

	execl(shell, argv0, NULL);
	warn("exec: %s", shell);
}

/* END */

-- 
Ben Smithurst
ben@scientia.demon.co.uk


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-questions" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?19990410231500.A81602>