add-shell, remove-shell: new applets
authorAlexander Shishkin <virtuoso@slind.org>
Wed, 20 Oct 2010 11:22:24 +0000 (13:22 +0200)
committerDenys Vlasenko <dvlasenk@redhat.com>
Wed, 20 Oct 2010 11:22:58 +0000 (13:22 +0200)
function                                             old     new   delta
add_remove_shell_main                                  -     259    +259
packed_usage                                       27408   27438     +30
applet_names                                        2326    2349     +23
applet_main                                         1364    1372      +8
applet_nameofs                                       682     686      +4
run_applet_and_exit                                  700     703      +3
dont_add                                               -       2      +2
applet_install_loc                                   171     172      +1
------------------------------------------------------------------------------
(add/remove: 3/0 grow/shrink: 6/0 up/down: 330/0)             Total: 330 bytes

Signed-off-by: Alexander Shishkin <virtuoso@slind.org>
Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
loginutils/add-remove-shell.c [new file with mode: 0644]

diff --git a/loginutils/add-remove-shell.c b/loginutils/add-remove-shell.c
new file mode 100644 (file)
index 0000000..986fe57
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * add-shell and remove-shell implementation for busybox
+ *
+ * Copyright (C) 2010 Nokia Corporation. All rights reserved.
+ * Written by Alexander Shishkin <virtuoso@slind.org>
+ *
+ * Licensed under GPLv2 or later, see the LICENSE file in this source tree
+ * for details.
+ */
+
+//applet:IF_ADD_SHELL(   APPLET_ODDNAME(add-shell   , add_remove_shell, _BB_DIR_USR_BIN, _BB_SUID_DROP, add_shell   ))
+//applet:IF_REMOVE_SHELL(APPLET_ODDNAME(remove-shell, add_remove_shell, _BB_DIR_USR_BIN, _BB_SUID_DROP, remove_shell))
+
+//kbuild:lib-$(CONFIG_ADD_SHELL)    += add-remove-shell.o
+//kbuild:lib-$(CONFIG_REMOVE_SHELL) += add-remove-shell.o
+
+//config:config ADD_SHELL
+//config:       bool "add-shell"
+//config:       default y if DESKTOP
+//config:       help
+//config:         Add shells to /etc/shells.
+//config:
+//config:config REMOVE_SHELL
+//config:       bool "remove-shell"
+//config:       default y if DESKTOP
+//config:       help
+//config:         Remove shells from /etc/shells.
+
+//usage:#define add_shell_trivial_usage
+//usage:       "SHELL..."
+//usage:#define add_shell_full_usage "\n\n"
+//usage:       "Add SHELLs to /etc/shells"
+
+//usage:#define remove_shell_trivial_usage
+//usage:       "SHELL..."
+//usage:#define remove_shell_full_usage "\n\n"
+//usage:       "Remove SHELLs from /etc/shells"
+
+#include "libbb.h"
+
+#define SHELLS_FILE "/etc/shells"
+
+#define REMOVE_SHELL (ENABLE_REMOVE_SHELL && (!ENABLE_ADD_SHELL || applet_name[0] == 'r'))
+#define ADD_SHELL    (ENABLE_ADD_SHELL && (!ENABLE_REMOVE_SHELL || applet_name[0] == 'a'))
+
+/* NB: we use the _address_, not the value, of this string
+ * as a "special value of pointer" in the code.
+ */
+static const char dont_add[] ALIGN1 = "\n";
+
+int add_remove_shell_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int add_remove_shell_main(int argc UNUSED_PARAM, char **argv)
+{
+       FILE *orig_fp;
+       char *orig_fn;
+       char *new_fn;
+
+       argv++;
+
+       orig_fn = xmalloc_follow_symlinks(SHELLS_FILE);
+       if (!orig_fn)
+               return EXIT_FAILURE;
+       orig_fp = fopen_for_read(orig_fn);
+
+       new_fn = xasprintf("%s.tmp", orig_fn);
+       xmove_fd(xopen(new_fn, O_WRONLY | O_CREAT | O_EXCL), STDOUT_FILENO);
+
+       /* TODO:
+       struct stat sb;
+       fstat(fileno(orig_fp), &sb);
+       xfchown(STDOUT_FILENO, sb.st_uid, sb.st_gid);
+       xfchmod(STDOUT_FILENO, sb.st_mode);
+       */
+
+       if (orig_fp) {
+               /* Copy old file, possibly skipping removed shell names */
+               char *line;
+               while ((line = xmalloc_fgetline(orig_fp)) != NULL) {
+                       char **cpp = argv;
+                       while (*cpp) {
+                               if (strcmp(*cpp, line) == 0) {
+                                       /* Old file has this shell name */
+                                       if (REMOVE_SHELL) {
+                                               /* we are remove-shell */
+                                               /* delete this name by not copying it */
+                                               goto next_line;
+                                       }
+                                       /* we are add-shell */
+                                       /* mark this name as "do not add" */
+                                       *cpp = (char*)dont_add;
+                               }
+                               cpp++;
+                       }
+                       /* copy shell name from old to new file */
+                       printf("%s\n", line);
+ next_line:
+                       free(line);
+               }
+               if (ENABLE_FEATURE_CLEAN_UP)
+                       fclose(orig_fp);
+       }
+
+       if (ADD_SHELL) {
+               char **cpp = argv;
+               while (*cpp) {
+                       if (*cpp != dont_add)
+                               printf("%s\n", *cpp);
+                       cpp++;
+               }
+       }
+
+       /* Ensure we wrote out everything */
+       if (fclose(stdout) != 0) {
+               xunlink(new_fn);
+               bb_perror_msg_and_die("%s: write error", new_fn);
+       }
+
+       /* Small hole: if rename fails, /etc/shells.tmp is not removed */
+       xrename(new_fn, orig_fn);
+
+       if (ENABLE_FEATURE_CLEAN_UP) {
+               free(orig_fn);
+               free(new_fn);
+       }
+
+       return EXIT_SUCCESS;
+}