opkg: add libopkg test application
[project/opkg-lede.git] / libopkg / opkg.c
1 /* opkg.c - the opkg package management system
2
3 Thomas Wood <thomas@openedhand.com>
4
5 Copyright (C) 2008 OpenMoko Inc
6
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2, or (at
10 your option) any later version.
11
12 This program is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16 */
17
18 #include <config.h>
19 #include <fnmatch.h>
20
21 #include "opkg.h"
22 #include "opkg_conf.h"
23 #include "args.h"
24
25 #include "opkg_install.h"
26 #include "opkg_configure.h"
27 #include "opkg_download.h"
28
29 #include "sprintf_alloc.h"
30 #include "file_util.h"
31
32 #include "libbb.h"
33
34 struct _opkg_t
35 {
36 args_t *args;
37 opkg_conf_t *conf;
38 opkg_option_t *options[];
39 };
40
41 /** Private Functions ***/
42
43
44 static int
45 opkg_configure_packages(opkg_conf_t *conf, char *pkg_name)
46 {
47 pkg_vec_t *all;
48 int i;
49 pkg_t *pkg;
50 int r, err = 0;
51
52 all = pkg_vec_alloc ();
53 pkg_hash_fetch_available (&conf->pkg_hash, all);
54
55 for (i = 0; i < all->len; i++)
56 {
57 pkg = all->pkgs[i];
58
59 if (pkg_name && fnmatch (pkg_name, pkg->name, 0))
60 continue;
61
62 if (pkg->state_status == SS_UNPACKED)
63 {
64 r = opkg_configure (conf, pkg);
65 if (r == 0)
66 {
67 pkg->state_status = SS_INSTALLED;
68 pkg->parent->state_status = SS_INSTALLED;
69 pkg->state_flag &= ~SF_PREFER;
70 }
71 else
72 {
73 if (!err)
74 err = r;
75 }
76 }
77 }
78
79 pkg_vec_free (all);
80 return err;
81 }
82
83
84
85 /*** Public API ***/
86
87 opkg_t *
88 opkg_new ()
89 {
90 opkg_t *opkg;
91 opkg = malloc (sizeof (opkg_t));
92 args_init (opkg->args);
93 opkg_conf_init (opkg->conf, opkg->args);
94 opkg_init_options_array (opkg->conf, opkg->options);
95 return opkg;
96 }
97
98 void
99 opkg_free (opkg_t *opkg)
100 {
101 opkg_conf_deinit (opkg->conf);
102 args_deinit (opkg->args);
103 }
104
105 void
106 opkg_get_option (opkg_t *opkg, char *option, void **value)
107 {
108 int i = 0;
109 opkg_option_t **options = opkg->options;
110
111 /* can't store a value in a NULL pointer! */
112 if (!value)
113 return;
114
115 /* look up the option
116 * TODO: this would be much better as a hash table
117 */
118 while (options[i]->name)
119 {
120 if (strcmp (options[i]->name, option) != 0)
121 {
122 i++;
123 continue;
124 }
125 }
126
127 /* get the option */
128 switch (options[i]->type)
129 {
130 case OPKG_OPT_TYPE_BOOL:
131 *((int *) value) = *((int *) options[i]->value);
132 return;
133
134 case OPKG_OPT_TYPE_INT:
135 *((int *) value) = *((int *) options[i]->value);
136 return;
137
138 case OPKG_OPT_TYPE_STRING:
139 *((char **)value) = strdup (options[i]->value);
140 return;
141 }
142
143 }
144
145 void
146 opkg_set_option (opkg_t *opkg, char *option, void *value)
147 {
148 int i = 0;
149 opkg_option_t **options = opkg->options;
150
151 /* NULL values are not defined */
152 if (!value)
153 return;
154
155 /* look up the option
156 * TODO: this would be much better as a hash table
157 */
158 while (options[i]->name)
159 {
160 if (strcmp (options[i]->name, option) != 0)
161 {
162 i++;
163 continue;
164 }
165 }
166
167 /* set the option */
168 switch (options[i]->type)
169 {
170 case OPKG_OPT_TYPE_BOOL:
171 if (*((int *) value) == 0)
172 *((int *)options[i]->value) = 0;
173 else
174 *((int *)options[i]->value) = 1;
175 return;
176
177 case OPKG_OPT_TYPE_INT:
178 *((int *) options[i]->value) = *((int *) value);
179 return;
180
181 case OPKG_OPT_TYPE_STRING:
182 *((char **)options[i]->value) = strdup (value);
183 return;
184 }
185
186 }
187
188 int
189 opkg_install_package (opkg_t *opkg, char *package_name)
190 {
191 int err;
192
193 pkg_info_preinstall_check (opkg->conf);
194
195 if (opkg->conf->multiple_providers)
196 {
197 err = opkg_install_multi_by_name (opkg->conf, package_name);
198 }
199 else
200 {
201 err = opkg_install_by_name (opkg->conf, package_name);
202 }
203
204 err = opkg_configure_packages (opkg->conf, NULL);
205
206 if (opkg->conf->noaction)
207 return err;
208
209 opkg_conf_write_status_files (opkg->conf);
210 pkg_write_changed_filelists (opkg->conf);
211
212 return err;
213 }
214
215 int
216 opkg_remove_package (opkg_t *opkg, char *package_name)
217 {
218 return 1;
219 }
220
221 int
222 opkg_upgrade_package (opkg_t *opkg, char *package_name)
223 {
224 return 1;
225 }
226
227 int
228 opkg_upgrade_all (opkg_t *opkg)
229 {
230 return 1;
231 }
232
233 int
234 opkg_update_package_lists (opkg_t *opkg)
235 {
236 char *tmp;
237 int err;
238 char *lists_dir;
239 pkg_src_list_elt_t *iter;
240 pkg_src_t *src;
241
242
243 sprintf_alloc (&lists_dir, "%s",
244 (opkg->conf->restrict_to_default_dest)
245 ? opkg->conf->default_dest->lists_dir
246 : opkg->conf->lists_dir);
247
248 if (!file_is_dir (lists_dir))
249 {
250 if (file_exists (lists_dir))
251 {
252 /* XXX: Error: file exists but is not a directory */
253 free (lists_dir);
254 return 1;
255 }
256
257 err = file_mkdir_hier (lists_dir, 0755);
258 if (err)
259 {
260 /* XXX: Error: failed to create directory */
261 free (lists_dir);
262 return 1;
263 }
264 }
265
266 tmp = strdup ("/tmp/opkg.XXXXXX");
267
268 if (mkdtemp (tmp) == NULL)
269 {
270 /* XXX: Error: could not create temporary file name */
271 free (lists_dir);
272 free (tmp);
273 return 1;
274 }
275
276
277 for (iter = opkg->conf->pkg_src_list.head; iter; iter = iter->next)
278 {
279 char *url, *list_file_name;
280
281 src = iter->data;
282
283 if (src->extra_data) /* debian style? */
284 sprintf_alloc (&url, "%s/%s/%s", src->value, src->extra_data,
285 src->gzip ? "Packages.gz" : "Packages");
286 else
287 sprintf_alloc (&url, "%s/%s", src->value, src->gzip ? "Packages.gz" : "Packages");
288
289 sprintf_alloc (&list_file_name, "%s/%s", lists_dir, src->name);
290 if (src->gzip)
291 {
292 char *tmp_file_name;
293 FILE *in, *out;
294
295 sprintf_alloc (&tmp_file_name, "%s/%s.gz", tmp, src->name);
296
297 /* XXX: Note: downloading url */
298 err = opkg_download (opkg->conf, url, tmp_file_name);
299
300 if (err == 0)
301 {
302 /* XXX: Note: Inflating downloaded file */
303 in = fopen (tmp_file_name, "r");
304 out = fopen (list_file_name, "w");
305 if (in && out)
306 unzip (in, out);
307 else
308 err = 1;
309 if (in)
310 fclose (in);
311 if (out)
312 fclose (out);
313 unlink (tmp_file_name);
314 }
315 }
316 else
317 err = opkg_download (opkg->conf, url, list_file_name);
318
319 if (err)
320 {
321 /* XXX: Error: download error */
322 }
323 free (url);
324
325 #ifdef HAVE_GPGME
326 /* download detached signitures to verify the package lists */
327 /* get the url for the sig file */
328 if (src->extra_data) /* debian style? */
329 sprintf_alloc (&url, "%s/%s/%s", src->value, src->extra_data,
330 "Packages.sig");
331 else
332 sprintf_alloc (&url, "%s/%s", src->value, "Packages.sig");
333
334 /* create temporary file for it */
335 char *tmp_file_name;
336
337 sprintf_alloc (&tmp_file_name, "%s/%s", tmp, "Packages.sig");
338
339 err = opkg_download (opkg->conf, url, tmp_file_name);
340 if (err)
341 {
342 /* XXX: Warning: Download failed */
343 }
344 else
345 {
346 int err;
347 err = opkg_verify_file (opkg->conf, list_file_name, tmp_file_name);
348 if (err == 0)
349 {
350 /* XXX: Notice: Signature check passed */
351 }
352 else
353 {
354 /* XXX: Warning: Signature check failed */
355 }
356 }
357 unlink (tmp_file_name);
358 free (tmp_file_name);
359 free (url);
360 #else
361 /* XXX: Note: Signiture check for %s skipped because GPG support was not
362 * enabled in this build
363 */
364 #endif
365 free (list_file_name);
366 }
367 rmdir (tmp);
368 free (tmp);
369 free (lists_dir);
370
371 return 0;
372 }