summaryrefslogtreecommitdiffstats
path: root/login-utils/chsh.c
diff options
context:
space:
mode:
authorSami Kerola2017-08-28 22:38:13 +0200
committerKarel Zak2017-08-30 11:21:59 +0200
commita1f5bb9d1fe87122270369b888b413260b02cfa9 (patch)
tree1103c32f62c98af0951bed19a9a025a23d2d5fd3 /login-utils/chsh.c
parentbash-completion: simplify pid listing (diff)
downloadkernel-qcow2-util-linux-a1f5bb9d1fe87122270369b888b413260b02cfa9.tar.gz
kernel-qcow2-util-linux-a1f5bb9d1fe87122270369b888b413260b02cfa9.tar.xz
kernel-qcow2-util-linux-a1f5bb9d1fe87122270369b888b413260b02cfa9.zip
chsh: remove local /etc/shells parsing in favour of getusershell(3)
Less code, less bugs. And if there are bugs at least share them with all other programs that use getusershell(3) from libc. Signed-off-by: Sami Kerola <kerolasa@iki.fi>
Diffstat (limited to 'login-utils/chsh.c')
-rw-r--r--login-utils/chsh.c98
1 files changed, 18 insertions, 80 deletions
diff --git a/login-utils/chsh.c b/login-utils/chsh.c
index 4721c870e..c267c7272 100644
--- a/login-utils/chsh.c
+++ b/login-utils/chsh.c
@@ -67,9 +67,6 @@ struct sinfo {
char *shell;
};
-/* global due readline completion */
-static char **global_shells;
-
static void __attribute__((__noreturn__)) usage(void)
{
FILE *fp = stdout;
@@ -90,78 +87,25 @@ static void __attribute__((__noreturn__)) usage(void)
}
/*
- * free_shells () -- free shells allocations.
- */
-static void free_shells(void)
-{
- if (global_shells) {
- char **s;
-
- for (s = global_shells; *s; s++)
- free(*s);
- free(global_shells);
- }
-}
-
-/*
- * init_shells () -- reads /etc/shells into global_shells
- */
-static int init_shells(void)
-{
- FILE *fp;
- char *buf = NULL;
- size_t sz = 0, shellsz = 8, n = 0;
- ssize_t len;
-
- if (global_shells)
- return 0; /* already initialized */
-
- fp = fopen(_PATH_SHELLS, "r");
- if (!fp)
- return 1;
-
- global_shells = xmalloc(sizeof(char *) * shellsz);
-
- while ((len = getline(&buf, &sz, fp)) != -1) {
- /* ignore comments and blank lines */
- if (*buf == '#' || len < 2)
- continue;
- /* strip the ending newline */
- if (buf[len - 1] == '\n')
- buf[len - 1] = 0;
- global_shells[n++] = buf;
- if (shellsz < n) {
- shellsz *= 2;
- global_shells = xrealloc(global_shells, sizeof(char *) * shellsz);
- }
- buf = NULL;
- }
-
- free(buf);
- global_shells[n] = NULL;
-
- fclose(fp);
- atexit(free_shells);
-
- return 0;
-}
-
-/*
* is_known_shell() -- if the given shell appears in /etc/shells,
* return true. if not, return false.
*/
static int is_known_shell(const char *shell_name)
{
- char **s;
+ char *s, ret = 0;
- if (!global_shells || !shell_name)
+ if (!shell_name)
return 0;
- for (s = global_shells; *s; s++) {
- if (strcmp(shell_name, *s) == 0)
- return 1;
+ setusershell();
+ while ((s = getusershell())) {
+ if (strcmp(shell_name, s) == 0) {
+ ret = 1;
+ break;
+ }
}
- return 0;
+ endusershell();
+ return ret;
}
/*
@@ -169,29 +113,25 @@ static int is_known_shell(const char *shell_name)
*/
static void print_shells(void)
{
- char **s;
-
- if (!global_shells)
- return;
+ char *s;
- for (s = global_shells; *s; s++)
- printf("%s\n", *s);
+ while ((s = getusershell()))
+ printf("%s\n", s);
+ endusershell();
}
#ifdef HAVE_LIBREADLINE
static char *shell_name_generator(const char *text, int state)
{
- static size_t len, idx;
+ static size_t len;
char *s;
- if (!global_shells)
- return NULL;
-
if (!state) {
- idx = 0;
+ setusershell();
len = strlen(text);
}
- while ((s = global_shells[idx++])) {
+
+ while ((s = getusershell())) {
if (strncmp(s, text, len) == 0)
return xstrdup(s);
}
@@ -232,7 +172,6 @@ static void parse_argv(int argc, char **argv, struct sinfo *pinfo)
case 'h':
usage();
case 'l':
- init_shells();
print_shells();
exit(EXIT_SUCCESS);
case 's':
@@ -386,7 +325,6 @@ int main(int argc, char **argv)
_("running UID doesn't match UID of user we're "
"altering, shell change denied"));
}
- init_shells();
if (uid != 0 && !is_known_shell(oldshell)) {
errno = EACCES;
err(EXIT_FAILURE, _("your shell is not in %s, "