summaryrefslogtreecommitdiffstats
path: root/login-utils/chsh.c
diff options
context:
space:
mode:
authorKarel Zak2017-06-05 13:29:20 +0200
committerKarel Zak2017-06-05 13:29:20 +0200
commit5f032ae4bb6a5ec832289f77727d34cb73cba602 (patch)
tree5b51e3363fe3923890d60dad063ccd72945fb2a7 /login-utils/chsh.c
parentchsh: split get_shell_list() (diff)
downloadkernel-qcow2-util-linux-5f032ae4bb6a5ec832289f77727d34cb73cba602.tar.gz
kernel-qcow2-util-linux-5f032ae4bb6a5ec832289f77727d34cb73cba602.tar.xz
kernel-qcow2-util-linux-5f032ae4bb6a5ec832289f77727d34cb73cba602.zip
chsh: cleanup global_shells usage
* global variables are always initialized by NULL * it seems we need it as global variable due to libreadline, then use it as global everywhere in the same .c file. Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'login-utils/chsh.c')
-rw-r--r--login-utils/chsh.c65
1 files changed, 39 insertions, 26 deletions
diff --git a/login-utils/chsh.c b/login-utils/chsh.c
index 7d67493a4..3bea971cd 100644
--- a/login-utils/chsh.c
+++ b/login-utils/chsh.c
@@ -68,7 +68,7 @@ struct sinfo {
};
/* global due readline completion */
-static char **global_shells = NULL;
+static char **global_shells;
static void __attribute__((__noreturn__)) usage (FILE *fp)
{
@@ -93,27 +93,34 @@ static void __attribute__((__noreturn__)) usage (FILE *fp)
*/
static void free_shells(void)
{
- char **s;
+ if (global_shells) {
+ char **s;
- for (s = global_shells; *s; s++)
- free(*s);
- free(global_shells);
+ for (s = global_shells; *s; s++)
+ free(*s);
+ free(global_shells);
+ }
}
/*
- * init_shells () -- fill shells variable from /etc/shells,
+ * init_shells () -- reads /etc/shells into global_shells
*/
-static int init_shells(char ***shells)
+static int init_shells(void)
{
FILE *fp;
char *buf = NULL;
size_t sz = 0, shellsz = 8, n = 0;
ssize_t len;
- *shells = xmalloc(sizeof(char *) * shellsz);
+ 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)
@@ -121,17 +128,20 @@ static int init_shells(char ***shells)
/* strip the ending newline */
if (buf[len - 1] == '\n')
buf[len - 1] = 0;
- (*shells)[n++] = buf;
+ global_shells[n++] = buf;
if (shellsz < n) {
shellsz *= 2;
- shells = xrealloc(shells, sizeof(char *) * shellsz);
+ global_shells = xrealloc(global_shells, sizeof(char *) * shellsz);
}
buf = NULL;
}
+
free(buf);
- (*shells)[n] = NULL;
+ global_shells[n] = NULL;
+
fclose(fp);
atexit(free_shells);
+
return 0;
}
@@ -139,14 +149,14 @@ static int init_shells(char ***shells)
* 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 ***shells)
+static int is_known_shell(const char *shell_name)
{
char **s;
- if (!shells || !shell_name)
+ if (!global_shells || !shell_name)
return 0;
- for (s = *shells; *s; s++) {
+ for (s = global_shells; *s; s++) {
if (strcmp(shell_name, *s) == 0)
return 1;
}
@@ -156,14 +166,14 @@ static int is_known_shell(const char *shell_name, char ***shells)
/*
* print_shells () -- /etc/shells is outputted to stdout.
*/
-static void print_shells(char ***shells)
+static void print_shells(void)
{
char **s;
- if (!shells)
+ if (!global_shells)
return;
- for (s = *shells; *s; s++)
+ for (s = global_shells; *s; s++)
printf("%s\n", *s);
}
@@ -173,6 +183,9 @@ static char *shell_name_generator(const char *text, int state)
static size_t len, idx;
char *s;
+ if (!global_shells)
+ return NULL;
+
if (!state) {
idx = 0;
len = strlen(text);
@@ -198,7 +211,7 @@ static char **shell_name_completion(const char *text,
* parse the command line arguments, and fill in "pinfo" with any
* information from the command line.
*/
-static void parse_argv(int argc, char **argv, struct sinfo *pinfo, char ***shells)
+static void parse_argv(int argc, char **argv, struct sinfo *pinfo)
{
static const struct option long_options[] = {
{"shell", required_argument, NULL, 's'},
@@ -218,8 +231,8 @@ static void parse_argv(int argc, char **argv, struct sinfo *pinfo, char ***shell
case 'h':
usage(stdout);
case 'l':
- init_shells(shells);
- print_shells(shells);
+ init_shells();
+ print_shells();
exit(EXIT_SUCCESS);
case 's':
if (!optarg)
@@ -272,7 +285,7 @@ static char *ask_new_shell(char *question, char *oldshell)
* check_shell () -- if the shell is completely invalid, print
* an error and exit.
*/
-static void check_shell(const char *shell, char ***shells)
+static void check_shell(const char *shell)
{
if (*shell != '/')
errx(EXIT_FAILURE, _("shell must be a full path name"));
@@ -282,7 +295,7 @@ static void check_shell(const char *shell, char ***shells)
errx(EXIT_FAILURE, _("\"%s\" is not executable"), shell);
if (illegal_passwd_chars(shell))
errx(EXIT_FAILURE, _("%s: has illegal characters"), shell);
- if (!is_known_shell(shell, shells)) {
+ if (!is_known_shell(shell)) {
#ifdef ONLY_LISTED_SHELLS
if (!getuid())
warnx(_("Warning: \"%s\" is not listed in %s."), shell,
@@ -314,7 +327,7 @@ int main(int argc, char **argv)
textdomain(PACKAGE);
atexit(close_stdout);
- parse_argv(argc, argv, &info, &global_shells);
+ parse_argv(argc, argv, &info);
if (!info.username) {
pw = getpwuid(uid);
if (!pw)
@@ -373,8 +386,8 @@ int main(int argc, char **argv)
_("running UID doesn't match UID of user we're "
"altering, shell change denied"));
}
- init_shells(&global_shells);
- if (uid != 0 && !is_known_shell(oldshell, &global_shells)) {
+ init_shells();
+ if (uid != 0 && !is_known_shell(oldshell)) {
errno = EACCES;
err(EXIT_FAILURE, _("your shell is not in %s, "
"shell change denied"), _PATH_SHELLS);
@@ -393,7 +406,7 @@ int main(int argc, char **argv)
return EXIT_SUCCESS;
}
- check_shell(info.shell, &global_shells);
+ check_shell(info.shell);
if (!nullshell && strcmp(oldshell, info.shell) == 0)
errx(EXIT_SUCCESS, _("Shell not changed."));