diff options
author | Christian Hesse <mail@eworm.de> | 2014-12-23 18:25:17 +0100 |
---|---|---|
committer | Christian Hesse <mail@eworm.de> | 2014-12-23 18:25:17 +0100 |
commit | 11bd572adf4a861e4c42123c2dadbacd3349af93 (patch) | |
tree | 995a932a7c13b463ec46c1b096012bc999561fd1 /bin/ykfde-cpio.c | |
parent | c96ab47092b799c274a4021b19b7f9cb3ddbb98d (diff) | |
download | mkinitcpio-ykfde-11bd572adf4a861e4c42123c2dadbacd3349af93.tar.gz mkinitcpio-ykfde-11bd572adf4a861e4c42123c2dadbacd3349af93.tar.zst |
support updating the challenge on boot
Diffstat (limited to 'bin/ykfde-cpio.c')
-rw-r--r-- | bin/ykfde-cpio.c | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/bin/ykfde-cpio.c b/bin/ykfde-cpio.c new file mode 100644 index 0000000..71a39db --- /dev/null +++ b/bin/ykfde-cpio.c @@ -0,0 +1,220 @@ +/* + * (C) 2014 by Christian Hesse <mail@eworm.de> + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + * + * compile with: + * $ gcc -o mkcpio mkcpio.c -larchive + */ + +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif + +#include <dirent.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> + +#include <archive.h> +#include <archive_entry.h> + +#define CONFIGFILE "/etc/ykfde.conf" +#define CHALLENGEDIR "/etc/ykfde.d/" +#define CPIOFILE "/boot/ykfde-challenges.img" +#define CPIOTMPFILE CPIOFILE "-XXXXXX" + +int add_dir(struct archive *archive, const char * path) { + struct stat st; + struct archive_entry *entry; + int8_t rc; + + /* initialize struct stat for directories from root */ + if ((rc = stat("/", &st)) < 0) { + perror("stat() failed"); + goto out; + } + + if ((entry = archive_entry_new()) == NULL) { + rc = EXIT_FAILURE; + fprintf(stderr, "archive_entry_new() failed"); + goto out; + } + + archive_entry_set_pathname(entry, path); + archive_entry_set_filetype(entry, AE_IFDIR); + archive_entry_copy_stat(entry, &st); + if (archive_write_header(archive, entry) != ARCHIVE_OK) { + rc = EXIT_FAILURE; + fprintf(stderr, "archive_write_header() failed"); + goto out; + } + archive_entry_free(entry); + + rc = EXIT_SUCCESS; + +out: + return rc; +} + +int main(int argc, const char **argv) { + char cpiotmpfile[] = CPIOTMPFILE; + struct archive *archive; + struct archive_entry *entry; + struct stat st; + char buff[64]; + int len, fdfile, fdarchive; + DIR * dir; + struct dirent * ent; + char * filename, * path; + off_t pathlength = 0; + int8_t rc = EXIT_FAILURE; + + if ((rc = fdarchive = mkstemp(cpiotmpfile)) < 0) { + perror("mkstemp() failed"); + goto out10; + } + + if ((archive = archive_write_new()) == NULL) { + rc = EXIT_FAILURE; + fprintf(stderr, "archive_write_new() failed.\n"); + goto out10; + } + + if (archive_write_set_format_cpio_newc(archive) != ARCHIVE_OK) { + rc = EXIT_FAILURE; + fprintf(stderr, "archive_write_set_format_cpio_newc() failed.\n"); + goto out10; + } + + if (archive_write_open_fd(archive, fdarchive) != ARCHIVE_OK) { + rc = EXIT_FAILURE; + fprintf(stderr, "archive_write_open_fd() failed.\n"); + goto out10; + } + + if ((rc = add_dir(archive, ".")) < 0) { + fprintf(stderr, "add_dir() failed"); + goto out10; + } + + while (1) { + path = strdup(CHALLENGEDIR + 1); + if (strstr(path + pathlength, "/") == NULL) + break; + *strstr(path + pathlength, "/") = 0; + pathlength = strlen(path) + 1; + + if ((rc = add_dir(archive, path)) < 0) { + fprintf(stderr, "add_dir() failed"); + goto out10; + } + + free(path); + } + + if ((dir = opendir(CHALLENGEDIR)) != NULL) { + while ((ent = readdir(dir)) != NULL) { + filename = malloc(sizeof(CHALLENGEDIR) + strlen(ent->d_name) + 1); + sprintf(filename, CHALLENGEDIR "%s", ent->d_name); + + if ((rc = stat(filename, &st)) < 0) { + perror("stat() failed"); + goto out10; + } + + if (S_ISREG(st.st_mode)) { + if ((entry = archive_entry_new()) == NULL) { + rc = EXIT_FAILURE; + fprintf(stderr, "archive_entry_new() failed.\n"); + goto out10; + } + + /* these do not return exit code */ + archive_entry_set_pathname(entry, filename + 1); + archive_entry_set_size(entry, st.st_size); + archive_entry_set_filetype(entry, AE_IFREG); + archive_entry_set_perm(entry, 0644); + + if (archive_write_header(archive, entry) != ARCHIVE_OK) { + rc = EXIT_FAILURE; + fprintf(stderr, "archive_write_header() failed"); + goto out10; + } + + if ((rc = fdfile = open(filename, O_RDONLY)) < 0) { + perror("open() failed"); + goto out10; + } + + if ((rc = len = read(fdfile, buff, sizeof(buff))) < 0) { + perror("read() failed"); + goto out10; + } + + while (len > 0) { + if (( rc = archive_write_data(archive, buff, len)) < 0) { + fprintf(stderr, "archive_write_data() failed"); + goto out10; + } + + if ((rc = len = read(fdfile, buff, sizeof(buff))) < 0) { + perror("read() failed"); + goto out10; + } + } + + if ((rc = close(fdfile)) < 0) { + perror("close() failed"); + goto out10; + } + + archive_entry_free(entry); + } + free(filename); + } + if ((rc = closedir(dir)) < 0) { + perror("closedir() failed"); + goto out10; + } + } else { + rc = EXIT_FAILURE; + perror("opendir() failed"); + goto out10; + } + + if (archive_write_close(archive) != ARCHIVE_OK) { + rc = EXIT_FAILURE; + fprintf(stderr, "archive_write_close() failed"); + goto out10; + } + + if (archive_write_free(archive) != ARCHIVE_OK) { + rc = EXIT_FAILURE; + fprintf(stderr, "archive_write_free() failed"); + goto out10; + } + + if (access(CPIOFILE, F_OK) == 0 && (rc = unlink(CPIOFILE)) < 0) { + perror("unkink() failed"); + goto out10; + } + + if ((rc = rename(cpiotmpfile, CPIOFILE)) < 0) { + perror("rename() failed"); + goto out10; + } + + rc = EXIT_SUCCESS; + +out10: + if (access(cpiotmpfile, F_OK) == 0) + unlink(cpiotmpfile); + + return rc; +} + +// vim: set syntax=c: |