Home | History | Annotate | Download | only in libpackagelistparser
      1 /*
      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 (at) intel.com>
     18  *
     19  */
     20 
     21 #include <errno.h>
     22 #include <stdbool.h>
     23 #include <stdio.h>
     24 #include <stdlib.h>
     25 #include <string.h>
     26 
     27 #include <sys/limits.h>
     28 
     29 #define LOG_TAG "packagelistparser"
     30 #include <utils/Log.h>
     31 
     32 #include <packagelistparser/packagelistparser.h>
     33 
     34 #define CLOGE(fmt, ...) \
     35     do {\
     36         IF_ALOGE() {\
     37             ALOGE(fmt, ##__VA_ARGS__);\
     38         }\
     39     } while(0)
     40 
     41 static size_t get_gid_cnt(const char *gids)
     42 {
     43     size_t cnt;
     44 
     45     if (*gids == '\0') {
     46         return 0;
     47     }
     48 
     49     if (!strcmp(gids, "none")) {
     50         return 0;
     51     }
     52 
     53     for (cnt = 1; gids[cnt]; gids[cnt] == ',' ? cnt++ : *gids++)
     54         ;
     55 
     56     return cnt;
     57 }
     58 
     59 static bool parse_gids(char *gids, gid_t *gid_list, size_t *cnt)
     60 {
     61     gid_t gid;
     62     char* token;
     63     char *endptr;
     64     size_t cmp = 0;
     65 
     66     while ((token = strsep(&gids, ",\r\n"))) {
     67 
     68         if (cmp > *cnt) {
     69             return false;
     70         }
     71 
     72         gid = strtoul(token, &endptr, 10);
     73         if (*endptr != '\0') {
     74             return false;
     75         }
     76 
     77         /*
     78          * if unsigned long is greater than size of gid_t,
     79          * prevent a truncation based roll-over
     80          */
     81         if (gid > GID_MAX) {
     82             CLOGE("A gid in field \"gid list\" greater than GID_MAX");
     83             return false;
     84         }
     85 
     86         gid_list[cmp++] = gid;
     87     }
     88     return true;
     89 }
     90 
     91 extern bool packagelist_parse(pfn_on_package callback, void *userdata)
     92 {
     93 
     94     FILE *fp;
     95     char *cur;
     96     char *next;
     97     char *endptr;
     98     unsigned long tmp;
     99     ssize_t bytesread;
    100 
    101     bool rc = false;
    102     char *buf = NULL;
    103     size_t buflen = 0;
    104     unsigned long lineno = 1;
    105     const char *errmsg = NULL;
    106     struct pkg_info *pkg_info = NULL;
    107 
    108     fp = fopen(PACKAGES_LIST_FILE, "re");
    109     if (!fp) {
    110         CLOGE("Could not open: \"%s\", error: \"%s\"\n", PACKAGES_LIST_FILE,
    111                 strerror(errno));
    112         return false;
    113     }
    114 
    115     while ((bytesread = getline(&buf, &buflen, fp)) > 0) {
    116 
    117         pkg_info = calloc(1, sizeof(*pkg_info));
    118         if (!pkg_info) {
    119             goto err;
    120         }
    121 
    122         next = buf;
    123 
    124         cur = strsep(&next, " \t\r\n");
    125         if (!cur) {
    126             errmsg = "Could not get next token for \"package name\"";
    127             goto err;
    128         }
    129 
    130         pkg_info->name = strdup(cur);
    131         if (!pkg_info->name) {
    132             goto err;
    133         }
    134 
    135         cur = strsep(&next, " \t\r\n");
    136         if (!cur) {
    137             errmsg = "Could not get next token for field \"uid\"";
    138             goto err;
    139         }
    140 
    141         tmp = strtoul(cur, &endptr, 10);
    142         if (*endptr != '\0') {
    143             errmsg = "Could not convert field \"uid\" to integer value";
    144             goto err;
    145         }
    146 
    147         /*
    148          * if unsigned long is greater than size of uid_t,
    149          * prevent a truncation based roll-over
    150          */
    151         if (tmp > UID_MAX) {
    152             errmsg = "Field \"uid\" greater than UID_MAX";
    153             goto err;
    154         }
    155 
    156         pkg_info->uid = (uid_t) tmp;
    157 
    158         cur = strsep(&next, " \t\r\n");
    159         if (!cur) {
    160             errmsg = "Could not get next token for field \"debuggable\"";
    161             goto err;
    162         }
    163 
    164         tmp = strtoul(cur, &endptr, 10);
    165         if (*endptr != '\0') {
    166             errmsg = "Could not convert field \"debuggable\" to integer value";
    167             goto err;
    168         }
    169 
    170         /* should be a valid boolean of 1 or 0 */
    171         if (!(tmp == 0 || tmp == 1)) {
    172             errmsg = "Field \"debuggable\" is not 0 or 1 boolean value";
    173             goto err;
    174         }
    175 
    176         pkg_info->debuggable = (bool) tmp;
    177 
    178         cur = strsep(&next, " \t\r\n");
    179         if (!cur) {
    180             errmsg = "Could not get next token for field \"data dir\"";
    181             goto err;
    182         }
    183 
    184         pkg_info->data_dir = strdup(cur);
    185         if (!pkg_info->data_dir) {
    186             goto err;
    187         }
    188 
    189         cur = strsep(&next, " \t\r\n");
    190         if (!cur) {
    191             errmsg = "Could not get next token for field \"seinfo\"";
    192             goto err;
    193         }
    194 
    195         pkg_info->seinfo = strdup(cur);
    196         if (!pkg_info->seinfo) {
    197             goto err;
    198         }
    199 
    200         cur = strsep(&next, " \t\r\n");
    201         if (!cur) {
    202             errmsg = "Could not get next token for field \"gid(s)\"";
    203             goto err;
    204         }
    205 
    206         /*
    207          * Parse the gid list, could be in the form of none, single gid or list:
    208          * none
    209          * gid
    210          * gid, gid ...
    211          */
    212         pkg_info->gids.cnt = get_gid_cnt(cur);
    213         if (pkg_info->gids.cnt > 0) {
    214 
    215             pkg_info->gids.gids = calloc(pkg_info->gids.cnt, sizeof(gid_t));
    216             if (!pkg_info->gids.gids) {
    217                 goto err;
    218             }
    219 
    220             rc = parse_gids(cur, pkg_info->gids.gids, &pkg_info->gids.cnt);
    221             if (!rc) {
    222                 errmsg = "Could not parse field \"gid list\"";
    223                 goto err;
    224             }
    225         }
    226 
    227         rc = callback(pkg_info, userdata);
    228         if (rc == false) {
    229             /*
    230              * We do not log this as this can be intentional from
    231              * callback to abort processing. We go to out to not
    232              * free the pkg_info
    233              */
    234             rc = true;
    235             goto out;
    236         }
    237         lineno++;
    238     }
    239 
    240     rc = true;
    241 
    242 out:
    243     free(buf);
    244     fclose(fp);
    245     return rc;
    246 
    247 err:
    248     if (errmsg) {
    249         CLOGE("Error Parsing \"%s\" on line: %lu for reason: %s",
    250                 PACKAGES_LIST_FILE, lineno, errmsg);
    251     }
    252     rc = false;
    253     packagelist_free(pkg_info);
    254     goto out;
    255 }
    256 
    257 void packagelist_free(pkg_info *info)
    258 {
    259     if (info) {
    260         free(info->name);
    261         free(info->data_dir);
    262         free(info->seinfo);
    263         free(info->gids.gids);
    264         free(info);
    265     }
    266 }
    267