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
151
152
153
154
155
156
157
158
159
160
161
|
#include "package_db.h"
#include "util.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <errno.h>
#define PKG_INFO_CMD "./scripts/get_pkg_attrs.sh"
#define PKG_INST_CMD "./scripts/run_pkg_install.sh"
// note: fixed location of package database for now
const char pkg_db[] = "../packages";
const size_t pkg_db_len = sizeof(pkg_db) - 1;
bool load_package_info(char* pkgid, package_info_t* info) {
memset(info, 0, sizeof(*info));
size_t pkgid_len = strlen(pkgid);
// construct package description directory path and ensure it exists
// pkg_dir = "pkg_db/pkgid"
size_t pkg_dir_len = pkg_db_len + pkgid_len + 1;
char* pkg_dir = emalloc(pkg_dir_len + 1, "pkg_dir");
{
memcpy(pkg_dir, pkg_db, pkg_db_len);
pkg_dir[pkg_db_len] = '/';
memcpy(pkg_dir + pkg_db_len + 1, pkgid, pkgid_len);
pkg_dir[pkg_dir_len] = '\0';
if (access(pkg_dir, F_OK) != 0) {
print("Package '%s' not found\n", pkgid);
free(pkg_dir);
return false;
}
}
// construct package description script path and ensure it exists
// script_path = "pkg_dir/pkgid.sh"
size_t script_path_len = pkg_dir_len + pkgid_len + 4;
info->script_path = emalloc(script_path_len + 1, "info->script_path");
{
memcpy(info->script_path, pkg_dir, pkg_dir_len);
info->script_path[pkg_dir_len] = '/';
memcpy(&info->script_path[pkg_dir_len + 1], pkgid, pkgid_len);
memcpy(&info->script_path[script_path_len - 3], ".sh", 3);
info->script_path[script_path_len] = '\0';
free(pkg_dir);
if (access(info->script_path, F_OK) != 0) {
print("Package '%s' broken, doesn't have description script\n", pkgid);
free(info->script_path);
return false;
}
}
// PIPE and FORK to run pkg attrs script
int pipefds[2] = {0};
if (pipe(pipefds) < 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 to the pipe
close(pipefds[0]);
dup2(pipefds[1], STDOUT_FILENO);
close(pipefds[1]);
// exec into get attr script
char* argv[] = { PKG_INFO_CMD, info->script_path, NULL };
char* envp[] = { NULL };
execve(PKG_INFO_CMD, argv, envp);
// what are you still doing here?
die("CHILD - execve to %s failed: %s", PKG_INFO_CMD, strerror(errno));
} else {
// parent proc, close write end of pipe
close(pipefds[1]);
}
// wait for 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 get_pkg_attr script");
// read all bytes from pipe into attr buffer
ssize_t bytes_read = read(pipefds[0], info->attrs.buffer, sizeof(info->attrs.buffer));
if (bytes_read < 0) die("failed to read from pipe: %s", strerror(errno));
close(pipefds[0]);
// read attributes from attr buffer
// attribute format: type (char), data value (null terminated str)
// todo(jqj): switch over to dynamically allocated buffer
for (int i = 0; i < bytes_read;) {
char atype = info->attrs.buffer[i];
i++;
switch (atype) {
case 'i':
info->attrs.id = &info->attrs.buffer[i]; break;
case 'n':
info->attrs.name = &info->attrs.buffer[i]; break;
case 'd':
info->attrs.desc = &info->attrs.buffer[i]; break;
case 'w':
info->attrs.webpage = &info->attrs.buffer[i]; break;
case 'l':
info->attrs.license = &info->attrs.buffer[i]; break;
case 'v':
info->attrs.version = &info->attrs.buffer[i]; break;
case 'u':
info->attrs.source_url = &info->attrs.buffer[i]; break;
case 'h':
info->attrs.source_hash = &info->attrs.buffer[i]; break;
}
for(;info->attrs.buffer[i] && i < bytes_read; i++);
i++;
}
return true;
}
void run_package_install(const package_info_t* info) {
// PIPE and FORK to run install script
int pipefds[2] = {0};
if (pipe(pipefds) < 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(pipefds[0]);
dup2(pipefds[1], STDOUT_FILENO);
dup2(pipefds[1], STDERR_FILENO);
close(pipefds[1]);
// exec into install script
char* argv[] = { PKG_INST_CMD, info->script_path, NULL };
char* envp[] = { NULL };
execve(PKG_INST_CMD, argv, envp);
// what are you still doing here?
die("CHILD - execve to %s failed: %s", PKG_INST_CMD, strerror(errno));
} else {
// parent proc, close write end of pipe
close(pipefds[1]);
}
// read from the pipe until EOF
char buf[4096];
ssize_t bytes_read = 0;
while ((bytes_read = read(pipefds[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(pipefds[0]);
// 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");
}
|