fordon_greeman / pkger

Branch: b68a1f4
Switch branches/tags
main
theidioticdev feat: rewrite pkger, go back to Makefile, and more b68a1f4 3d ago
282 lines · 6.1 KB Raw Blame History
1 /* this project is licensed under GNU Public License Version 3 */
2
3 #include <stdio.h>
4 #include <unistd.h>
5 #include <sys/wait.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <sys/stat.h>
9 #include <sys/types.h>
10 #include <dirent.h>
11
12 /* recipe header
13 edit it to add new entries in the recipe format */
14 #include "recipe.h"
15
16 /* fakeroot fs */
17 char root_dir[512];
18 char bin_dir[512];
19 char recipe_dir[512];
20 char usr_dir[512];
21 char etc_dir[512];
22
23 /* make the fakeroot fs */
24 int
25 init_fakeroot (void)
26 {
27 char *home = getenv ("HOME");
28
29 if (home == NULL) return -1;
30
31 snprintf (root_dir, sizeof (root_dir), "%s/pkger_root", home);
32 snprintf (bin_dir, sizeof (bin_dir), "%s/usr/bin", root_dir);
33 snprintf (usr_dir, sizeof (usr_dir), "%s/usr", root_dir);
34 snprintf (etc_dir, sizeof (etc_dir), "%s/etc", root_dir);
35 snprintf (recipe_dir, sizeof (recipe_dir), "%s/etc/recipes", root_dir);
36
37 struct stat st;
38 if (stat (root_dir, &st) == 0 && S_ISDIR (st.st_mode))
39 return 0;
40
41 mkdir (root_dir, 0755);
42 mkdir (usr_dir, 0755);
43 mkdir (bin_dir, 0755);
44 mkdir (etc_dir, 0755);
45 mkdir (recipe_dir, 0755);
46
47 printf ("[INIT] created fakeroot at %s\n", root_dir);
48 return 0;
49 }
50
51 /* recipes parsing */
52
53 int
54 recipe_parse (const char *filepath, Recipe *r)
55 {
56 FILE *file = fopen (filepath, "r");
57 if (!file)
58 {
59 perror ("Failed to open file");
60 return -1;
61 }
62 memset (r, 0, sizeof(Recipe));
63 char line[1024];
64
65 while (fgets(line, sizeof(line), file))
66 {
67 char key[64], val[512];
68
69 if (sscanf (line, " %63[^ =] = \"%511[^\"]\"", key, val) == 2)
70 {
71 if (strcmp(key, "pkg_name") == 0) strcpy(r->pkg_name, val);
72 else if (strcmp(key, "pkg_ver") == 0) strcpy(r->pkg_ver, val);
73 else if (strcmp(key, "pkg_fetch") == 0) strcpy(r->pkg_fetch, val);
74 else if (strcmp(key, "pkg_build") == 0) strcpy(r->pkg_build, val);
75 else if (strcmp(key, "pkg_install") == 0) strcpy(r->pkg_install, val);
76 else if (strcmp(key, "pkg_uninstall") == 0) strcpy(r->pkg_uninstall, val);
77 }
78 }
79 fclose(file);
80 return 0;
81 }
82
83
84 /* recipe list */
85 void
86 list_recipes (void)
87 {
88 DIR *d = opendir (recipe_dir);
89 if (!d)
90 {
91 perror ("Failed to open recipes");
92 return;
93 }
94
95 Recipe r;
96 struct dirent *e;
97 while ((e = readdir (d)) != NULL)
98 {
99 if (e->d_name[0] == '.')
100 continue;
101 char filepath[1024];
102 snprintf (filepath, sizeof (filepath), "%s/%s", recipe_dir, e->d_name);
103
104 if (recipe_parse (filepath, &r) == 0)
105 {
106 char fp[1024];
107 snprintf (fp, sizeof (fp), "%s (v%s)", r.pkg_name, r.pkg_ver);
108 printf ("[PKG] %s\n", fp);
109 }
110 }
111
112 closedir (d);
113 }
114
115 /* helper 1 */
116 int
117 run_cmd (char *const argv[])
118 {
119 pid_t pid = fork();
120 if (pid == 0)
121 {
122 execvp(argv[0], argv);
123 perror("execvp failed");
124 _exit(1);
125 } else if (pid > 0)
126 {
127 int status;
128 waitpid(pid, &status, 0);
129 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) return 0;
130 }
131 return -1;
132 }
133
134 /* helper 2 */
135 int
136 exec_str (const char *cmd)
137 {
138 if (cmd == NULL || cmd[0] == '\0') return 0;
139 char *const argv[] = { "/bin/sh", "-c", (char *)cmd, NULL };
140 printf("[EXEC] %s\n", cmd);
141 return run_cmd (argv);
142 }
143
144 /* TODO: add simple dependency res */
145
146 /* dependencies, finally. */
147 int
148 get_deps (const char *pkg_name)
149 {
150 char filepath[1024];
151 snprintf (filepath, sizeof (filepath), "%s/%s.deps", recipe_dir, pkg_name);
152
153 FILE *file = fopen (filepath, "r");
154 if (!file)
155 {
156 return 0;
157 }
158
159 printf ("[DEPS] Loading dependencies for %s\n", pkg_name);
160 char line[1024];
161 while (fgets (line, sizeof (line), file))
162 {
163 line[strcspn (line, "\r\n")] = 0;
164
165 if (line[0] == '\0' || line[0] == '#')
166 continue;
167
168 if (line[0] == '!')
169 {
170 if (exec_str (line + 1) != 0)
171 {
172 fprintf (stderr, "Error: Dependency command failed\n");
173 fclose (file);
174 return -1;
175 }
176 }
177 }
178
179 fclose (file);
180 return 0;
181 }
182 /* finally installing pkgs */
183 int
184 pkg_get (const char *pkg_name)
185 {
186 char fp[1024];
187 snprintf (fp, sizeof (fp), "%s/%s.build", recipe_dir, pkg_name);
188
189 Recipe r;
190 if (recipe_parse (fp, &r) != 0)
191 {
192 printf ("recipe '%s' not found\n", pkg_name);
193 return -1;
194 }
195 printf ("[GET] %s (v%s)\n", r.pkg_name, r.pkg_ver );
196 char build_dir[1024];
197 char build_root[512];
198
199 snprintf (build_root, sizeof (build_root), "%s/tmp/build", root_dir);
200 snprintf (build_dir, sizeof (build_dir), "%s/%s", build_root, pkg_name);
201
202 if (mkdir (build_root, 0755) != 0)
203 {
204 perror("Failed to make directory");
205 return -1;
206 }
207
208 if (mkdir (build_dir, 0755) != 0)
209 {
210 perror("Failed to make directory");
211 return -1;
212 }
213
214 if (chdir (build_dir) != 0)
215 {
216 perror("Failed to change directory");
217 return -1;
218 }
219
220 if (exec_str (r.pkg_fetch) != 0) return -1;
221 if (exec_str (r.pkg_build) != 0) return -1;
222 if (exec_str (r.pkg_install) != 0) return -1;
223
224 return 0;
225 }
226
227 /* rming pkgs */
228 int
229 pkg_rm (const char *pkg_name)
230 {
231 char filepath[1024];
232 snprintf (filepath, sizeof (filepath), "%s/%s.build", recipe_dir, pkg_name);
233
234 Recipe r;
235 if (recipe_parse (filepath, &r) != 0)
236 {
237 fprintf (stderr, "Error: Recipe for '%s' not found at %s\n", pkg_name, filepath);
238 return -1;
239 }
240
241 printf ("[RM] Removing package: %s\n", r.pkg_name);
242 exec_str (r.pkg_uninstall);
243
244 return 0;
245 }
246
247 /* do i need to document this? */
248 int
249 main (int argc, char **argv)
250 {
251 if (init_fakeroot () != 0)
252 return EXIT_FAILURE;
253
254 if (argc < 2)
255 {
256 fprintf (stderr, "Usage: %s [list|get|rm|help] <pkg>\n", argv[0]);
257 return EXIT_FAILURE;
258 }
259 if (strcmp (argv[1], "help") == 0)
260 {
261 printf ("Usage: %s [list|get|rm|help] <pkg>\n", argv[0]);
262 }
263 else if (strcmp (argv[1], "list") == 0)
264 {
265 list_recipes ();
266 }
267 else if (strcmp (argv[1], "get") == 0 && argc > 2)
268 {
269 pkg_get (argv[2]);
270 }
271 else if (strcmp (argv[1], "rm") == 0 && argc > 2)
272 {
273 pkg_rm (argv[2]);
274 }
275 else
276 {
277 fprintf (stderr, "Unknown command or missing package name.\n");
278 return EXIT_FAILURE;
279 }
280
281 return EXIT_SUCCESS;
282 }