[go: nahoru, domu]

1b62286e60c079936a5f1e5b0befd32d2d9bf1b3fMark Salyzyn#include <dirent.h>
24600dd053dbdbd4b95f3b11057a1cc55b99f9c77Narayan Kamath#include <inttypes.h>
3b62286e60c079936a5f1e5b0befd32d2d9bf1b3fMark Salyzyn#include <sys/stat.h>
4b62286e60c079936a5f1e5b0befd32d2d9bf1b3fMark Salyzyn
513221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross#include "idmap.h"
613221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross
70881a7445f9106e835486c5a697c01f4f18e619bDan Albert#include <memory>
813221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross#include <androidfw/ResourceTypes.h>
913221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross#include <androidfw/StreamingZipInflater.h>
1013221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross#include <androidfw/ZipFileRO.h>
1113221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross#include <private/android_filesystem_config.h> // for AID_SYSTEM
1213221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross#include <utils/SortedVector.h>
1313221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross#include <utils/String16.h>
1413221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross#include <utils/String8.h>
1513221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross
1613221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross#define NO_OVERLAY_TAG (-1000)
1713221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross
1813221c9cffdb289851411bdc73a9a5236fcb9291Colin Crossusing namespace android;
1913221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross
2013221c9cffdb289851411bdc73a9a5236fcb9291Colin Crossnamespace {
2113221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross    struct Overlay {
2213221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        Overlay() {}
2313221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        Overlay(const String8& a, const String8& i, int p) :
2413221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross            apk_path(a), idmap_path(i), priority(p) {}
2513221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross
2613221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        bool operator<(Overlay const& rhs) const
2713221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        {
287197d91eb7dfbd0f5b065b56d4f391019e71d03aMårten Kongstad            return rhs.priority > priority;
2913221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        }
3013221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross
3113221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        String8 apk_path;
3213221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        String8 idmap_path;
3313221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        int priority;
3413221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross    };
3513221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross
3613221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross    bool writePackagesList(const char *filename, const SortedVector<Overlay>& overlayVector)
3713221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross    {
3813221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        FILE* fout = fopen(filename, "w");
3913221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        if (fout == NULL) {
4013221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross            return false;
4113221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        }
4213221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross
4313221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        for (size_t i = 0; i < overlayVector.size(); ++i) {
4413221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross            const Overlay& overlay = overlayVector[i];
4513221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross            fprintf(fout, "%s %s\n", overlay.apk_path.string(), overlay.idmap_path.string());
4613221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        }
4713221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross
4813221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        fclose(fout);
4913221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross
5013221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        // Make file world readable since Zygote (running as root) will read
5113221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        // it when creating the initial AssetManger object
5213221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; // 0644
5313221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        if (chmod(filename, mode) == -1) {
5413221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross            unlink(filename);
5513221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross            return false;
5613221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        }
5713221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross
5813221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        return true;
5913221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross    }
6013221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross
6113221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross    String8 flatten_path(const char *path)
6213221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross    {
6313221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        String16 tmp(path);
6413221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        tmp.replaceAll('/', '@');
6513221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        return String8(tmp);
6613221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross    }
6713221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross
6813221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross    int parse_overlay_tag(const ResXMLTree& parser, const char *target_package_name)
6913221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross    {
7013221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        const size_t N = parser.getAttributeCount();
7113221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        String16 target;
7213221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        int priority = -1;
7313221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        for (size_t i = 0; i < N; ++i) {
7413221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross            size_t len;
7513221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross            String16 key(parser.getAttributeName(i, &len));
7613221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross            if (key == String16("targetPackage")) {
776698749dd4d4d6513b26aa9071af290b956b68a7Dan Albert                const char16_t *p = parser.getAttributeStringValue(i, &len);
78cfedceb8c180a2e176154d461659e0c3569dc931Andreas Gampe                if (p != NULL) {
7913221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross                    target = String16(p, len);
8013221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross                }
8113221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross            } else if (key == String16("priority")) {
8213221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross                Res_value v;
8313221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross                if (parser.getAttributeValue(i, &v) == sizeof(Res_value)) {
8413221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross                    priority = v.data;
8513221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross                    if (priority < 0 || priority > 9999) {
8613221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross                        return -1;
8713221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross                    }
8813221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross                }
8913221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross            }
9013221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        }
9113221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        if (target == String16(target_package_name)) {
9213221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross            return priority;
9313221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        }
9413221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        return NO_OVERLAY_TAG;
9513221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross    }
9613221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross
9713221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross    int parse_manifest(const void *data, size_t size, const char *target_package_name)
9813221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross    {
99de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski        ResXMLTree parser;
100de898ff42912bd7ca1bfb099cd439562496765a4Adam Lesinski        parser.setTo(data, size);
10113221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        if (parser.getError() != NO_ERROR) {
10213221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross            ALOGD("%s failed to init xml parser, error=0x%08x\n", __FUNCTION__, parser.getError());
10313221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross            return -1;
10413221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        }
10513221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross
10613221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        ResXMLParser::event_code_t type;
10713221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        do {
10813221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross            type = parser.next();
10913221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross            if (type == ResXMLParser::START_TAG) {
11013221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross                size_t len;
11113221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross                String16 tag(parser.getElementName(&len));
11213221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross                if (tag == String16("overlay")) {
11313221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross                    return parse_overlay_tag(parser, target_package_name);
11413221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross                }
11513221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross            }
11613221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        } while (type != ResXMLParser::BAD_DOCUMENT && type != ResXMLParser::END_DOCUMENT);
11713221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross
11813221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        return NO_OVERLAY_TAG;
11913221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross    }
12013221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross
12113221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross    int parse_apk(const char *path, const char *target_package_name)
12213221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross    {
1230881a7445f9106e835486c5a697c01f4f18e619bDan Albert        std::unique_ptr<ZipFileRO> zip(ZipFileRO::open(path));
12413221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        if (zip.get() == NULL) {
12513221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross            ALOGW("%s: failed to open zip %s\n", __FUNCTION__, path);
12613221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross            return -1;
12713221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        }
12813221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        ZipEntryRO entry;
12913221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        if ((entry = zip->findEntryByName("AndroidManifest.xml")) == NULL) {
13013221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross            ALOGW("%s: failed to find entry AndroidManifest.xml\n", __FUNCTION__);
13113221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross            return -1;
13213221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        }
1334600dd053dbdbd4b95f3b11057a1cc55b99f9c77Narayan Kamath        uint32_t uncompLen = 0;
1344600dd053dbdbd4b95f3b11057a1cc55b99f9c77Narayan Kamath        uint16_t method;
13513221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        if (!zip->getEntryInfo(entry, &method, &uncompLen, NULL, NULL, NULL, NULL)) {
13613221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross            ALOGW("%s: failed to read entry info\n", __FUNCTION__);
13713221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross            return -1;
13813221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        }
13913221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        if (method != ZipFileRO::kCompressDeflated) {
1404600dd053dbdbd4b95f3b11057a1cc55b99f9c77Narayan Kamath            ALOGW("%s: cannot handle zip compression method %" PRIu16 "\n", __FUNCTION__, method);
14113221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross            return -1;
14213221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        }
14313221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        FileMap *dataMap = zip->createEntryFileMap(entry);
144cfedceb8c180a2e176154d461659e0c3569dc931Andreas Gampe        if (dataMap == NULL) {
14513221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross            ALOGW("%s: failed to create FileMap\n", __FUNCTION__);
14613221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross            return -1;
14713221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        }
14813221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        char *buf = new char[uncompLen];
14913221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        if (NULL == buf) {
1504600dd053dbdbd4b95f3b11057a1cc55b99f9c77Narayan Kamath            ALOGW("%s: failed to allocate %" PRIu32 " byte\n", __FUNCTION__, uncompLen);
151688ff4cf0f93d1a886437884f23874e5595d59a3Narayan Kamath            delete dataMap;
15213221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross            return -1;
15313221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        }
15413221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        StreamingZipInflater inflater(dataMap, uncompLen);
15513221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        if (inflater.read(buf, uncompLen) < 0) {
1564600dd053dbdbd4b95f3b11057a1cc55b99f9c77Narayan Kamath            ALOGW("%s: failed to inflate %" PRIu32 " byte\n", __FUNCTION__, uncompLen);
15713221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross            delete[] buf;
158688ff4cf0f93d1a886437884f23874e5595d59a3Narayan Kamath            delete dataMap;
15913221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross            return -1;
16013221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        }
16113221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross
1624600dd053dbdbd4b95f3b11057a1cc55b99f9c77Narayan Kamath        int priority = parse_manifest(buf, static_cast<size_t>(uncompLen), target_package_name);
16313221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        delete[] buf;
164688ff4cf0f93d1a886437884f23874e5595d59a3Narayan Kamath        delete dataMap;
16513221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        return priority;
16613221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross    }
16713221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross}
16813221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross
16983ab0d7c1824f3a29e41af8a95a954c73f48c287Mårten Kongstadint idmap_scan(const char *target_package_name, const char *target_apk_path,
17083ab0d7c1824f3a29e41af8a95a954c73f48c287Mårten Kongstad        const char *idmap_dir, const android::Vector<const char *> *overlay_dirs)
17113221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross{
17213221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross    String8 filename = String8(idmap_dir);
17313221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross    filename.appendPath("overlays.list");
17413221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross    if (unlink(filename.string()) != 0 && errno != ENOENT) {
17513221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        return EXIT_FAILURE;
17613221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross    }
17713221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross
17813221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross    SortedVector<Overlay> overlayVector;
17983ab0d7c1824f3a29e41af8a95a954c73f48c287Mårten Kongstad    const size_t N = overlay_dirs->size();
18083ab0d7c1824f3a29e41af8a95a954c73f48c287Mårten Kongstad    for (size_t i = 0; i < N; ++i) {
18183ab0d7c1824f3a29e41af8a95a954c73f48c287Mårten Kongstad        const char *overlay_dir = overlay_dirs->itemAt(i);
18283ab0d7c1824f3a29e41af8a95a954c73f48c287Mårten Kongstad        DIR *dir = opendir(overlay_dir);
18383ab0d7c1824f3a29e41af8a95a954c73f48c287Mårten Kongstad        if (dir == NULL) {
18483ab0d7c1824f3a29e41af8a95a954c73f48c287Mårten Kongstad            return EXIT_FAILURE;
18583ab0d7c1824f3a29e41af8a95a954c73f48c287Mårten Kongstad        }
18683ab0d7c1824f3a29e41af8a95a954c73f48c287Mårten Kongstad
18783ab0d7c1824f3a29e41af8a95a954c73f48c287Mårten Kongstad        struct dirent *dirent;
18883ab0d7c1824f3a29e41af8a95a954c73f48c287Mårten Kongstad        while ((dirent = readdir(dir)) != NULL) {
18983ab0d7c1824f3a29e41af8a95a954c73f48c287Mårten Kongstad            struct stat st;
19083ab0d7c1824f3a29e41af8a95a954c73f48c287Mårten Kongstad            char overlay_apk_path[PATH_MAX + 1];
19183ab0d7c1824f3a29e41af8a95a954c73f48c287Mårten Kongstad            snprintf(overlay_apk_path, PATH_MAX, "%s/%s", overlay_dir, dirent->d_name);
19283ab0d7c1824f3a29e41af8a95a954c73f48c287Mårten Kongstad            if (stat(overlay_apk_path, &st) < 0) {
19383ab0d7c1824f3a29e41af8a95a954c73f48c287Mårten Kongstad                continue;
19483ab0d7c1824f3a29e41af8a95a954c73f48c287Mårten Kongstad            }
19583ab0d7c1824f3a29e41af8a95a954c73f48c287Mårten Kongstad            if (!S_ISREG(st.st_mode)) {
19683ab0d7c1824f3a29e41af8a95a954c73f48c287Mårten Kongstad                continue;
19783ab0d7c1824f3a29e41af8a95a954c73f48c287Mårten Kongstad            }
19813221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross
19983ab0d7c1824f3a29e41af8a95a954c73f48c287Mårten Kongstad            int priority = parse_apk(overlay_apk_path, target_package_name);
20083ab0d7c1824f3a29e41af8a95a954c73f48c287Mårten Kongstad            if (priority < 0) {
20183ab0d7c1824f3a29e41af8a95a954c73f48c287Mårten Kongstad                continue;
20283ab0d7c1824f3a29e41af8a95a954c73f48c287Mårten Kongstad            }
20313221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross
20483ab0d7c1824f3a29e41af8a95a954c73f48c287Mårten Kongstad            String8 idmap_path(idmap_dir);
20583ab0d7c1824f3a29e41af8a95a954c73f48c287Mårten Kongstad            idmap_path.appendPath(flatten_path(overlay_apk_path + 1));
20683ab0d7c1824f3a29e41af8a95a954c73f48c287Mårten Kongstad            idmap_path.append("@idmap");
20713221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross
20883ab0d7c1824f3a29e41af8a95a954c73f48c287Mårten Kongstad            if (idmap_create_path(target_apk_path, overlay_apk_path, idmap_path.string()) != 0) {
20983ab0d7c1824f3a29e41af8a95a954c73f48c287Mårten Kongstad                ALOGE("error: failed to create idmap for target=%s overlay=%s idmap=%s\n",
21083ab0d7c1824f3a29e41af8a95a954c73f48c287Mårten Kongstad                        target_apk_path, overlay_apk_path, idmap_path.string());
21183ab0d7c1824f3a29e41af8a95a954c73f48c287Mårten Kongstad                continue;
21283ab0d7c1824f3a29e41af8a95a954c73f48c287Mårten Kongstad            }
21383ab0d7c1824f3a29e41af8a95a954c73f48c287Mårten Kongstad
21483ab0d7c1824f3a29e41af8a95a954c73f48c287Mårten Kongstad            Overlay overlay(String8(overlay_apk_path), idmap_path, priority);
21583ab0d7c1824f3a29e41af8a95a954c73f48c287Mårten Kongstad            overlayVector.add(overlay);
21613221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        }
21713221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross
21883ab0d7c1824f3a29e41af8a95a954c73f48c287Mårten Kongstad        closedir(dir);
21913221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross    }
22013221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross
22113221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross    if (!writePackagesList(filename.string(), overlayVector)) {
22213221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross        return EXIT_FAILURE;
22313221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross    }
22413221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross
22513221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross    return EXIT_SUCCESS;
22613221c9cffdb289851411bdc73a9a5236fcb9291Colin Cross}
227