b54ad9aead061af2bc51c33a16dbe464f76c83fc
[project/opkg-lede.git] / libopkg / pkg_parse.c
1 /* pkg_parse.c - the opkg package management system
2
3 Copyright (C) 2009 Ubiq Technologies <graham.gower@gmail.com>
4
5 Steven M. Ayer
6 Copyright (C) 2002 Compaq Computer Corporation
7
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2, or (at
11 your option) any later version.
12
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17 */
18
19 #include "config.h"
20
21 #include <stdio.h>
22 #include <ctype.h>
23
24 #include "pkg.h"
25 #include "opkg_utils.h"
26 #include "pkg_parse.h"
27 #include "libbb/libbb.h"
28
29 #include "parse_util.h"
30
31 static void
32 parse_status(pkg_t *pkg, const char *sstr)
33 {
34 char sw_str[64], sf_str[64], ss_str[64];
35
36 if (sscanf(sstr, "Status: %63s %63s %63s",
37 sw_str, sf_str, ss_str) != 3) {
38 opkg_msg(ERROR, "Failed to parse Status line for %s\n",
39 pkg->name);
40 return;
41 }
42
43 pkg->state_want = pkg_state_want_from_str(sw_str);
44 pkg->state_flag = pkg_state_flag_from_str(sf_str);
45 pkg->state_status = pkg_state_status_from_str(ss_str);
46 }
47
48 static void
49 parse_conffiles(pkg_t *pkg, const char *cstr)
50 {
51 char file_name[1024], md5sum[35];
52
53 if (sscanf(cstr, "%1023s %34s", file_name, md5sum) != 2) {
54 opkg_msg(ERROR, "Failed to parse Conffiles line for %s\n",
55 pkg->name);
56 return;
57 }
58
59 conffile_list_append(&pkg->conffiles, file_name, md5sum);
60 }
61
62 int
63 parse_version(pkg_t *pkg, const char *vstr)
64 {
65 char *colon;
66
67 if (strncmp(vstr, "Version:", 8) == 0)
68 vstr += 8;
69
70 while (*vstr && isspace(*vstr))
71 vstr++;
72
73 colon = strchr(vstr, ':');
74 if (colon) {
75 errno = 0;
76 pkg->epoch = strtoul(vstr, NULL, 10);
77 if (errno) {
78 opkg_perror(ERROR, "%s: invalid epoch", pkg->name);
79 }
80 vstr = ++colon;
81 } else {
82 pkg->epoch= 0;
83 }
84
85 pkg->version = xstrdup(vstr);
86 pkg->revision = strrchr(pkg->version,'-');
87
88 if (pkg->revision)
89 *pkg->revision++ = '\0';
90
91 return 0;
92 }
93
94 static int
95 get_arch_priority(const char *arch)
96 {
97 nv_pair_list_elt_t *l;
98
99 list_for_each_entry(l , &conf->arch_list.head, node) {
100 nv_pair_t *nv = (nv_pair_t *)l->data;
101 if (strcmp(nv->name, arch) == 0)
102 return strtol(nv->value, NULL, 0);
103 }
104 return 0;
105 }
106
107 int
108 pkg_parse_line(void *ptr, const char *line, uint mask)
109 {
110 pkg_t *pkg = (pkg_t *) ptr;
111
112 /* these flags are a bit hackish... */
113 static int reading_conffiles = 0, reading_description = 0;
114 int ret = 0;
115
116 /* Exclude globally masked fields. */
117 mask |= conf->pfm;
118
119 /* Flip the semantics of the mask. */
120 mask ^= PFM_ALL;
121
122 switch (*line) {
123 case 'A':
124 if ((mask & PFM_ARCHITECTURE ) && is_field("Architecture", line)) {
125 pkg->architecture = parse_simple("Architecture", line);
126 pkg->arch_priority = get_arch_priority(pkg->architecture);
127 } else if ((mask & PFM_AUTO_INSTALLED) && is_field("Auto-Installed", line)) {
128 char *tmp = parse_simple("Auto-Installed", line);
129 if (strcmp(tmp, "yes") == 0)
130 pkg->auto_installed = 1;
131 free(tmp);
132 }
133 break;
134
135 case 'C':
136 if ((mask & PFM_CONFFILES) && is_field("Conffiles", line)) {
137 reading_conffiles = 1;
138 reading_description = 0;
139 goto dont_reset_flags;
140 }
141 else if ((mask & PFM_CONFLICTS) && is_field("Conflicts", line))
142 pkg->conflicts_str = parse_list(line, &pkg->conflicts_count, ',', 0);
143 break;
144
145 case 'D':
146 if ((mask & PFM_DESCRIPTION) && is_field("Description", line)) {
147 pkg->description = parse_simple("Description", line);
148 reading_conffiles = 0;
149 reading_description = 1;
150 goto dont_reset_flags;
151 } else if ((mask & PFM_DEPENDS) && is_field("Depends", line))
152 pkg->depends_str = parse_list(line, &pkg->depends_count, ',', 0);
153 break;
154
155 case 'E':
156 if((mask & PFM_ESSENTIAL) && is_field("Essential", line)) {
157 char *tmp = parse_simple("Essential", line);
158 if (strcmp(tmp, "yes") == 0)
159 pkg->essential = 1;
160 free(tmp);
161 }
162 break;
163
164 case 'F':
165 if((mask & PFM_FILENAME) && is_field("Filename", line))
166 pkg->filename = parse_simple("Filename", line);
167 break;
168
169 case 'I':
170 if ((mask & PFM_INSTALLED_SIZE) && is_field("Installed-Size", line)) {
171 char *tmp = parse_simple("Installed-Size", line);
172 pkg->installed_size = strtoul(tmp, NULL, 0);
173 free (tmp);
174 } else if ((mask & PFM_INSTALLED_TIME) && is_field("Installed-Time", line)) {
175 char *tmp = parse_simple("Installed-Time", line);
176 pkg->installed_time = strtoul(tmp, NULL, 0);
177 free (tmp);
178 }
179 break;
180
181 case 'M':
182 if ((mask & PFM_MD5SUM) && is_field("MD5sum:", line))
183 pkg->md5sum = parse_simple("MD5sum", line);
184 /* The old opkg wrote out status files with the wrong
185 * case for MD5sum, let's parse it either way */
186 else if ((mask & PFM_MD5SUM) && is_field("MD5Sum:", line))
187 pkg->md5sum = parse_simple("MD5Sum", line);
188 else if((mask & PFM_MAINTAINER) && is_field("Maintainer", line))
189 pkg->maintainer = parse_simple("Maintainer", line);
190 break;
191
192 case 'P':
193 if ((mask & PFM_PACKAGE) && is_field("Package", line))
194 pkg->name = parse_simple("Package", line);
195 else if ((mask & PFM_PRIORITY) && is_field("Priority", line))
196 pkg->priority = parse_simple("Priority", line);
197 else if ((mask & PFM_PROVIDES) && is_field("Provides", line))
198 pkg->provides_str = parse_list(line, &pkg->provides_count, ',', 0);
199 else if ((mask & PFM_PRE_DEPENDS) && is_field("Pre-Depends", line))
200 pkg->pre_depends_str = parse_list(line, &pkg->pre_depends_count, ',', 0);
201 break;
202
203 case 'R':
204 if ((mask & PFM_RECOMMENDS) && is_field("Recommends", line))
205 pkg->recommends_str = parse_list(line, &pkg->recommends_count, ',', 0);
206 else if ((mask & PFM_REPLACES) && is_field("Replaces", line))
207 pkg->replaces_str = parse_list(line, &pkg->replaces_count, ',', 0);
208
209 break;
210
211 case 'S':
212 if ((mask & PFM_SECTION) && is_field("Section", line))
213 pkg->section = parse_simple("Section", line);
214 #ifdef HAVE_SHA256
215 else if ((mask & PFM_SHA256SUM) && is_field("SHA256sum", line))
216 pkg->sha256sum = parse_simple("SHA256sum", line);
217 #endif
218 else if ((mask & PFM_SIZE) && is_field("Size", line)) {
219 char *tmp = parse_simple("Size", line);
220 pkg->size = strtoul(tmp, NULL, 0);
221 free (tmp);
222 } else if ((mask & PFM_SOURCE) && is_field("Source", line))
223 pkg->source = parse_simple("Source", line);
224 else if ((mask & PFM_STATUS) && is_field("Status", line))
225 parse_status(pkg, line);
226 else if ((mask & PFM_SUGGESTS) && is_field("Suggests", line))
227 pkg->suggests_str = parse_list(line, &pkg->suggests_count, ',', 0);
228 break;
229
230 case 'T':
231 if ((mask & PFM_TAGS) && is_field("Tags", line))
232 pkg->tags = parse_simple("Tags", line);
233 break;
234
235 case 'V':
236 if ((mask & PFM_VERSION) && is_field("Version", line))
237 parse_version(pkg, line);
238 break;
239
240 case ' ':
241 if ((mask & PFM_DESCRIPTION) && reading_description) {
242 pkg->description = xrealloc(pkg->description,
243 strlen(pkg->description)
244 + 1 + strlen(line) + 1);
245 strcat(pkg->description, "\n");
246 strcat(pkg->description, (line));
247 goto dont_reset_flags;
248 } else if ((mask & PFM_CONFFILES) && reading_conffiles) {
249 parse_conffiles(pkg, line);
250 goto dont_reset_flags;
251 }
252
253 /* FALLTHROUGH */
254 default:
255 /* For package lists, signifies end of package. */
256 if(line_is_blank(line)) {
257 ret = 1;
258 break;
259 }
260 }
261
262 reading_description = 0;
263 reading_conffiles = 0;
264
265 dont_reset_flags:
266
267 return ret;
268 }
269
270 int
271 pkg_parse_from_stream(pkg_t *pkg, FILE *fp, uint mask)
272 {
273 int ret;
274 char *buf;
275 const size_t len = 4096;
276
277 buf = xmalloc(len);
278 ret = parse_from_stream_nomalloc(pkg_parse_line, pkg, fp, mask, &buf, len);
279 free(buf);
280
281 if (pkg->name == NULL) {
282 /* probably just a blank line */
283 ret = 1;
284 }
285
286 return ret;
287 }