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
146
147
|
#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 "util_rt.h"
#include "util_ct.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
memzero(encounter_arr, sizeof(archive_tuple_t*) * NB_PRNE_ARCH);
memzero(archive_arr, 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_arch_fstr(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)(((uint_fast32_t)st.st_size & 0x00FF0000) >> 16);
head[2] = (uint8_t)(((uint_fast32_t)st.st_size & 0x0000FF00) >> 8);
head[3] = (uint8_t)((uint_fast32_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;
}
prne_close(bin_fd);
bin_fd = -1;
}
prne_close(bin_fd);
bin_fd = -1;
errno = 0;
return proc_result ? 0 : 2;
}
|