diff options
| author | 2015-10-22 23:38:40 +0000 | |
|---|---|---|
| committer | 2015-10-22 23:38:40 +0000 | |
| commit | a2dbc1cea3c60510f27bfeb39012ae2c2796503c (patch) | |
| tree | 1203c58c7e50066ae11a62115ef6d4d47545244f | |
| parent | d3511518f927eead41fb33c56803104672dcffc2 (diff) | |
| parent | 188e8875db1a55a6bafc8e8ef741400baab6e6fb (diff) | |
Merge "libs: add libpackagelistparser" am: cc7373eafd
am: 188e8875db
* commit '188e8875db1a55a6bafc8e8ef741400baab6e6fb':
libs: add libpackagelistparser
| -rw-r--r-- | libs/packagelistparser/Android.mk | 32 | ||||
| -rw-r--r-- | libs/packagelistparser/packagelistparser.c | 266 | ||||
| -rw-r--r-- | libs/packagelistparser/packagelistparser.h | 92 | ||||
| -rw-r--r-- | services/core/java/com/android/server/pm/Settings.java | 4 |
4 files changed, 391 insertions, 3 deletions
diff --git a/libs/packagelistparser/Android.mk b/libs/packagelistparser/Android.mk new file mode 100644 index 000000000000..802a3cb253ba --- /dev/null +++ b/libs/packagelistparser/Android.mk @@ -0,0 +1,32 @@ +LOCAL_PATH:= $(call my-dir) + +######################### +include $(CLEAR_VARS) + +LOCAL_MODULE := libpackagelistparser +LOCAL_MODULE_TAGS := optional +LOCAL_SRC_FILES := packagelistparser.c +LOCAL_COPY_HEADERS_TO := packagelistparser +LOCAL_COPY_HEADERS := packagelistparser.h +LOCAL_SHARED_LIBRARIES := liblog + +LOCAL_CLANG := true +LOCAL_SANITIZE := integer + +include $(BUILD_SHARED_LIBRARY) + +######################### +include $(CLEAR_VARS) + + +LOCAL_MODULE := libpackagelistparser +LOCAL_MODULE_TAGS := optional +LOCAL_SRC_FILES := packagelistparser.c +LOCAL_COPY_HEADERS_TO := packagelistparser +LOCAL_COPY_HEADERS := packagelistparser.h +LOCAL_STATIC_LIBRARIES := liblog + +LOCAL_CLANG := true +LOCAL_SANITIZE := integer + +include $(BUILD_STATIC_LIBRARY) diff --git a/libs/packagelistparser/packagelistparser.c b/libs/packagelistparser/packagelistparser.c new file mode 100644 index 000000000000..3e2539c7673f --- /dev/null +++ b/libs/packagelistparser/packagelistparser.c @@ -0,0 +1,266 @@ +/* + * 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> + * + */ + +#include <errno.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <sys/limits.h> + +#define LOG_TAG "packagelistparser" +#include <utils/Log.h> + +#include "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); + } +} diff --git a/libs/packagelistparser/packagelistparser.h b/libs/packagelistparser/packagelistparser.h new file mode 100644 index 000000000000..d602c26dc53d --- /dev/null +++ b/libs/packagelistparser/packagelistparser.h @@ -0,0 +1,92 @@ +/* + * 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> + * + * This is a parser library for parsing the packages.list file generated + * by PackageManager service. + * + * This simple parser is sensitive to format changes in + * frameworks/base/services/core/java/com/android/server/pm/Settings.java + * A dependency note has been added to that file to correct + * this parser. + */ + +#ifndef PACKAGELISTPARSER_H_ +#define PACKAGELISTPARSER_H_ + +#include <stdbool.h> +#include <sys/cdefs.h> +#include <sys/types.h> + +__BEGIN_DECLS + +/** The file containing the list of installed packages on the system */ +#define PACKAGES_LIST_FILE "/data/system/packages.list" + +typedef struct pkg_info pkg_info; +typedef struct gid_list gid_list; + +struct gid_list { + size_t cnt; + gid_t *gids; +}; + +struct pkg_info { + char *name; + uid_t uid; + bool debuggable; + char *data_dir; + char *seinfo; + gid_list gids; + void *private_data; +}; + +/** + * Callback function to be used by packagelist_parse() routine. + * @param info + * The parsed package information + * @param userdata + * The supplied userdata pointer to packagelist_parse() + * @return + * true to keep processing, false to stop. + */ +typedef bool (*pfn_on_package)(pkg_info *info, void *userdata); + +/** + * Parses the file specified by PACKAGES_LIST_FILE and invokes the callback on + * each entry found. Once the callback is invoked, ownership of the pkg_info pointer + * is passed to the callback routine, thus they are required to perform any cleanup + * desired. + * @param callback + * The callback function called on each parsed line of the packages list. + * @param userdata + * An optional userdata supplied pointer to pass to the callback function. + * @return + * true on success false on failure. + */ +extern bool packagelist_parse(pfn_on_package callback, void *userdata); + +/** + * Frees a pkg_info structure. + * @param info + * The struct to free + */ +extern void packagelist_free(pkg_info *info); + +__END_DECLS + +#endif /* PACKAGELISTPARSER_H_ */ diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 647c17bb5c6d..4093e20199bd 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -2278,10 +2278,8 @@ final class Settings { // // DO NOT MODIFY THIS FORMAT UNLESS YOU CAN ALSO MODIFY ITS USERS // FROM NATIVE CODE. AT THE MOMENT, LOOK AT THE FOLLOWING SOURCES: - // system/core/logd/LogStatistics.cpp + // frameworks/base/libs/packagelistparser // system/core/run-as/run-as.c - // system/core/sdcard/sdcard.c - // external/libselinux/src/android.c:package_info_init() // sb.setLength(0); sb.append(ai.packageName); |