aboutsummaryrefslogtreecommitdiff
path: root/snag/pkg_db.c
blob: ad9eff3f28f739272afdea84462d25115b7c7696 (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
#include "pkg_db.h"
#include "util.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/wait.h>

#define PKG_DB "../packages"
#define PKG_DB_LEN (sizeof(PKG_DB) - 1)
#define PKG_INFO_CMD "./get_pkg_attrs.sh"

bool load_package_info(package_info_t* info, char* pkgid) {

    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) {
			eprintf("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", 4);
		free(pkg_dir);
		if (access(info->script_path, F_OK) != 0) {
			eprintf("Package '%s' broken, doesn't have description script\n", pkgid);
			free(info->script_path);
			return false;
		}
	}

	// PIPE and FORK to run get pkg attrs script
    int pipefds[2] = {0};
    if (pipe(pipefds) < 0) error_out("failed to pipe: %s", strerror(errno));
    pid_t pid = fork();
    if (pid < 0) error_out("failed to fork: %s", strerror(errno));

	// child proc
    if (pid == 0) {
		// write my stdout the 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);
		error_out("execve failed");
    }

	// wait for child to finish
    int wstatus;
    if (waitpid(pid, &wstatus, 0) < 0) error_out("waitpid failed: %s", strerror(errno));
	if (WEXITSTATUS(wstatus) != 0) error_out("failed to execute get pkg attr script");

	// read all bytes from pipe
    ssize_t bytes_read = read(pipefds[0], info->package_attrs, sizeof(info->package_attrs));
    if (bytes_read < 0) error_out("Failed to read from pipe");

	// read attributes from pipe data
    for (int i = 0; i < bytes_read;) {
        char atype = info->package_attrs[i];
        i++;
        switch (atype) {
        case 'i':
            info->attrs.id = &info->package_attrs[i];
            break;
        case 'n':
            info->attrs.name = &info->package_attrs[i];
            break;
        case 'd':
            info->attrs.desc = &info->package_attrs[i];
            break;
        }
        for(;info->package_attrs[i] && i < bytes_read; i++);
        i++;
    }

	return true;
}