From b6aa1c857c9cf4c2d54681875761fa5107433771 Mon Sep 17 00:00:00 2001 From: Roy Marples Date: Wed, 19 Sep 2007 16:27:37 +0000 Subject: [PATCH] Added the checkown applet based on the work by Renato Caldas, #192682 checkdir ensures that the specified files (or directories) are owned by the current user/group or as specified on the command line. You can optionally check permissions too. --- ChangeLog | 5 ++ src/Makefile | 4 +- src/_usage.h | 6 +- src/builtins.h | 1 + src/checkown.c | 179 ++++++++++++++++++++++++++++++++++++++++ src/mountinfo.c | 7 +- src/rc.c | 2 + src/start-stop-daemon.c | 13 +-- 8 files changed, 197 insertions(+), 20 deletions(-) create mode 100644 src/checkown.c diff --git a/ChangeLog b/ChangeLog index 6f99ebac..e1b5f529 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,11 @@ 19 Sep 2007; Roy Marples : + Added the checkown applet based on the work by Renato Caldas, #192682 + checkdir ensures that the specified files (or directories) are owned + by the current user/group or as specified on the command line. You can + optionally check permissions too. + Change from /lib/rcscripts to /lib/rc and adjust our files so changing our libdir is much easier in future. This move makes sense it's so much more than a holding place for our scripts now. It also has the added diff --git a/src/Makefile b/src/Makefile index 4da64061..96799aaa 100644 --- a/src/Makefile +++ b/src/Makefile @@ -56,7 +56,7 @@ LIBRCSO = librc.so.$(LIBRCSOVER) LIBRCOBJS = librc.o librc-depend.o librc-daemon.o librc-misc.o librc-strlist.o LDLIBS_LIBRC = -leinfo -RCOBJS = env-update.o fstabinfo.o mountinfo.o \ +RCOBJS = checkown.o env-update.o fstabinfo.o mountinfo.o \ rc-depend.o rc-plugin.o rc-status.o rc-update.o runscript.o \ start-stop-daemon.o rc.o LDLIBS_RC = $(LDLIBS_LIBRC) -lrc @@ -80,7 +80,7 @@ RCLINKS = einfon einfo ewarnn ewarn eerrorn eerror ebegin eend ewend \ mark_service_coldplugged \ get_options save_options rc-abort rc-depend \ is_runlevel_start is_runlevel_stop service_started_daemon \ - fstabinfo mountinfo + checkown fstabinfo mountinfo BINLINKS = rc-status SBINLINKS = env-update rc-update runscript start-stop-daemon diff --git a/src/_usage.h b/src/_usage.h index 56ea8f6e..6f48cf8a 100644 --- a/src/_usage.h +++ b/src/_usage.h @@ -7,12 +7,14 @@ * Released under the GPLv2 */ -#define getoptstring_COMMON "Ch" +#define getoptstring_COMMON "Chq" #define longopts_COMMON \ { "help", 0, NULL, 'h'}, \ - { "nocolor", 0, NULL, 'C'}, + { "nocolor", 0, NULL, 'C'}, \ + { "quiet", 0, NULL, 'q'}, #define case_RC_COMMON_GETOPT \ case 'C': setenv ("RC_NOCOLOR", "yes", 1); break; \ case 'h': usage (EXIT_SUCCESS); \ + case 'q': setenv ("RC_QUIET", "yes", 1); break; \ default: usage (EXIT_FAILURE); diff --git a/src/builtins.h b/src/builtins.h index 62a406b1..c234ad83 100644 --- a/src/builtins.h +++ b/src/builtins.h @@ -7,6 +7,7 @@ * Released under the GPLv2 */ +int checkown (int argc, char **argv); int env_update (int argc, char **argv); int fstabinfo (int argc, char **argv); int mountinfo (int argc, char **argv); diff --git a/src/checkown.c b/src/checkown.c new file mode 100644 index 00000000..5326321a --- /dev/null +++ b/src/checkown.c @@ -0,0 +1,179 @@ +/* + checkown.c + Checks for the existance of a directory and creates it + if necessary. It can also correct its ownership. + + Copyright 2007 Gentoo Foundation + */ + +#define APPLET "checkown" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "builtins.h" +#include "einfo.h" + +static char *applet = NULL; + +static int do_check (char *path, uid_t uid, gid_t gid, mode_t mode) +{ + struct stat dirstat; + + memset (&dirstat, 0, sizeof (dirstat)); + + if (stat (path, &dirstat)) { + einfo ("%s: creating directory", path); + if (! mode) + mode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH; + if (mkdir (path, mode)) { + eerror ("%s: mkdir: %s", applet, strerror (errno)); + return (-1); + } + } else if (mode && (dirstat.st_mode & 0777) != mode) { + einfo ("%s: correcting mode", applet); + if (chmod (path, mode)) { + eerror ("%s: chmod: %s", applet, strerror (errno)); + return (-1); + } + } + + if (dirstat.st_uid != uid || dirstat.st_gid != gid) { + if (dirstat.st_dev || dirstat.st_ino) + einfo ("%s: correcting owner", path); + if (chown (path, uid, gid)) { + eerror ("%s: chown: %s", applet, strerror (errno)); + return (-1); + } + } + + return (0); +} + +/* Based on busybox */ +static int parse_mode (mode_t *mode, char *text) +{ + /* Check for a numeric mode */ + if ((*mode - '0') < 8) { + char *p; + unsigned long l = strtoul (text, &p, 8); + if (*p || l > 07777U) { + errno = EINVAL; + return (-1); + } + *mode = l; + return (0); + } + + /* We currently don't check g+w type stuff */ + errno = EINVAL; + return (-1); +} + +static struct passwd *get_user (char **name) +{ + struct passwd *pw; + char *p = *name; + char *token; + int tid; + + token = strsep (&p, ":"); + if (sscanf (token, "%d", &tid) != 1) + pw = getpwnam (token); + else + pw = getpwuid (tid); + + if (! pw) + eerrorx ("%s: user `%s' not found", applet, token); + + *name = p; + return (pw); +} + +static struct group *get_group (const char *name) +{ + struct group *gr; + int tid; + + if (sscanf (name, "%d", &tid) != 1) + gr = getgrnam (name); + else + gr = getgrgid (tid); + + if (! gr) + eerrorx ("%s: group `%s' not found", applet, name); + + return (gr); +} + +#include "_usage.h" +#define getoptstring "m:g:u:" getoptstring_COMMON +static struct option longopts[] = { + { "mode", 1, NULL, 'm'}, + { "user", 1, NULL, 'u'}, + { "group", 1, NULL, 'g'}, + longopts_COMMON + { NULL, 0, NULL, 0} +}; +#include "_usage.c" + +int checkown (int argc, char **argv) +{ + int opt; + uid_t uid = geteuid(); + gid_t gid = getgid(); + mode_t mode = 0; + + struct passwd *pw = NULL; + struct group *gr = NULL; + char *p; + int retval = EXIT_SUCCESS; + + applet = argv[0]; + + while ((opt = getopt_long (argc, argv, getoptstring, + longopts, (int *) 0)) != -1) + { + switch (opt) { + case 'm': + if (parse_mode (&mode, optarg)) + eerrorx ("%s: invalid mode `%s'", applet, optarg); + break; + case 'u': + p = optarg; + pw = get_user (&p); + if (p && *p) + optarg = p; + else + break; + case 'g': + gr = get_group (optarg); + break; + + case_RC_COMMON_GETOPT + } + } + + if (pw) { + uid = pw->pw_uid; + gid = pw->pw_gid; + } + if (gr) + gid = gr->gr_gid; + + while (optind < argc) { + if (do_check (argv[optind], uid, gid, mode)) + retval = EXIT_FAILURE; + optind++; + } + + exit (retval); +} diff --git a/src/mountinfo.c b/src/mountinfo.c index 7ee663ae..6ed257a5 100644 --- a/src/mountinfo.c +++ b/src/mountinfo.c @@ -259,7 +259,6 @@ static struct option longopts[] = { { "options", 0, NULL, 'i'}, { "fstype", 0, NULL, 's'}, { "node", 0, NULL, 't'}, - { "quiet", 0, NULL, 'q'}, longopts_COMMON { NULL, 0, NULL, 0} }; @@ -274,7 +273,6 @@ int mountinfo (int argc, char **argv) char **nodes = NULL; char *n; int opt; - bool quiet = false; int result; #define DO_REG(_var) \ @@ -321,9 +319,6 @@ int mountinfo (int argc, char **argv) case 't': args.mount_type = mount_from; break; - case 'q': - quiet = true; - break; case_RC_COMMON_GETOPT } @@ -358,7 +353,7 @@ int mountinfo (int argc, char **argv) continue; if (skip_point_regex && regexec (skip_point_regex, n, 0, NULL, 0) == 0) continue; - if (! quiet) + if (! rc_is_env ("RC_QUIET", "yes")) printf ("%s\n", n); result = EXIT_SUCCESS; } diff --git a/src/rc.c b/src/rc.c index 49b53bed..850be074 100644 --- a/src/rc.c +++ b/src/rc.c @@ -759,6 +759,8 @@ int main (int argc, char **argv) exit (runscript (argc, argv)); else if (strcmp (applet, "start-stop-daemon") == 0) exit (start_stop_daemon (argc, argv)); + else if (strcmp (applet, "checkown") == 0) + exit (checkown (argc, argv)); argc--; argv++; diff --git a/src/start-stop-daemon.c b/src/start-stop-daemon.c index 76158c65..8b419959 100644 --- a/src/start-stop-daemon.c +++ b/src/start-stop-daemon.c @@ -461,7 +461,7 @@ static void handle_signal (int sig) #include "_usage.h" -#define getoptstring "KN:R:Sbc:d:g:mn:op:qs:tu:r:vx:1:2:" getoptstring_COMMON +#define getoptstring "KN:R:Sbc:d:g:mn:op:s:tu:r:vx:1:2:" getoptstring_COMMON static struct option longopts[] = { { "stop", 0, NULL, 'K'}, { "nicelevel", 1, NULL, 'N'}, @@ -476,7 +476,6 @@ static struct option longopts[] = { { "name", 1, NULL, 'n'}, { "oknodo", 0, NULL, 'o'}, { "pidfile", 1, NULL, 'p'}, - { "quiet", 0, NULL, 'q'}, { "signal", 1, NULL, 's'}, { "test", 0, NULL, 't'}, { "user", 1, NULL, 'u'}, @@ -507,7 +506,7 @@ int start_stop_daemon (int argc, char **argv) bool stop = false; bool oknodo = false; bool test = false; - bool quiet = false; + bool quiet; bool verbose = false; char *exec = NULL; char *cmd = NULL; @@ -635,10 +634,6 @@ int start_stop_daemon (int argc, char **argv) pidfile = optarg; break; - case 'q': /* --quiet */ - quiet = true; - break; - case 's': /* --signal */ sig = parse_signal (optarg); break; @@ -671,9 +666,7 @@ int start_stop_daemon (int argc, char **argv) case_RC_COMMON_GETOPT } - /* Respect RC as well as how we are called */ - if (rc_is_env ("RC_QUIET", "yes") && ! verbose) - quiet = true; + quiet = rc_is_env ("RC_QUIET", "yes"); /* Allow start-stop-daemon --signal HUP --exec /usr/sbin/dnsmasq * instead of forcing --stop --oknodo as well */