aboutsummaryrefslogtreecommitdiff
path: root/src/proone-packer.c
blob: 3568bf86f150ac4f3fa5d10a4cc8ea391e4aea5f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
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 "proone_protocol.h"


int main (const int args, const char **argc) {
    typedef struct {
        proone_arch_t arch;
        const char *path;
    } archive_tuple_t;
    size_t i;
    const archive_tuple_t *encounter_arr[NB_PROONE_ARCH];
    archive_tuple_t archive_arr[NB_PROONE_ARCH];
    archive_tuple_t *archive;
    size_t archive_arr_cnt = 0;
    const char *path, *ext;
    bool proc_result = true;
    proone_arch_t arch;
    int bin_fd = -1;
    struct stat st;
    uint8_t head[4];

    if (args <= 1) {
        fprintf(stderr, "Usage: %s <path to binary 1> [path to binary 2 [path to binary ...]]\n", argc[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 (args - 1 > NB_PROONE_ARCH) {
        fprintf(stderr, "** Too many files given (%d > %d).\n", args - 1, NB_PROONE_ARCH);
        return 1;
    }

    // init
    memset(encounter_arr, 0, sizeof(archive_tuple_t*) * NB_PROONE_ARCH);
    memset(archive_arr, 0, sizeof(archive_tuple_t) * NB_PROONE_ARCH);

    // Check the file names are valid
    for (i = 1; i < (size_t)args; i += 1) {
        path = argc[i];

        ext = strrchr(path, '.');
        if (ext == NULL) {
            fprintf(stderr, "** %s: file extension not found\n", path);
            proc_result = false;
            continue;
        }
        ext += 1;

        arch = proone_str2arch(ext);
        if (arch == PROONE_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_PROONE_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;
}