diff options
Diffstat (limited to 'src/cmdline.c')
-rw-r--r-- | src/cmdline.c | 429 |
1 files changed, 0 insertions, 429 deletions
diff --git a/src/cmdline.c b/src/cmdline.c deleted file mode 100644 index 25939cb..0000000 --- a/src/cmdline.c +++ /dev/null @@ -1,429 +0,0 @@ -/** - * MIT/X Consortium License - * - * Copyright © 2015 Mattias Andrée <maandree@member.fsf.org> - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ -#include "bus.h" - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <grp.h> -#include <pwd.h> - - - -/** - * Statement wrapper that goes to `fail` on failure - */ -#define t(inst) if ((inst) == -1) goto fail - - - -/** - * The name of the process - */ -char *argv0; - -/** - * The command to spawn when a message is received - */ -static const char *command; - - - -/** - * Spawn a command because a message has been received - * - * @param message The received message - * @param user_data Not used - * @return 1 (continue listening) on success, -1 on error - */ -static int -spawn_continue(const char *message, void *user_data) -{ - pid_t pid; - if (!message) - return 1; - if ((pid = fork())) - return pid == -1 ? -1 : 1; - setenv("msg", message, 1); - execlp("sh", "sh", "-c", command, NULL); - perror(argv0); - exit(1); - (void) user_data; -} - - -/** - * Spawn a command because a message has been received - * - * @param message The received message - * @param user_data Not used - * @return 0 (stop listening) on success, -1 on error, or 1 if `message` is `NULL` - */ -static int -spawn_break(const char *message, void *user_data) -{ - pid_t pid; - if (!message) - return 1; - if ((pid = fork())) - return pid == -1 ? -1 : 0; - setenv("msg", message, 1); - execlp("sh", "sh", "-c", command, NULL); - perror(argv0); - exit(1); - (void) user_data; -} - - -/** - * Parse a permission string - * - * @param str The permission string - * @param andnot Output paramter for the mask of bits to remove (before applying `*or`) - * @param or Output paramter for the mask of bits to apply - * @return 0 on success, -1 on error - */ -static int -parse_mode(const char *str, mode_t *andnot, mode_t *or) -{ -#define U S_IRWXU -#define G S_IRWXG -#define O S_IRWXO - const char *s = str; - int numerical = 1; - mode_t mode = 0; - char op = '='; - mode_t bits; - - *andnot = 0; - *or = 0; - - if (!*s) - return errno = 0, -1; - - for (s = str; *s; s++) { - if (('0' > *s) || (*s > '7')) { - numerical = 0; - break; - } else { - mode = (mode << 3) | (*s & 15); - } - } - - if (numerical) { - *andnot = U | G | O; - *or = mode; - *or &= U | G | O; - *or = (*or & U) ? (*or | U) : (*or & (mode_t)~U); - *or = (*or & G) ? (*or | G) : (*or & (mode_t)~G); - *or = (*or & O) ? (*or | O) : (*or & (mode_t)~O); - return 0; - } - - for (s = str; *s; s++) { - if (strchr("+-=", *s)) { - op = *s; - } else if (strchr("ugo", *s)) { - if (*s == 'u') - bits = U; - else if (*s == 'g') - bits = G; - else - bits = O; - if (op == '+') { - *andnot |= bits; - *or |= bits; - } - else if (op == '-') { - *andnot |= bits; - *or &= ~bits; - } - else if (op == '=') { - *andnot |= U | G | O; - *or |= bits; - } - } else { - return errno = 0, -1; - } - } - - return 0; -} - - -/** - * Parse a user name/identifier string - * - * @param str The user's name or identifier - * @param uid Output parameter for the user's identifier - * @return 0 on success, -1 on error - */ -static int -parse_uid(const char *str, uid_t *uid) -{ - const char *s = str; - int numerical = 1; - uid_t rc = 0; - struct passwd *pwd; - - if (!*s || (*s == ':')) - return errno = 0, -1; - - for (s = str; *s; s++) { - if (('0' > *s) || (*s > '9')) { - numerical = 0; - break; - } - } - - if (numerical) { - for (s = str; *s; s++) - rc = (rc * 10) + (*s & 15); - *uid = rc; - return 0; - } - - pwd = getpwnam(str); - if (!pwd) { - return -1; - } - *uid = pwd->pw_uid; - return 0; -} - - -/** - * Parse a group name/identifier string - * - * @param str The group's name or identifier - * @param gid Output parameter for the group's identifier - * @return 0 on success, -1 on error - */ -static int -parse_gid(const char *str, gid_t *gid) -{ - const char *s = str; - int numerical = 1; - gid_t rc = 0; - struct group *grp; - - if (!*s || strchr(s, ':')) - return errno = 0, -1; - - for (s = str; *s; s++) { - if (('0' > *s) || (*s > '9')) { - numerical = 0; - break; - } - } - - if (numerical) { - for (s = str; *s; s++) - rc = (rc * 10) + (*s & 15); - *gid = rc; - return 0; - } - - grp = getgrnam(str); - if (!grp) - return -1; - *gid = grp->gr_gid; - return 0; -} - - -/** - * Parse a ownership string - * - * @param str The ownership string - * @param uid Output parameter for the owner, `NULL` if `str` only contains the group - * @param gid Output parameter for the group, `NULL` if `str` only contains the owner - * @return 0 on success, -1 on error - */ -static int -parse_owner(char *str, uid_t *uid, gid_t *gid) -{ - int r = 0; - char* group; - - if (!uid) - return parse_gid(str, gid); - if (!gid) - return parse_uid(str, uid); - - group = strchr(str, ':'); - *group++ = 0; - - r = parse_gid(group, gid); - if (r) - return r; - return parse_uid(str, uid); -} - - - -/** - * Main function of the command line interface for the bus system - * - * @param argc The number of elements in `argv` - * @param argv The command. Valid commands: - * <argv0> create [-x] [--] [<path>] # create a bus - * <argv0> remove [--] <path> # remove a bus - * <argv0> listen [--] <path> <command> # listen for new messages - * <argv0> wait [--] <path> <command> # listen for one new message - * <argv0> broadcast [-n] [--] <path> <message> # broadcast a message - * <argv0> chmod [--] <mode> <path> # change permissions - * <argv0> chown [--] <owner>[:<group>] <path> # change ownership - * <argv0> chgrp [--] <group> <path> # change group - * <command> will be spawned with $arg set to the message - * @return 0 on sucess, 1 on error, 2 on invalid command - */ -int -main(int argc, char *argv[]) -{ - bus_t bus; - char *file; - struct stat attr; - uid_t uid; - gid_t gid; - mode_t mode_andnot, mode_or; - int opt_x = 0, opt_n = 0; - const char *arg; - char **nonoptv = alloca((size_t)argc * sizeof(char*)); - int nonoptc = 0; - - argv0 = *argv++; - argc--; - - /* Parse arguments. */ - while (argc) { - if (!strcmp(*argv, "--")) { - argv++; - argc--; - break; - } else if (**argv == '-') { - arg = *argv++; - argc--; - for (arg++; *arg; arg++) { - if (*arg == 'x') - opt_x = 1; - else if (*arg == 'n') - opt_n = 1; - else - return -2; - } - } else { - *nonoptv++ = *argv++; - nonoptc++; - argc--; - } - } - while (argc) { - *nonoptv++ = *argv++; - nonoptc++; - argc--; - } - nonoptv -= nonoptc; - - /* Check options. */ - if (opt_x && strcmp(nonoptv[0], "create") && (nonoptc != 2)) - return 2; - if (opt_n && strcmp(nonoptv[0], "broadcast") && (nonoptc != 3)) - return 2; - - /* Create a new bus with selected name. */ - if ((nonoptc == 2) && !strcmp(nonoptv[0], "create")) { - t(bus_create(nonoptv[1], opt_x * BUS_EXCL, NULL)); - - /* Create a new bus with random name. */ - } else if ((nonoptc == 1) && !strcmp(nonoptv[0], "create")) { - t(bus_create(NULL, 0, &file)); - printf("%s\n", file); - free(file); - - /* Remove a bus. */ - } else if ((nonoptc == 2) && !strcmp(nonoptv[0], "remove")) { - t(bus_unlink(nonoptv[1])); - - /* Listen on a bus in a loop. */ - } else if ((nonoptc == 3) && !strcmp(nonoptv[0], "listen")) { - command = nonoptv[2]; - t(bus_open(&bus, nonoptv[1], BUS_RDONLY)); - t(bus_read(&bus, spawn_continue, NULL)); - t(bus_close(&bus)); - - /* Listen on a bus for one message. */ - } else if ((nonoptc == 3) && !strcmp(nonoptv[0], "wait")) { - command = nonoptv[2]; - t(bus_open(&bus, nonoptv[1], BUS_RDONLY)); - t(bus_read(&bus, spawn_break, NULL)); - t(bus_close(&bus)); - - /* Broadcast a message on a bus. */ - } else if ((nonoptc == 3) && !strcmp(nonoptv[0], "broadcast")) { - t(bus_open(&bus, nonoptv[1], BUS_WRONLY)); - t(bus_write(&bus, nonoptv[2], opt_n * BUS_NOWAIT)); - t(bus_close(&bus)); - - /* Change permissions. */ - } else if ((nonoptc == 3) && !strcmp(nonoptv[0], "chmod")) { - t(parse_mode(nonoptv[1], &mode_andnot, &mode_or)); - t(stat(nonoptv[2], &attr)); - attr.st_mode &= ~mode_andnot; - attr.st_mode |= mode_or; - t(bus_chmod(nonoptv[2], attr.st_mode)); - - /* Change ownership. */ - } else if ((nonoptc == 3) && !strcmp(nonoptv[0], "chown")) { - if (strchr(nonoptv[1], ':')) { - t(parse_owner(nonoptv[1], &uid, &gid)); - t(bus_chown(nonoptv[2], uid, gid)); - } else { - t(parse_owner(nonoptv[1], &uid, NULL)); - t(stat(nonoptv[2], &attr)); - t(bus_chown(nonoptv[2], uid, attr.st_gid)); - } - - /* Change group. */ - } else if ((nonoptc == 3) && !strcmp(nonoptv[0], "chgrp")) { - t(parse_owner(nonoptv[1], NULL, &gid)); - t(stat(nonoptv[2], &attr)); - t(bus_chown(nonoptv[2], attr.st_uid, gid)); - - } else - return 2; - - return 0; - -fail: - if (errno == 0) - return 2; - perror(argv0); - return 1; -} - |