summaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
authorRichard Maw <richard.maw@gmail.com>2014-09-24 16:24:48 +0000
committerRichard Maw <richard.maw@gmail.com>2014-10-01 09:30:14 +0000
commitb228561897aecea8a60908c354cee79938cf4e31 (patch)
treeba161de446ac54a762d8b810037b069521b2ebbc /scripts
parentb15babc4a166e476d5bcd3946e8db8e2d4583969 (diff)
downloadmorph-b228561897aecea8a60908c354cee79938cf4e31.tar.gz
Add test shell for use in staging area tests
This is intended to be statically linked, so it can be run in the staging area, without having to build a libc. You shouldn't generally statically link GLibc, because it dynamically links things like NSS modules or locale data, but we only need some very simple stuff, so we can get away with that. There's also potential licensing issues, as GLibc is LGPLv2, so distribution requires providing the ability to re-link against another library, but its use in the test-suite shouldn't count as distribution. There's a couple of commands, the only two needed by the yarn test suite are "copy files" which is like `cp -r . "$DESTDIR"`, and "false", which is for commands to deliberately fail.
Diffstat (limited to 'scripts')
-rw-r--r--scripts/test-shell.c144
1 files changed, 144 insertions, 0 deletions
diff --git a/scripts/test-shell.c b/scripts/test-shell.c
new file mode 100644
index 00000000..7975c188
--- /dev/null
+++ b/scripts/test-shell.c
@@ -0,0 +1,144 @@
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+
+#include <stdint.h>
+#include <ftw.h>
+#include <errno.h>
+
+char *readlinka(char const *path){
+ size_t buflen = BUFSIZ;
+ char *buf = malloc(buflen);
+ ssize_t read;
+ while ((read = readlink(path, buf, buflen - 1)) >= buflen - 1) {
+ char *newbuf = realloc(buf, buflen * 2);
+ if (newbuf == NULL) {
+ goto failure;
+ }
+ buf = newbuf;
+ buflen = buflen * 2;
+ }
+ buf[read] = '\0';
+ return buf;
+failure:
+ free(buf);
+ return NULL;
+}
+
+int copy_file_paths(char const *source_file, char const *target_file) {
+ int source_fd;
+ int target_fd;
+ int ret = -1;
+ struct stat st;
+ if ((source_fd = open(source_file, O_RDONLY)) == -1) {
+ return ret;
+ }
+ if (fstat(source_fd, &st) == -1) {
+ perror("stat");
+ ret = -2;
+ goto cleanup_in;
+ }
+ if ((target_fd = open(target_file, O_WRONLY|O_CREAT, st.st_mode)) == -1) {
+ ret = -3;
+ goto cleanup_in;
+ }
+ ssize_t read;
+ while ((read = sendfile(target_fd, source_fd, NULL, BUFSIZ)) > 0);
+ if (read < 0) {
+ perror("sendfile");
+ ret = -4;
+ }
+ ret = 0;
+cleanup_all:
+ close(target_fd);
+cleanup_in:
+ close(source_fd);
+ return ret;
+}
+
+int copy_entry(const char *fpath, const struct stat *sb, int typeflag,
+ struct FTW *ftwbuf) {
+ int ret = 0;
+ char *target_path = NULL;
+ if (asprintf(&target_path, "%s/%s", getenv("DESTDIR"), fpath) == -1) {
+ return -1;
+ }
+ switch (typeflag) {
+ case FTW_F:
+ /* Copy file */
+ if ((ret = copy_file_paths(fpath, target_path)) < 0) {
+ perror("Copy file");
+ ret = -1;
+ }
+ break;
+ case FTW_D:
+ case FTW_DNR:
+ /* Copy directory */
+ if (mkdir(target_path, sb->st_mode)) {
+ if (errno != EEXIST) {
+ perror("mkdir");
+ ret = -1;
+ }
+ }
+ break;
+ case FTW_NS:
+ case FTW_SL:
+ case FTW_SLN: {
+ /* Create symlink */
+ char *link_target = readlinka(fpath);
+ if (link_target == NULL) {
+ perror("readlink");
+ ret = -1;
+ }
+ if (symlink(link_target, target_path) == -1) {
+ perror("symlink");
+ ret = -1;
+ }
+ break;
+ }
+ }
+cleanup:
+ free(target_path);
+ return ret;
+}
+
+int main(int argc, char *argv[]) {
+ int ret = 1;
+ if (argc != 3 || strcmp(argv[1], "-c") != 0) {
+ fprintf(stderr, "Usage: %s -c COMMAND\n", argv[0]);
+ return 1;
+ }
+ size_t cmdlen = strlen(argv[2]);
+ FILE *cmdstream = fmemopen(argv[2], cmdlen, "r");
+ {
+ ssize_t read;
+ size_t len = 0;
+ char *line = NULL;
+
+ ret = 0;
+ while ((read = getline(&line, &len, cmdstream)) != -1) {
+ if (line[read - 1] == '\n') line[read - 1] = '\0';
+ if (strcmp(line, "copy files") == 0) {
+ /* Recursively copy contents of current dir to DESTDIR */
+ if (nftw(".", copy_entry, 20, FTW_PHYS)) {
+ ret = 1;
+ break;
+ }
+ } else if (strcmp(line, "false") == 0 ||
+ strstr(line, "false ") == line) {
+ ret = 1;
+ break;
+ } else {
+ ret = 127;
+ break;
+ }
+ }
+ free(line);
+ }
+ return ret;
+}