blob: 3e1a3d193e7df0841535743204e578f1e990d311 [file] [log] [blame]
Andreas Gampe438eb752015-10-22 19:51:51 -07001/*
2 * Copyright 2015, Intel Corporation
3 * Copyright (C) 2015 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 * Written by William Roberts <william.c.roberts@intel.com>
18 *
19 */
20
Mark Salyzyn66ce3e02016-09-28 10:07:20 -070021#define LOG_TAG "packagelistparser"
22
Andreas Gampe438eb752015-10-22 19:51:51 -070023#include <errno.h>
24#include <stdbool.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
Andreas Gampe438eb752015-10-22 19:51:51 -070028#include <sys/limits.h>
29
Mark Salyzyn30f991f2017-01-10 13:19:54 -080030#include <log/log.h>
Colin Cross7f68acb2015-11-04 17:05:24 -080031#include <packagelistparser/packagelistparser.h>
Andreas Gampe438eb752015-10-22 19:51:51 -070032
33#define CLOGE(fmt, ...) \
34 do {\
35 IF_ALOGE() {\
36 ALOGE(fmt, ##__VA_ARGS__);\
37 }\
38 } while(0)
39
40static size_t get_gid_cnt(const char *gids)
41{
42 size_t cnt;
43
44 if (*gids == '\0') {
45 return 0;
46 }
47
48 if (!strcmp(gids, "none")) {
49 return 0;
50 }
51
52 for (cnt = 1; gids[cnt]; gids[cnt] == ',' ? cnt++ : *gids++)
53 ;
54
55 return cnt;
56}
57
58static bool parse_gids(char *gids, gid_t *gid_list, size_t *cnt)
59{
60 gid_t gid;
61 char* token;
62 char *endptr;
63 size_t cmp = 0;
64
65 while ((token = strsep(&gids, ",\r\n"))) {
66
67 if (cmp > *cnt) {
68 return false;
69 }
70
71 gid = strtoul(token, &endptr, 10);
72 if (*endptr != '\0') {
73 return false;
74 }
75
76 /*
77 * if unsigned long is greater than size of gid_t,
78 * prevent a truncation based roll-over
79 */
80 if (gid > GID_MAX) {
81 CLOGE("A gid in field \"gid list\" greater than GID_MAX");
82 return false;
83 }
84
85 gid_list[cmp++] = gid;
86 }
87 return true;
88}
89
90extern bool packagelist_parse(pfn_on_package callback, void *userdata)
91{
92
93 FILE *fp;
94 char *cur;
95 char *next;
96 char *endptr;
97 unsigned long tmp;
98 ssize_t bytesread;
99
100 bool rc = false;
101 char *buf = NULL;
102 size_t buflen = 0;
103 unsigned long lineno = 1;
104 const char *errmsg = NULL;
105 struct pkg_info *pkg_info = NULL;
106
107 fp = fopen(PACKAGES_LIST_FILE, "re");
108 if (!fp) {
109 CLOGE("Could not open: \"%s\", error: \"%s\"\n", PACKAGES_LIST_FILE,
110 strerror(errno));
111 return false;
112 }
113
114 while ((bytesread = getline(&buf, &buflen, fp)) > 0) {
115
116 pkg_info = calloc(1, sizeof(*pkg_info));
117 if (!pkg_info) {
118 goto err;
119 }
120
121 next = buf;
122
123 cur = strsep(&next, " \t\r\n");
124 if (!cur) {
125 errmsg = "Could not get next token for \"package name\"";
126 goto err;
127 }
128
129 pkg_info->name = strdup(cur);
130 if (!pkg_info->name) {
131 goto err;
132 }
133
134 cur = strsep(&next, " \t\r\n");
135 if (!cur) {
136 errmsg = "Could not get next token for field \"uid\"";
137 goto err;
138 }
139
140 tmp = strtoul(cur, &endptr, 10);
141 if (*endptr != '\0') {
142 errmsg = "Could not convert field \"uid\" to integer value";
143 goto err;
144 }
145
146 /*
147 * if unsigned long is greater than size of uid_t,
148 * prevent a truncation based roll-over
149 */
150 if (tmp > UID_MAX) {
151 errmsg = "Field \"uid\" greater than UID_MAX";
152 goto err;
153 }
154
155 pkg_info->uid = (uid_t) tmp;
156
157 cur = strsep(&next, " \t\r\n");
158 if (!cur) {
159 errmsg = "Could not get next token for field \"debuggable\"";
160 goto err;
161 }
162
163 tmp = strtoul(cur, &endptr, 10);
164 if (*endptr != '\0') {
165 errmsg = "Could not convert field \"debuggable\" to integer value";
166 goto err;
167 }
168
169 /* should be a valid boolean of 1 or 0 */
170 if (!(tmp == 0 || tmp == 1)) {
171 errmsg = "Field \"debuggable\" is not 0 or 1 boolean value";
172 goto err;
173 }
174
175 pkg_info->debuggable = (bool) tmp;
176
177 cur = strsep(&next, " \t\r\n");
178 if (!cur) {
179 errmsg = "Could not get next token for field \"data dir\"";
180 goto err;
181 }
182
183 pkg_info->data_dir = strdup(cur);
184 if (!pkg_info->data_dir) {
185 goto err;
186 }
187
188 cur = strsep(&next, " \t\r\n");
189 if (!cur) {
190 errmsg = "Could not get next token for field \"seinfo\"";
191 goto err;
192 }
193
194 pkg_info->seinfo = strdup(cur);
195 if (!pkg_info->seinfo) {
196 goto err;
197 }
198
199 cur = strsep(&next, " \t\r\n");
200 if (!cur) {
201 errmsg = "Could not get next token for field \"gid(s)\"";
202 goto err;
203 }
204
205 /*
206 * Parse the gid list, could be in the form of none, single gid or list:
207 * none
208 * gid
209 * gid, gid ...
210 */
211 pkg_info->gids.cnt = get_gid_cnt(cur);
212 if (pkg_info->gids.cnt > 0) {
213
214 pkg_info->gids.gids = calloc(pkg_info->gids.cnt, sizeof(gid_t));
215 if (!pkg_info->gids.gids) {
216 goto err;
217 }
218
219 rc = parse_gids(cur, pkg_info->gids.gids, &pkg_info->gids.cnt);
220 if (!rc) {
221 errmsg = "Could not parse field \"gid list\"";
222 goto err;
223 }
224 }
225
226 rc = callback(pkg_info, userdata);
227 if (rc == false) {
228 /*
229 * We do not log this as this can be intentional from
230 * callback to abort processing. We go to out to not
231 * free the pkg_info
232 */
233 rc = true;
234 goto out;
235 }
236 lineno++;
237 }
238
239 rc = true;
240
241out:
242 free(buf);
243 fclose(fp);
244 return rc;
245
246err:
247 if (errmsg) {
248 CLOGE("Error Parsing \"%s\" on line: %lu for reason: %s",
249 PACKAGES_LIST_FILE, lineno, errmsg);
250 }
251 rc = false;
252 packagelist_free(pkg_info);
253 goto out;
254}
255
256void packagelist_free(pkg_info *info)
257{
258 if (info) {
259 free(info->name);
260 free(info->data_dir);
261 free(info->seinfo);
262 free(info->gids.gids);
263 free(info);
264 }
265}