diff options
Diffstat (limited to 'aports-cache.c')
-rw-r--r-- | aports-cache.c | 145 |
1 files changed, 134 insertions, 11 deletions
diff --git a/aports-cache.c b/aports-cache.c index b0dfdf0..728acef 100644 --- a/aports-cache.c +++ b/aports-cache.c @@ -1,5 +1,8 @@ #include <sys/stat.h> #include <sys/types.h> +#include <sys/wait.h> + +#define _GNU_SOURCE #include <errno.h> #include <dirent.h> @@ -10,6 +13,7 @@ #include <stdio.h> #include <string.h> #include <unistd.h> +#include <spawn.h> #ifdef DEBUG #define debug_printf(args...) fprintf(stderr, ## args) @@ -17,25 +21,109 @@ #define debug_printf(args...) #endif + +int spawn_shell_pipe(char *const argv[], pid_t *pid) +{ + int pipefd[2]; + posix_spawn_file_actions_t factions; + + if (pipe(pipefd) < 0) + err(1, "pipe"); + + if (posix_spawn_file_actions_init(&factions) < 0) + err(1, "posix_spawn_file_actions_init"); + + if (posix_spawn_file_actions_adddup2(&factions, pipefd[0], 0) < 0) + err(1, "posix_spawn_file_actions_adddup2"); + + if (posix_spawn(pid, argv[0], &factions, NULL, argv, NULL) < 0) + err(1, "posiz_spawn"); + close(pipefd[0]); + + debug_printf("shellfd=%i\n", pipefd[1]); + return pipefd[1]; +} + +int read_apkbuild(int shellfd, int aportfd, size_t size, const char *name) +{ +#define ECHO_STR(var) "echo \" " #var ": $" #var "\"\n" +#define ECHO_LIST(var) "echo \" " #var ": \"$" #var "\n" + char *fmtbuf = + "unset pkgname" + " pkgver" + " pkgrel" + " arch" + " options" + " depends" + " makedepends" + " checkdepends" + " subpackages" + " source" + " license" + " url" + "\n" + "cd %s\n" + "aports_cache_pwd=\"$PWD\"\n" + + ". ./APKBUILD >/dev/null\n" + + "if [ \"$PWD\" != \"$aports_cache_pwd\" ]; then\n" + " echo \"%s: PWD changed\" >&2\n" + " exit 1\n" + "fi\n" + + "echo \"-\"\n" + ECHO_STR(pkgname) + ECHO_STR(pkgver) + ECHO_LIST(arch) + ECHO_LIST(options) + ECHO_LIST(depends) + ECHO_LIST(makedepends) + ECHO_LIST(checkdepends) + ECHO_LIST(subpackages) + ECHO_LIST(linuguas) + ECHO_LIST(source) + ECHO_STR(url) + ECHO_STR(license) + "cd ..\n\n"; + char buf[strlen(fmtbuf) + 512]; + size_t bufsize = snprintf(buf, sizeof(buf), fmtbuf, name, name); + ssize_t r, offs=0; + + while (1) { + r = write(shellfd, &buf[offs], bufsize - offs); + if (r < 0) + err(1, "shell pipe"); + offs += r; + if (r == 0 || offs == bufsize) + break; + } + + return 0; +} + int is_newer(struct timespec a, struct timespec b) { return (a.tv_sec == b.tv_sec) ? a.tv_nsec > b.tv_nsec : a.tv_sec > b.tv_sec; } -int cache_invalid(int dirfd, const char *filename) +int cache_refresh_or_check(int dirfd, const char *cachefile, int shellfd) { struct stat cache; DIR *dir; struct dirent *ent; int r = 0; + int dirfd2 = dup(dirfd); - if (fstatat(dirfd, filename, &cache, 0) == -1) + debug_printf("shellfd(check)||:=%i\n", shellfd); + if (shellfd == -1 && fstatat(dirfd, cachefile, &cache, 0) == -1) return 1; - dir = fdopendir(dirfd); + dir = fdopendir(dirfd2); if (dir == NULL) - err(1, "fdopendir"); + return -1; + debug_printf("dir opened\n"); while(1) { char buf[PATH_MAX]; struct stat apkbuild; @@ -52,13 +140,23 @@ int cache_invalid(int dirfd, const char *filename) continue; snprintf(buf, sizeof(buf), "%s/APKBUILD", ent->d_name); + if (fstatat(dirfd, buf, &apkbuild, 0) == -1) { warn("%s", buf); continue; } + if (shellfd != -1) { + int fd = openat(dirfd, buf, O_RDONLY); + if (fd == -1) + err(1, "%s", buf); + read_apkbuild(shellfd, fd, apkbuild.st_size, ent->d_name); + close(fd); + continue; + } + if (is_newer(apkbuild.st_mtim, cache.st_mtim)) { - debug_printf("%s\n", buf); + debug_printf("modified: %s\n", buf); r = 1; break; } @@ -68,28 +166,47 @@ int cache_invalid(int dirfd, const char *filename) return r; } +int cache_check(int dirfd, const char *cachefile) +{ + return cache_refresh_or_check(dirfd, cachefile, -1); +} + +int cache_refresh(int dirfd, const char *cachefile, char *const shell_argv[]) +{ + pid_t shell_pid; + int shellfd = spawn_shell_pipe(shell_argv, &shell_pid); + + cache_refresh_or_check(dirfd, cachefile, shellfd); + write(shellfd, "exit\n", 5); + wait(NULL); + return 0; +} + int main(int argc, char *argv[]) { static struct option opts[] = { {"verbose", no_argument, 0, 'v' }, {"force", no_argument, 0, 'f' }, + {"shell", required_argument, 0, 's' }, { 0, 0, 0, 0} }; int i, c, verbose=0; - const char *cachefile = ".aports.cache.json"; + const char *cachefile = ".aports.cache.yaml"; char dirpath_buf[PATH_MAX]; char *dirpath = dirpath_buf; int dirfd; + char *shell_argv[] = {"/bin/sh", NULL}; - while ((c = getopt_long(argc, argv, "fv", opts, &i)) != -1) { + while ((c = getopt_long(argc, argv, "fs:v", opts, &i)) != -1) { switch(c) { + case 's': + shell_argv[0] = optarg; + break; case 'v': verbose = 1; break; } } - if (verbose) - printf("optind=%i, argc=%i\n", optind, argc); if (optind < argc) { dirpath = argv[optind]; @@ -100,9 +217,15 @@ int main(int argc, char *argv[]) dirfd = open(dirpath, O_DIRECTORY); if (dirfd < 0) err(1, "%s", dirpath); + fchdir(dirfd); - if (cache_invalid(dirfd, cachefile)) - printf("refresh\n"); + if (!cache_check(dirfd, cachefile)) + return 0; + + if (verbose) + printf("updating cache for %s\n", dirpath); + cache_refresh(dirfd, cachefile, shell_argv); + close(dirfd); return 0; } |