Hi

As you will know, the default Cygwin shortcuts invoke "cygwin.bat" which in turn runs "bash --login".

On most of my Unix accounts, I have tcsh set as my login shell, and have also started to find zsh quite useful, therefore I would prefer to be able to set my preferred shell in Cygwin as well. Most Unix systems do this with the pw_shell field of the password database, /etc/passwd.

I have attached a simple C source file which tries to use the user's shell if it's specified in the password database. You might compile this and make it available with a name such as /bin/shell and change cygwin.bat to invoke "shell" instead of "bash --login".

Design decisions:
- falls back to the default shell rather than exiting if a user
  doesn't exist since Cygwin doesn't currently require a valid
  user account
- uses the default shell if the shell field in /etc/passwd is blank
  as many other Unixes do
- uses /bin/bash as the default shell since cygwin.bat uses that
  as the default

Features:
- sets argv[0] to the shell's basename prefixed by a hyphen/minus
  character which makes most common shells switch to "login" mode

I hope you find it useful.

--
Michael Wardle
/*
 * shell - start user's preferred shell
 */

#include <sys/types.h>
#include <errno.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define DEFAULT_SHELL "/bin/bash"
#define PATH_SEPARATOR '/'

int main(int argc, char **argv)
{
        const struct passwd *passwd;
        const char *shell;
        char *basename;
        char *arg0;
        char **args;

        /* Get the current user's shell */
        errno = 0;
        passwd = getpwuid(getuid());
        if (!passwd) {
                fprintf(stderr, "Cannot get password entry: %s\n",
                        strerror(errno));
                shell = NULL;
        }
        else {
                shell = passwd->pw_shell;
        }

        /* Fall back to the default if the shell is unset or empty */
        if (!shell||!*shell) {
                fprintf(stderr, "Using default shell %s\n", DEFAULT_SHELL);
                shell = DEFAULT_SHELL;
        }

        /* Set the SHELL environment variable for make, etc. */
        setenv("SHELL", shell, 1);

        /* Set up the shell's argument vector - argv[0] */
        errno = 0;
        arg0 = (char *)malloc(strlen(shell)*sizeof(char)+1);
        if (!arg0) {
                perror("Cannot allocate memory for shell argument 0\n");
                exit(1);
        }
        basename = strrchr(shell, (int)PATH_SEPARATOR);
        if (basename) basename++;       /* move past '/' */
        if (basename) {
                /* Set arg0 to -basename to denote login shell */
                strcpy(arg0, "-");
                strcat(arg0, basename);
        }
        else {
                /* Leave arg0 as full path */
                strcpy(arg0, shell);
        }

        /* Set up the shell's argument vector - argv */
        errno = 0;
        args = (char **)malloc(2*sizeof(arg0)); /* {arg0, NULL} */
        if (!args) {
                perror("Cannot allocate memory for shell arguments\n");
                exit(1);
        }
        args[0] = arg0;
        args[1] = (char *)NULL;

        /* Start the shell */
        errno = 0;
        if (execv(shell, args) == -1) {
                fprintf(stderr, "Cannot execute shell %s: %s\n", shell,
                        strerror(errno));
                exit(1);
        }

        exit(0);
}

--
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple
Problem reports:       http://cygwin.com/problems.html
Documentation:         http://cygwin.com/docs.html
FAQ:                   http://cygwin.com/faq/

Reply via email to