aboutsummaryrefslogtreecommitdiff
path: root/snag/pkg_db.c
blob: 032c089559096296442e1bf97d4923a31568e5bb (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
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
#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_INFO_CMD "./get_pkg_attrs.sh"
#define PKG_INST_CMD "./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) {
			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", 3);
		info->script_path[script_path_len] = '\0';
		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 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));

    if (pid == 0) {
		// child proc
		// write 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?
		error_out("execve failed");
    } else {
		// parent proc, close write end of pipe
		close(pipefds[1]);
	}

	// 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 into attr buffer
    ssize_t bytes_read = read(pipefds[0], info->attrs.buffer, sizeof(info->attrs.buffer));
    if (bytes_read < 0) error_out("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;
        }
        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) error_out("failed to pipe: %s", strerror(errno));
    pid_t pid = fork();
    if (pid < 0) error_out("failed to fork: %s", strerror(errno));

    if (pid == 0) {
		// child proc
		// write 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?
		error_out("execve failed");
    } 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) error_out("failed to read from pipe: %s", strerror(errno));
	close(pipefds[0]);

	// reap the 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 install script");
}