catalog.c revision 03e334a1c7dc8c20c38902aa039440763acc9b17
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering This file is part of systemd.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Copyright 2012 Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering systemd is free software; you can redistribute it and/or modify it
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering under the terms of the GNU Lesser General Public License as published by
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering (at your option) any later version.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering systemd is distributed in the hope that it will be useful, but
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Lesser General Public License for more details.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering You should have received a copy of the GNU Lesser General Public License
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
15a5e95075a7f6007dd97b2a165c8ed16fe683dfLennart Poetteringconst char * const catalog_file_dirs[] = {
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering#define CATALOG_SIGNATURE (uint8_t[]) { 'R', 'H', 'H', 'H', 'K', 'S', 'L', 'P' }
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poetteringunsigned long catalog_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) {
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering memcpy(mempcpy(v, &i->id, sizeof(i->id)), i->language, l);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering siphash24((uint8_t*) &u, v, sz, hash_key);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering return (unsigned long) u;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poetteringint catalog_compare_func(const void *a, const void *b) {
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering const CatalogItem *i = a, *j = b;
5bcd08db289cd02aad8a89b37b2a46244a7bd473Lennart Poettering for (k = 0; k < ELEMENTSOF(j->id.bytes); k++) {
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering offset = strbuf_add_string(sb, payload, strlen(payload));
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering assert(strlen(language) > 1 && strlen(language) < 32);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering log_warning("Duplicate entry for " SD_ID128_FORMAT_STR ".%s, ignoring.",
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering SD_ID128_FORMAT_VAL(id), language ? language : "C");
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poetteringint catalog_file_lang(const char* filename, char **lang) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering while (beg > filename && *beg != '.' && *beg != '/' && end - beg < 32)
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poetteringint catalog_import_file(Hashmap *h, struct strbuf *sb, const char *path) {
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering unsigned n = 0;
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering _cleanup_free_ char *deflang = NULL, *lang = NULL;
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering log_error("Failed to open file %s: %m", path);
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering log_error("Failed to determine language for file %s: %m", path);
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering log_debug("File %s has language %s.", path, deflang);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering log_error("Failed to read file %s: %m", path);
06820eafdbc3dd89cb1f7563564c7d91426709caLennart Poettering if (line[0] == 0) {
4e724d9c5ab76c3f8327945317463ef706011082Lennart Poettering (line[2+1+32] == ' ' || line[2+1+32] == '\0')) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering /* New entry */
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering if (sd_id128_from_string(line + 2 + 1, &jd) >= 0) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering r = finish_item(h, sb, id, lang ?: deflang, payload);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering log_error("[%s:%u] Language too short.", path, n);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering log_error("[%s:%u] language too long.", path, n);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering log_warning("[%s:%u] language %s", path, n,
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering "specified unnecessarily" :
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering "differs from default for file");
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering log_error("[%s:%u] Got payload before ID.", path, n);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering c = a + (empty_line ? 1 : 0) + b + 1 + 1;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering t[a+b] = '\n';
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = finish_item(h, sb, id, lang ?: deflang, payload);
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poetteringstatic long write_catalog(const char *database, Hashmap *h, struct strbuf *sb,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error("Recursive mkdir %s: %s", d, strerror(-r));
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering log_error("Failed to open database for writing: %s: %s",
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering memcpy(header.signature, CATALOG_SIGNATURE, sizeof(header.signature));
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering header.header_size = htole64(ALIGN_TO(sizeof(CatalogHeader), 8));
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering header.catalog_item_size = htole64(sizeof(CatalogItem));
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering header.n_items = htole64(hashmap_size(h));
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering k = fwrite(&header, 1, sizeof(header), w);
554604b3073467af75dc94fac9e2343148603289Lennart Poettering if (k != sizeof(header)) {
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering log_error("%s: failed to write header.", p);
554604b3073467af75dc94fac9e2343148603289Lennart Poettering k = fwrite(items, 1, n * sizeof(CatalogItem), w);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (k != n * sizeof(CatalogItem)) {
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering log_error("%s: failed to write database.", p);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error("%s: failed to write strings.", p);
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering log_error("%s: failed to write database.", p);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error("rename (%s -> %s) failed: %m", p, database);
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poetteringint catalog_update(const char* database, const char* root, const char* const* dirs) {
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering _cleanup_free_ CatalogItem *items = NULL;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering h = hashmap_new(catalog_hash_func, catalog_compare_func);
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering if (!h || !sb) {
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering r = conf_files_list_strv(&files, ".catalog", root, dirs);
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering log_error("Failed to get catalog files: %s", strerror(-r));
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering log_debug("Found %u items in catalog.", hashmap_size(h));
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering items = new(CatalogItem, hashmap_size(h));
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering log_debug("Found " SD_ID128_FORMAT_STR ", language %s",
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering isempty(i->language) ? "C" : i->language);
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering qsort_safe(items, n, sizeof(CatalogItem), catalog_compare_func);
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering r = write_catalog(database, h, sb, items, n);
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering log_error("Failed to write %s: %s", database, strerror(-r));
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering log_debug("%s: wrote %u items, with %zu bytes of strings, %ld total size.",
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering return r < 0 ? r : 0;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poetteringstatic int open_mmap(const char *database, int *_fd, struct stat *_st, void **_p) {
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering if (st.st_size < (off_t) sizeof(CatalogHeader)) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering p = mmap(NULL, PAGE_ALIGN(st.st_size), PROT_READ, MAP_SHARED, fd, 0);
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering if (memcmp(h->signature, CATALOG_SIGNATURE, sizeof(h->signature)) != 0 ||
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering le64toh(h->header_size) < sizeof(CatalogHeader) ||
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering le64toh(h->catalog_item_size) < sizeof(CatalogItem) ||
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering st.st_size < (off_t) (le64toh(h->header_size) + le64toh(h->catalog_item_size) * le64toh(h->n_items))) {
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poetteringstatic const char *find_id(void *p, sd_id128_t id) {
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering if (loc && loc[0] && !streq(loc, "C") && !streq(loc, "POSIX")) {
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering strncpy(key.language, loc, sizeof(key.language));
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering key.language[strcspn(key.language, ".@")] = 0;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering f = bsearch(&key, (const uint8_t*) p + le64toh(h->header_size), le64toh(h->n_items), le64toh(h->catalog_item_size), catalog_compare_func);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering f = bsearch(&key, (const uint8_t*) p + le64toh(h->header_size), le64toh(h->n_items), le64toh(h->catalog_item_size), catalog_compare_func);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering f = bsearch(&key, (const uint8_t*) p + le64toh(h->header_size), le64toh(h->n_items), le64toh(h->catalog_item_size), catalog_compare_func);
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering return (const char*) p +
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering le64toh(h->n_items) * le64toh(h->catalog_item_size) +
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poetteringint catalog_get(const char* database, sd_id128_t id, char **_text) {
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering const char *s;
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poetteringstatic char *find_header(const char *s, const char *header) {
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering const char *v, *e;
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering /* End of text */
c19de71113f956809995fc68817e055e9f61f607Lennart Poettering /* End of header */
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poetteringstatic void dump_catalog_entry(FILE *f, sd_id128_t id, const char *s, bool oneline) {
9030ca462bd13cd6536299814e4a71d5c5e85be9Lennart Poettering _cleanup_free_ char *subject = NULL, *defined_by = NULL;
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering defined_by = find_header(s, "Defined-By:");
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering fprintf(f, SD_ID128_FORMAT_STR " %s: %s\n",
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering fprintf(f, "-- " SD_ID128_FORMAT_STR "\n%s\n",
40205d706e1210763ff4c98a317556375bd04bcdLennart Poetteringint catalog_list(FILE *f, const char *database, bool oneline) {
5f8cc96a0301c1177b11dd2e89370ef0b2ef577bLennart Poettering items = (const CatalogItem*) ((const uint8_t*) p + le64toh(h->header_size));
5f8cc96a0301c1177b11dd2e89370ef0b2ef577bLennart Poettering for (n = 0; n < le64toh(h->n_items); n++) {
5f8cc96a0301c1177b11dd2e89370ef0b2ef577bLennart Poettering const char *s;
5f8cc96a0301c1177b11dd2e89370ef0b2ef577bLennart Poettering if (last_id_set && sd_id128_equal(last_id, items[n].id))
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering dump_catalog_entry(f, items[n].id, s, oneline);
49af9e1368571f4e423cde0fd45ee284451434d1Lennart Poetteringint catalog_list_items(FILE *f, const char *database, bool oneline, char **items) {
49af9e1368571f4e423cde0fd45ee284451434d1Lennart Poettering log_error("Failed to parse id128 '%s': %s",
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering log_full(k == -ENOENT ? LOG_NOTICE : LOG_ERR,
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering "Failed to retrieve catalog entry for '%s': %s",