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
|
#include "package_db.h"
#include "cfg.h"
#include "util.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <errno.h>
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 = cfg.package_db_len + pkgid_len + 1;
char* pkg_dir = emalloc(pkg_dir_len + 1, "pkg_dir");
{
memcpy(pkg_dir, cfg.package_db, cfg.package_db_len);
pkg_dir[cfg.package_db_len] = '/';
memcpy(pkg_dir + cfg.package_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[] = { cfg.get_package_info_script, info->script_path, NULL };
char* envp[] = { NULL };
execve(cfg.get_package_info_script, argv, envp);
// what are you still doing here?
die("CHILD - execve to %s failed: %s", cfg.get_package_info_script, 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: %d", WEXITSTATUS(wstatus));
// 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 's':
info->attrs.source.name = &info->attrs.buffer[i]; break;
case 'u':
info->attrs.source.url = &info->attrs.buffer[i]; break;
case 'c':
info->attrs.source.checksum = &info->attrs.buffer[i]; break;
}
while(info->attrs.buffer[i] != '\0' && i < bytes_read) i++;
i++;
}
return true;
}
|