diff --git a/winsup/utils/Makefile.am b/winsup/utils/Makefile.am index 6be5b12c2..75da1163b 100644 --- a/winsup/utils/Makefile.am +++ b/winsup/utils/Makefile.am @@ -31,6 +31,7 @@ bin_PROGRAMS = \ mkgroup \ mkpasswd \ mount \ + newgrp \ passwd \ pldd \ profiler \ diff --git a/winsup/utils/newgrp.c b/winsup/utils/newgrp.c new file mode 100644 index 000000000..012c3188f --- /dev/null +++ b/winsup/utils/newgrp.c @@ -0,0 +1,101 @@ +/* newgrp.c + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include +#include +#include +#include +#include +#include +#include +#include + +int +main (int argc, const char **argv) +{ + struct group *gr; + gid_t gid; + const char *cmd; + const char **cmd_av; + const char *fake_av[2]; + + /* TODO: Implement '-' option */ + /* TODO: Add command description to documentation */ + + if (argc < 2 || argv[1][0] == '-') + { + fprintf (stderr, + "Usage: %1$s group [command [args...]]\n" + "\n" + "%1$s changes the current primary group for a command.\n" + "The primary group must be member of the supplementary group\n" + "list of the user.\n" + "The command and its arguments are specified on the command\n" + "line. Default is the user's standard shell.\n", + program_invocation_short_name); + return 1; + } + if (isdigit ((int) argv[1][0])) + { + char *e = NULL; + + gid = strtol (argv[1], &e, 10); + if (e && *e != '\0') + { + fprintf (stderr, "%s: invalid gid `%s'\n", + program_invocation_short_name, argv[1]); + return 2; + } + gr = getgrgid (gid); + if (!gr) + { + fprintf (stderr, "%s: unknown group gid `%u'\n", + program_invocation_short_name, gid); + return 2; + } + } + else + { + gr = getgrnam (argv[1]); + if (!gr) + { + fprintf (stderr, "%s: unknown group name `%s'\n", + program_invocation_short_name, argv[1]); + return 2; + } + gid = gr->gr_gid; + } + if (setgid (gid) != 0) + { + fprintf (stderr, "%s: can't switch primary group to `%s'\n", + program_invocation_short_name, argv[1]); + return 2; + } + argc -= 2; + argv += 2; + if (argc < 1) + { + struct passwd *pw = getpwuid (getuid ()); + if (!pw) + cmd = "/usr/bin/bash"; + else + cmd = pw->pw_shell; + fake_av[0] = cmd; + fake_av[1] = NULL; + cmd_av = fake_av; + } + else + { + cmd = argv[0]; + cmd_av = argv; + } + execvp (cmd, (char **) cmd_av); + fprintf (stderr, "%s: failed to start `%s': %s\n", + program_invocation_short_name, cmd, strerror (errno)); + return 3; +}