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
148
149
150
|
#include "build_db.h"
#include "cfg.h"
#include "util.h"
#include "source_db.h"
#include <poll.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <errno.h>
#define API_MESSAGE_NONE 0
#define API_MESSAGE_FINISHED 1
#define API_MESSAGE_TEST 2
bool package_setup_build(const package_info_t* info, package_build_t* build) {
// get timestamp string
char timestamp_str[32];
{
// get time in ms
struct timespec ts;
if (clock_gettime(CLOCK_REALTIME, &ts) != 0) die("failed to get time: %s", strerror(errno));
unsigned long long total_ms = ((unsigned long long)ts.tv_sec * 1000) + (ts.tv_nsec / 1000000);
snprintf(timestamp_str, sizeof(timestamp_str), "%llu", total_ms);
}
// create build info
memset(build, 0, sizeof(*build));
build->package = info;
build->directory = vastrcat(cfg.build_db, "/", info->attrs.id, "-", timestamp_str);
// create build directory
if (mkdir(build->directory, 0777) == -1) die("failed to create build directory: %s", strerror(errno));
// (re)create symlink to build directory
char* symlink_name = vastrcat(cfg.build_db, "/", info->attrs.id);
if (unlink(symlink_name) == -1 && errno != ENOENT) die("failed to remove build symlink '%s': %s", symlink_name, strerror(errno));
if (symlink(build->directory + cfg.build_db_len + 1, symlink_name) == -1) die("failed to create build symlink '%s': %s", symlink_name, strerror(errno));
free(symlink_name);
// unpack package source (eventually this will be done by swenu api)
build->source_directory = join_path(build->directory, "source");
unpack_source(&info->attrs.source, build->source_directory);
// todo - create paths for log files
// todo - create rebuild script
return true;
}
void build_run(const package_build_t* build) {
int api_from_sh[2] = {0};
if (pipe(api_from_sh) < 0) die("failed to open api endpoint pipe: %s", strerror(errno));
int api_to_sh[2] = {0};
if (pipe(api_to_sh) < 0) die("failed to open api response pipe: %s", strerror(errno));
// PIPE and FORK to run install script
int child_output[2] = {0};
if (pipe(child_output) < 0) die("failed to pipe: %s", strerror(errno));
pid_t pid = fork();
if (pid < 0) die("failed to fork: %s", strerror(errno));
if (pid == 0) {
// child proc
// connect my stdout and stderr to the pipe
close(child_output[0]);
dup2(child_output[1], STDOUT_FILENO);
dup2(child_output[1], STDERR_FILENO);
close(child_output[1]);
// close unused api pipes
close(api_from_sh[0]);
close(api_to_sh[1]);
char buf1[1024];
snprintf(buf1, sizeof(buf1), "%d", api_from_sh[1]);
char buf2[1024];
snprintf(buf2, sizeof(buf2), "%d", api_to_sh[0]);
// exec into install script
chdir(build->source_directory);
char* argv[] = { cfg.build_package_script, buf1, buf2, build->package->script_path, NULL };
execv(cfg.build_package_script, argv);
// what are you still doing here?
die("CHILD - execve to %s failed: %s", cfg.build_package_script, strerror(errno));
} else {
// parent proc, close write end of pipe
close(child_output[1]);
// close unused api pipes
close(api_from_sh[1]);
close(api_to_sh[0]);
}
// all of this should be rewritten
char buf[4096];
ssize_t bytes_read = 0;
struct pollfd pollfds[] = {
{ .fd = api_from_sh[0], .events = POLLIN, .revents = 0 },
{ .fd = child_output[0], .events = POLLIN, .revents = 0 }
};
bool finished = false;
while (!finished) {
if (poll(pollfds, sizeof(pollfds) / sizeof(*pollfds), 0) < 0) {
die("polling child process fds failed %s", strerror(errno));
}
if (pollfds[1].revents == POLLIN) {
bytes_read = read(child_output[0], buf, sizeof(buf));
if (bytes_read < 0) die("failed to read from child output: %s", strerror(errno));
// print build out, can log and stuff in future
printf("%.*s", (int)bytes_read, buf);
}
if (pollfds[0].revents == POLLIN) {
int api_call = 0;
bytes_read = read(api_from_sh[0], &api_call, sizeof(api_call));
if (bytes_read < 0) {
print("reading from api pipe failed: %s\n", strerror(errno));
}
switch (api_call) {
case API_MESSAGE_FINISHED:
finished = true;
break;
case API_MESSAGE_TEST:
printf("api test\n");
write(api_to_sh[1], "api test\n", strlen("api test\n"));
break;
case API_MESSAGE_NONE:
break;
}
}
}
while ((bytes_read = read(child_output[0], buf, sizeof(buf))) > 0) {
// print build out, can log and stuff in future
printf("%.*s", (int)bytes_read, buf);
}
if (bytes_read < 0) die("failed to read from pipe: %s", strerror(errno));
close(child_output[0]);
// close api pipes
close(api_from_sh[0]);
close(api_to_sh[1]);
// reap the child to finish
int wstatus;
if (waitpid(pid, &wstatus, 0) < 0) die("waitpid failed: %s", strerror(errno));
if (WEXITSTATUS(wstatus) != 0) die("the child failed to execute install script");
}
|