aboutsummaryrefslogtreecommitdiff
path: root/src/proone-pack.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/proone-pack.c')
-rw-r--r--src/proone-pack.c145
1 files changed, 145 insertions, 0 deletions
diff --git a/src/proone-pack.c b/src/proone-pack.c
new file mode 100644
index 0000000..2098f4e
--- /dev/null
+++ b/src/proone-pack.c
@@ -0,0 +1,145 @@
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/sendfile.h>
+#include <fcntl.h>
+
+#include "protocol.h"
+
+
+int main (const int argc, const char **args) {
+ typedef struct {
+ prne_arch_t arch;
+ const char *path;
+ } archive_tuple_t;
+ size_t i;
+ const archive_tuple_t *encounter_arr[NB_PRNE_ARCH];
+ archive_tuple_t archive_arr[NB_PRNE_ARCH];
+ archive_tuple_t *archive;
+ size_t archive_arr_cnt = 0;
+ const char *path, *ext;
+ bool proc_result = true;
+ prne_arch_t arch;
+ int bin_fd = -1;
+ struct stat st;
+ uint8_t head[4];
+
+ if (argc <= 1) {
+ fprintf(stderr, "Usage: %s <path to binary 1> [path to binary 2 [path to binary ...]]\n", args[0]);
+ return 1;
+ }
+ // refuse to run if stdout is terminal
+ if (isatty(STDOUT_FILENO)) {
+ fprintf(stderr, "** Refusing to print on terminal.\n");
+ return 1;
+ }
+ // too many files
+ if (argc - 1 > NB_PRNE_ARCH) {
+ fprintf(stderr, "** Too many files given (%d > %d).\n", argc - 1, NB_PRNE_ARCH);
+ return 1;
+ }
+
+ // init
+ memset(encounter_arr, 0, sizeof(archive_tuple_t*) * NB_PRNE_ARCH);
+ memset(archive_arr, 0, sizeof(archive_tuple_t) * NB_PRNE_ARCH);
+
+ // Check the file names are valid
+ for (i = 1; i < (size_t)argc; i += 1) {
+ path = args[i];
+
+ ext = strrchr(path, '.');
+ if (ext == NULL) {
+ fprintf(stderr, "** %s: file extension not found\n", path);
+ proc_result = false;
+ continue;
+ }
+ ext += 1;
+
+ arch = prne_str2arch(ext);
+ if (arch == PRNE_ARCH_NONE) {
+ fprintf(stderr, "** %s: unknown arch \"%s\"\n", path, ext);
+ proc_result = false;
+ continue;
+ }
+
+ if (encounter_arr[arch] != NULL) {
+ fprintf(stderr, "** Duplicate arch!\n%s\n%s\n", encounter_arr[arch]->path, path);
+ proc_result = false;
+ continue;
+ }
+
+ archive_arr[archive_arr_cnt].arch = arch;
+ archive_arr[archive_arr_cnt].path = path;
+ encounter_arr[arch] = &archive_arr[archive_arr_cnt];
+ archive_arr_cnt += 1;
+ }
+ if (!proc_result) {
+ return 1;
+ }
+
+ // do packing
+ fprintf(stderr, archive_arr_cnt == NB_PRNE_ARCH ? "Packing %zu binaries.\n" : "* Warning: packing only %zu binaries\n", archive_arr_cnt);
+ for (i = 0; i < archive_arr_cnt; i += 1) {
+ archive = &archive_arr[i];
+ fprintf(stderr, "Packing: %s ...\n", archive->path);
+
+ bin_fd = open(archive->path, O_RDONLY);
+ if (bin_fd < 0) {
+ perror("** open()");
+ proc_result = false;
+ break;
+ }
+
+ // get size
+ if (fstat(bin_fd, &st) != 0) {
+ perror("** fstat()");
+ proc_result = false;
+ break;
+ }
+ if (st.st_size == 0) {
+ fprintf(stderr, "** empty file!\n");
+ proc_result = false;
+ break;
+ }
+ if (st.st_size > 0x00FFFFFE) {
+ fprintf(stderr, "** binary too large!\n");
+ proc_result = false;
+ break;
+ }
+
+ // write head
+ head[0] = (uint8_t)archive->arch;
+ // endian conversion as the file is big endian
+ head[1] = (uint8_t)(((uint32_t)st.st_size & 0x00FF0000) >> 16);
+ head[2] = (uint8_t)(((uint32_t)st.st_size & 0x0000FF00) >> 8);
+ head[3] = (uint8_t)((uint32_t)st.st_size & 0x000000FF);
+ if (write(STDOUT_FILENO, head, 4) != 4) {
+ perror("write()");
+ proc_result = false;
+ break;
+ }
+
+ // write binary
+ if (sendfile(STDOUT_FILENO, bin_fd, NULL, st.st_size) < 0) {
+ perror("** sendfile()");
+ proc_result = false;
+ break;
+ }
+
+ close(bin_fd);
+ bin_fd = -1;
+ }
+
+ close(bin_fd);
+ bin_fd = -1;
+ errno = 0;
+
+ return proc_result ? 0 : 2;
+}