summaryrefslogtreecommitdiffstats
path: root/aports-cache.c
diff options
context:
space:
mode:
authorNatanael Copa <ncopa@alpinelinux.org>2017-04-30 18:49:19 +0200
committerNatanael Copa <ncopa@alpinelinux.org>2017-04-30 19:09:32 +0200
commit141fe72708cfe1d2d0643290242825cf31772027 (patch)
tree6a635fb6d1195a09f5cb02124c09f02adc334873 /aports-cache.c
parente4a21ab9165074353d265a183063333892ca2ccc (diff)
downloadaports-cache-141fe72708cfe1d2d0643290242825cf31772027.tar.bz2
aports-cache-141fe72708cfe1d2d0643290242825cf31772027.tar.xz
spawn shell and parse APKBUILDs
Diffstat (limited to 'aports-cache.c')
-rw-r--r--aports-cache.c145
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;
}