You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
265 lines
6.2 KiB
265 lines
6.2 KiB
/* |
|
* Copyright 2015, Intel Corporation |
|
* Copyright (C) 2015 The Android Open Source Project |
|
* |
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
* you may not use this file except in compliance with the License. |
|
* You may obtain a copy of the License at |
|
* |
|
* http://www.apache.org/licenses/LICENSE-2.0 |
|
* |
|
* Unless required by applicable law or agreed to in writing, software |
|
* distributed under the License is distributed on an "AS IS" BASIS, |
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
* See the License for the specific language governing permissions and |
|
* limitations under the License. |
|
* |
|
* Written by William Roberts <william.c.roberts@intel.com> |
|
* |
|
*/ |
|
|
|
#define LOG_TAG "packagelistparser" |
|
|
|
#include <errno.h> |
|
#include <stdbool.h> |
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <string.h> |
|
#include <sys/limits.h> |
|
|
|
#include <log/log.h> |
|
#include <packagelistparser/packagelistparser.h> |
|
|
|
#define CLOGE(fmt, ...) \ |
|
do {\ |
|
IF_ALOGE() {\ |
|
ALOGE(fmt, ##__VA_ARGS__);\ |
|
}\ |
|
} while(0) |
|
|
|
static size_t get_gid_cnt(const char *gids) |
|
{ |
|
size_t cnt; |
|
|
|
if (*gids == '\0') { |
|
return 0; |
|
} |
|
|
|
if (!strcmp(gids, "none")) { |
|
return 0; |
|
} |
|
|
|
for (cnt = 1; gids[cnt]; gids[cnt] == ',' ? cnt++ : *gids++) |
|
; |
|
|
|
return cnt; |
|
} |
|
|
|
static bool parse_gids(char *gids, gid_t *gid_list, size_t *cnt) |
|
{ |
|
gid_t gid; |
|
char* token; |
|
char *endptr; |
|
size_t cmp = 0; |
|
|
|
while ((token = strsep(&gids, ",\r\n"))) { |
|
|
|
if (cmp > *cnt) { |
|
return false; |
|
} |
|
|
|
gid = strtoul(token, &endptr, 10); |
|
if (*endptr != '\0') { |
|
return false; |
|
} |
|
|
|
/* |
|
* if unsigned long is greater than size of gid_t, |
|
* prevent a truncation based roll-over |
|
*/ |
|
if (gid > GID_MAX) { |
|
CLOGE("A gid in field \"gid list\" greater than GID_MAX"); |
|
return false; |
|
} |
|
|
|
gid_list[cmp++] = gid; |
|
} |
|
return true; |
|
} |
|
|
|
extern bool packagelist_parse(pfn_on_package callback, void *userdata) |
|
{ |
|
|
|
FILE *fp; |
|
char *cur; |
|
char *next; |
|
char *endptr; |
|
unsigned long tmp; |
|
ssize_t bytesread; |
|
|
|
bool rc = false; |
|
char *buf = NULL; |
|
size_t buflen = 0; |
|
unsigned long lineno = 1; |
|
const char *errmsg = NULL; |
|
struct pkg_info *pkg_info = NULL; |
|
|
|
fp = fopen(PACKAGES_LIST_FILE, "re"); |
|
if (!fp) { |
|
CLOGE("Could not open: \"%s\", error: \"%s\"\n", PACKAGES_LIST_FILE, |
|
strerror(errno)); |
|
return false; |
|
} |
|
|
|
while ((bytesread = getline(&buf, &buflen, fp)) > 0) { |
|
|
|
pkg_info = calloc(1, sizeof(*pkg_info)); |
|
if (!pkg_info) { |
|
goto err; |
|
} |
|
|
|
next = buf; |
|
|
|
cur = strsep(&next, " \t\r\n"); |
|
if (!cur) { |
|
errmsg = "Could not get next token for \"package name\""; |
|
goto err; |
|
} |
|
|
|
pkg_info->name = strdup(cur); |
|
if (!pkg_info->name) { |
|
goto err; |
|
} |
|
|
|
cur = strsep(&next, " \t\r\n"); |
|
if (!cur) { |
|
errmsg = "Could not get next token for field \"uid\""; |
|
goto err; |
|
} |
|
|
|
tmp = strtoul(cur, &endptr, 10); |
|
if (*endptr != '\0') { |
|
errmsg = "Could not convert field \"uid\" to integer value"; |
|
goto err; |
|
} |
|
|
|
/* |
|
* if unsigned long is greater than size of uid_t, |
|
* prevent a truncation based roll-over |
|
*/ |
|
if (tmp > UID_MAX) { |
|
errmsg = "Field \"uid\" greater than UID_MAX"; |
|
goto err; |
|
} |
|
|
|
pkg_info->uid = (uid_t) tmp; |
|
|
|
cur = strsep(&next, " \t\r\n"); |
|
if (!cur) { |
|
errmsg = "Could not get next token for field \"debuggable\""; |
|
goto err; |
|
} |
|
|
|
tmp = strtoul(cur, &endptr, 10); |
|
if (*endptr != '\0') { |
|
errmsg = "Could not convert field \"debuggable\" to integer value"; |
|
goto err; |
|
} |
|
|
|
/* should be a valid boolean of 1 or 0 */ |
|
if (!(tmp == 0 || tmp == 1)) { |
|
errmsg = "Field \"debuggable\" is not 0 or 1 boolean value"; |
|
goto err; |
|
} |
|
|
|
pkg_info->debuggable = (bool) tmp; |
|
|
|
cur = strsep(&next, " \t\r\n"); |
|
if (!cur) { |
|
errmsg = "Could not get next token for field \"data dir\""; |
|
goto err; |
|
} |
|
|
|
pkg_info->data_dir = strdup(cur); |
|
if (!pkg_info->data_dir) { |
|
goto err; |
|
} |
|
|
|
cur = strsep(&next, " \t\r\n"); |
|
if (!cur) { |
|
errmsg = "Could not get next token for field \"seinfo\""; |
|
goto err; |
|
} |
|
|
|
pkg_info->seinfo = strdup(cur); |
|
if (!pkg_info->seinfo) { |
|
goto err; |
|
} |
|
|
|
cur = strsep(&next, " \t\r\n"); |
|
if (!cur) { |
|
errmsg = "Could not get next token for field \"gid(s)\""; |
|
goto err; |
|
} |
|
|
|
/* |
|
* Parse the gid list, could be in the form of none, single gid or list: |
|
* none |
|
* gid |
|
* gid, gid ... |
|
*/ |
|
pkg_info->gids.cnt = get_gid_cnt(cur); |
|
if (pkg_info->gids.cnt > 0) { |
|
|
|
pkg_info->gids.gids = calloc(pkg_info->gids.cnt, sizeof(gid_t)); |
|
if (!pkg_info->gids.gids) { |
|
goto err; |
|
} |
|
|
|
rc = parse_gids(cur, pkg_info->gids.gids, &pkg_info->gids.cnt); |
|
if (!rc) { |
|
errmsg = "Could not parse field \"gid list\""; |
|
goto err; |
|
} |
|
} |
|
|
|
rc = callback(pkg_info, userdata); |
|
if (rc == false) { |
|
/* |
|
* We do not log this as this can be intentional from |
|
* callback to abort processing. We go to out to not |
|
* free the pkg_info |
|
*/ |
|
rc = true; |
|
goto out; |
|
} |
|
lineno++; |
|
} |
|
|
|
rc = true; |
|
|
|
out: |
|
free(buf); |
|
fclose(fp); |
|
return rc; |
|
|
|
err: |
|
if (errmsg) { |
|
CLOGE("Error Parsing \"%s\" on line: %lu for reason: %s", |
|
PACKAGES_LIST_FILE, lineno, errmsg); |
|
} |
|
rc = false; |
|
packagelist_free(pkg_info); |
|
goto out; |
|
} |
|
|
|
void packagelist_free(pkg_info *info) |
|
{ |
|
if (info) { |
|
free(info->name); |
|
free(info->data_dir); |
|
free(info->seinfo); |
|
free(info->gids.gids); |
|
free(info); |
|
} |
|
}
|
|
|