#include #include #include #include #include #include #include #include "iolib.h" #include "freedt.h" #include "config.h" /* SuSv3 says this is in unistd.h, but glibc and others don't include it. */ extern char **environ; void warn(const char *msg) { format(fd_err, "@c: @c\n", progname, msg); } void warn2(const char *msg1, const char *msg2) { format(fd_err, "@c: @c: @c\n", progname, msg1, msg2); } void die(const char *msg) { warn(msg); exit(111); } void die2(const char *msg1, const char *msg2) { warn2(msg1, msg2); exit(111); } static void show_version() { format(fd_out, "@c from freedt version " VERSION "\n", progname); } void version() { show_version(); exit(1); } void help() { show_version(); format(fd_out, "\n@c" "-V Show version information\n" "-? Show usage information\n", proghelp); exit(1); } void get_default_args(int argc, char **argv) { while (1) { int c = getopt(argc, argv, "+V?"); if (c == -1) break; switch (c) { case 'V': version(); default: help(); } } } void setuidgidroot() { char *root, *uid, *gid; root = getenv("ROOT"); if (root != NULL) { if (chdir(root) < 0) die2(root, "unable to chdir"); if (chroot(root) < 0) die2(root, "unable to chroot"); } gid = getenv("GID"); if (gid != NULL) { gid_t g = atoi(gid); if (setgid(g) < 0) die("unable to setgid"); if (setgroups(1, &g) < 0) die("unable to setgroups"); } uid = getenv("UID"); if (uid != NULL) { uid_t u = atoi(uid); if (setuid(u) < 0) die("unable to setuid"); } } static int environ_size() { int num = 0; char **p; for (p = environ; *p != NULL; p++) ++num; return num; } static int build_environ_copy() { static int have_run = 0; char **new_environ; int num, i; if (have_run) return 0; have_run = 1; num = environ_size(); new_environ = malloc((num + 1) * sizeof *new_environ); if (new_environ == NULL) return -1; for (i = 0; i < num; i++) { new_environ[i] = strdup(environ[i]); if (new_environ[i] == NULL) { while (--i >= 0) { free(new_environ[i]); } free(new_environ); return -1; } } new_environ[num] = NULL; environ = new_environ; return 0; } static char **find_environ(const char *name) { char **p; int l = strlen(name); for (p = environ; *p != NULL; p++) { if (strlen(*p) <= l) continue; if (strncmp(*p, name, l) == 0 && (*p)[l] == '=') return p; } return NULL; } int fdt_setenv(const char *name, const char *value) { char *s; char **p; if (build_environ_copy() < 0) return -1; s = malloc(strlen(name) + strlen(value) + 2); if (s == NULL) return -1; strcpy(s, name); strcat(s, "="); strcat(s, value); p = find_environ(name); if (p == NULL) { int num = environ_size(); char **new_environ; new_environ = realloc(environ, (num + 2) * sizeof *environ); if (new_environ == NULL) { free(s); return -1; } new_environ[num] = s; new_environ[num + 1] = NULL; environ = new_environ; } else { free(*p); *p = s; } return 0; } int fdt_unsetenv(const char *name) { char **p; if (build_environ_copy() < 0) return -1; p = find_environ(name); if (p == NULL) return -1; do { *p = *(p + 1); } while (*p++ != NULL); return 0; } void change_fd_flags(int fd, int add, int remove) { int flags = fcntl(fd, F_GETFL); if (flags < 0) die("unable to read FD flags"); flags |= add; flags &= ~remove; if (fcntl(fd, F_SETFL, flags) < 0) die("unable to set FD flags"); } void set_fd_cloexec(int fd) { if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) die("unable to set FD_CLOEXEC"); } void reliable_sleep(int seconds) { while (seconds > 0) seconds = sleep(seconds); } int lock_fd(int fd, int block) { struct flock lock; int rc; lock.l_type = F_WRLCK; lock.l_whence = SEEK_SET; lock.l_start = 0; lock.l_len = 0; do { rc = fcntl(fd, block ? F_SETLKW : F_SETLK, &lock); } while (rc < 0 && errno == EINTR); return rc; }