fordon_greeman / pkger

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