catalog.c revision 03e334a1c7dc8c20c38902aa039440763acc9b17
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering/***
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering This file is part of systemd.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Copyright 2012 Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart 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
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
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/>.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering***/
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <fcntl.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <stdio.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <unistd.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <errno.h>
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering#include <string.h>
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering#include <sys/mman.h>
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering#include <locale.h>
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering#include <libgen.h>
96aad8d15a324d0e956a4e5653a11a67b209b41aLennart Poettering
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering#include "util.h"
23c80348e656a4e6fd9ba8f17523a65b6fa349a0Kay Sievers#include "log.h"
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering#include "sparse-endian.h"
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering#include "sd-id128.h"
25300b5a1fcf54674a69d0f4ab08925be00b0227Lennart Poettering#include "hashmap.h"
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering#include "strv.h"
a90fb858ac91de4c14c9b68da6060731954515b7Lennart Poettering#include "strbuf.h"
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering#include "strxcpyx.h"
003dffde2c1b93afbc9aff24b277276f65424406Lennart Poettering#include "conf-files.h"
4cee5eede280b7fd48c18a1942616c4ac896a554Lennart Poettering#include "mkdir.h"
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering#include "catalog.h"
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering#include "siphash24.h"
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering
15a5e95075a7f6007dd97b2a165c8ed16fe683dfLennart Poetteringconst char * const catalog_file_dirs[] = {
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering "/usr/local/lib/systemd/catalog/",
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering "/usr/lib/systemd/catalog/",
b1d4f8e154bf61b5de1b27461ef8e9c8c5e838a1Lennart Poettering NULL
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering};
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering#define CATALOG_SIGNATURE (uint8_t[]) { 'R', 'H', 'H', 'H', 'K', 'S', 'L', 'P' }
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poetteringtypedef struct CatalogHeader {
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering uint8_t signature[8]; /* "RHHHKSLP" */
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering le32_t compatible_flags;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering le32_t incompatible_flags;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering le64_t header_size;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering le64_t n_items;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering le64_t catalog_item_size;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering} CatalogHeader;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poetteringtypedef struct CatalogItem {
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering sd_id128_t id;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering char language[32];
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering le64_t offset;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering} CatalogItem;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poetteringunsigned long catalog_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) {
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering const CatalogItem *i = p;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering uint64_t u;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering size_t l, sz;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering void *v;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering l = strlen(i->language);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering sz = sizeof(i->id) + l;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering v = alloca(sz);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering memcpy(mempcpy(v, &i->id, sizeof(i->id)), i->language, l);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering siphash24((uint8_t*) &u, v, sz, hash_key);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering return (unsigned long) u;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering}
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poetteringint catalog_compare_func(const void *a, const void *b) {
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering const CatalogItem *i = a, *j = b;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering unsigned k;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
5bcd08db289cd02aad8a89b37b2a46244a7bd473Lennart Poettering for (k = 0; k < ELEMENTSOF(j->id.bytes); k++) {
cb81cd8073392936882643af0129934bf67e96c4Lennart Poettering if (i->id.bytes[k] < j->id.bytes[k])
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering return -1;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering if (i->id.bytes[k] > j->id.bytes[k])
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering return 1;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering }
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering return strcmp(i->language, j->language);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering}
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poetteringstatic int finish_item(
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering Hashmap *h,
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering struct strbuf *sb,
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering sd_id128_t id,
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering const char *language,
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering const char *payload) {
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering ssize_t offset;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering CatalogItem *i;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering int r;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering assert(h);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering assert(sb);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering assert(payload);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering offset = strbuf_add_string(sb, payload, strlen(payload));
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering if (offset < 0)
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering return log_oom();
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering i = new0(CatalogItem, 1);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering if (!i)
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering return log_oom();
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering i->id = id;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering if (language) {
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering assert(strlen(language) > 1 && strlen(language) < 32);
5bcd08db289cd02aad8a89b37b2a46244a7bd473Lennart Poettering strcpy(i->language, language);
cb81cd8073392936882643af0129934bf67e96c4Lennart Poettering }
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering i->offset = htole64((uint64_t) offset);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering r = hashmap_put(h, i, i);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering if (r == EEXIST) {
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering log_warning("Duplicate entry for " SD_ID128_FORMAT_STR ".%s, ignoring.",
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering SD_ID128_FORMAT_VAL(id), language ? language : "C");
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering free(i);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering return 0;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering }
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering return 0;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering}
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poetteringint catalog_file_lang(const char* filename, char **lang) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering char *beg, *end, *_lang;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering end = endswith(filename, ".catalog");
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (!end)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return 0;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering beg = end - 1;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering while (beg > filename && *beg != '.' && *beg != '/' && end - beg < 32)
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering beg --;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (*beg != '.' || end <= beg + 1)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return 0;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering _lang = strndup(beg + 1, end - beg - 1);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (!_lang)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return -ENOMEM;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering *lang = _lang;
df2d202e6ed4001a21c6512c244acad5d4706c87Lennart Poettering return 1;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering}
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poetteringint catalog_import_file(Hashmap *h, struct strbuf *sb, const char *path) {
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering _cleanup_fclose_ FILE *f = NULL;
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering _cleanup_free_ char *payload = NULL;
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering unsigned n = 0;
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering sd_id128_t id;
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering _cleanup_free_ char *deflang = NULL, *lang = NULL;
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering bool got_id = false, empty_line = true;
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering int r;
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering assert(h);
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering assert(sb);
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering assert(path);
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering f = fopen(path, "re");
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering if (!f) {
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering log_error("Failed to open file %s: %m", path);
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering return -errno;
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering }
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering r = catalog_file_lang(path, &deflang);
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering if (r < 0)
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering log_error("Failed to determine language for file %s: %m", path);
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering if (r == 1)
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering log_debug("File %s has language %s.", path, deflang);
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering for (;;) {
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering char line[LINE_MAX];
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering size_t a, b, c;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering char *t;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
4e724d9c5ab76c3f8327945317463ef706011082Lennart Poettering if (!fgets(line, sizeof(line), f)) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (feof(f))
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering break;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering log_error("Failed to read file %s: %m", path);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return -errno;
4e724d9c5ab76c3f8327945317463ef706011082Lennart Poettering }
4e724d9c5ab76c3f8327945317463ef706011082Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering n++;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering truncate_nl(line);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
06820eafdbc3dd89cb1f7563564c7d91426709caLennart Poettering if (line[0] == 0) {
06820eafdbc3dd89cb1f7563564c7d91426709caLennart Poettering empty_line = true;
06820eafdbc3dd89cb1f7563564c7d91426709caLennart Poettering continue;
4e724d9c5ab76c3f8327945317463ef706011082Lennart Poettering }
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering if (strchr(COMMENTS "\n", line[0]))
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering continue;
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering if (empty_line &&
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering strlen(line) >= 2+1+32 &&
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering line[0] == '-' &&
4e724d9c5ab76c3f8327945317463ef706011082Lennart Poettering line[1] == '-' &&
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering line[2] == ' ' &&
4e724d9c5ab76c3f8327945317463ef706011082Lennart Poettering (line[2+1+32] == ' ' || line[2+1+32] == '\0')) {
4e724d9c5ab76c3f8327945317463ef706011082Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering bool with_language;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering sd_id128_t jd;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering /* New entry */
de0671ee7fe465e108f62dcbbbe9366f81dd9e9aZbigniew Jędrzejewski-Szmek
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering with_language = line[2+1+32] != '\0';
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering line[2+1+32] = '\0';
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering if (sd_id128_from_string(line + 2 + 1, &jd) >= 0) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
df2d202e6ed4001a21c6512c244acad5d4706c87Lennart Poettering if (got_id) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering r = finish_item(h, sb, id, lang ?: deflang, payload);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (r < 0)
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering return r;
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering free(lang);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering lang = NULL;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering }
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (with_language) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering t = strstrip(line + 2 + 1 + 32 + 1);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering c = strlen(t);
df2d202e6ed4001a21c6512c244acad5d4706c87Lennart Poettering if (c <= 0) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering log_error("[%s:%u] Language too short.", path, n);
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering return -EINVAL;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering }
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (c > 31) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering log_error("[%s:%u] language too long.", path, n);
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering return -EINVAL;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering }
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (deflang) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering log_warning("[%s:%u] language %s", path, n,
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering streq(t, deflang) ?
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering "specified unnecessarily" :
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering "differs from default for file");
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering lang = strdup(t);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (!lang)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return -ENOMEM;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering }
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering }
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering got_id = true;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering empty_line = false;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering id = jd;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (payload)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering payload[0] = '\0';
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering continue;
9030ca462bd13cd6536299814e4a71d5c5e85be9Lennart Poettering }
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering }
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering /* Payload */
8aec412ff697bc14995746953912ca6fdf2c9ba8Lennart Poettering if (!got_id) {
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering log_error("[%s:%u] Got payload before ID.", path, n);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -EINVAL;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering a = payload ? strlen(payload) : 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering b = strlen(line);
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering c = a + (empty_line ? 1 : 0) + b + 1 + 1;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering t = realloc(payload, c);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (!t)
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering return log_oom();
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (empty_line) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering t[a] = '\n';
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering memcpy(t + a + 1, line, b);
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering t[a+b+1] = '\n';
7f0d207d2c816e0a8cb2742b0a789911f7c99356Lennart Poettering t[a+b+2] = 0;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering } else {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering memcpy(t + a, line, b);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering t[a+b] = '\n';
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering t[a+b+1] = 0;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering payload = t;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering empty_line = false;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering if (got_id) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = finish_item(h, sb, id, lang ?: deflang, payload);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (r < 0)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return r;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering return 0;
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering}
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poetteringstatic long write_catalog(const char *database, Hashmap *h, struct strbuf *sb,
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering CatalogItem *items, size_t n) {
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering CatalogHeader header;
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering _cleanup_fclose_ FILE *w = NULL;
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering int r;
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering _cleanup_free_ char *d, *p = NULL;
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering size_t k;
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering d = dirname_malloc(database);
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering if (!d)
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering return log_oom();
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = mkdir_p(d, 0775);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error("Recursive mkdir %s: %s", d, strerror(-r));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = fopen_temporary(database, &w, &p);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (r < 0) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering log_error("Failed to open database for writing: %s: %s",
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering database, strerror(-r));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return r;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering }
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering zero(header);
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));
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering r = -EIO;
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering
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);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering goto error;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering }
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
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 goto error;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering k = fwrite(sb->buf, 1, sb->len, w);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (k != sb->len) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error("%s: failed to write strings.", p);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering goto error;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering fflush(w);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (ferror(w)) {
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering log_error("%s: failed to write database.", p);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering goto error;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering fchmod(fileno(w), 0644);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (rename(p, database) < 0) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error("rename (%s -> %s) failed: %m", p, database);
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering r = -errno;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering goto error;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return ftell(w);
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poetteringerror:
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering unlink(p);
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering return r;
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering}
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poetteringint catalog_update(const char* database, const char* root, const char* const* dirs) {
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering _cleanup_strv_free_ char **files = NULL;
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering char **f;
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering Hashmap *h;
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering struct strbuf *sb = NULL;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering _cleanup_free_ CatalogItem *items = NULL;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering CatalogItem *i;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering Iterator j;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering unsigned n;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering long r;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering h = hashmap_new(catalog_hash_func, catalog_compare_func);
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering sb = strbuf_new();
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering if (!h || !sb) {
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering r = log_oom();
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering goto finish;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering }
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering r = conf_files_list_strv(&files, ".catalog", root, dirs);
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering if (r < 0) {
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering log_error("Failed to get catalog files: %s", strerror(-r));
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering goto finish;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering }
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering STRV_FOREACH(f, files) {
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering log_debug("reading file '%s'", *f);
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering catalog_import_file(h, sb, *f);
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering }
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering if (hashmap_size(h) <= 0) {
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering log_info("No items in catalog.");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering goto finish;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering } else
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering log_debug("Found %u items in catalog.", hashmap_size(h));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering strbuf_complete(sb);
a3e7f417d72ba3251fd6b3a228a2721a4b725a03Zbigniew Jędrzejewski-Szmek
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering items = new(CatalogItem, hashmap_size(h));
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering if (!items) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = log_oom();
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering goto finish;
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering }
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering n = 0;
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering HASHMAP_FOREACH(i, h, j) {
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering log_debug("Found " SD_ID128_FORMAT_STR ", language %s",
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering SD_ID128_FORMAT_VAL(i->id),
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering isempty(i->language) ? "C" : i->language);
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering items[n++] = *i;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering }
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering assert(n == hashmap_size(h));
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering qsort_safe(items, n, sizeof(CatalogItem), catalog_compare_func);
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering r = write_catalog(database, h, sb, items, n);
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering if (r < 0)
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering log_error("Failed to write %s: %s", database, strerror(-r));
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering else
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering log_debug("%s: wrote %u items, with %zu bytes of strings, %ld total size.",
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering database, n, sb->len, r);
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering r = 0;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poetteringfinish:
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering if (h)
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering hashmap_free_free(h);
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering if (sb)
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering strbuf_cleanup(sb);
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering return r < 0 ? r : 0;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering}
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poetteringstatic int open_mmap(const char *database, int *_fd, struct stat *_st, void **_p) {
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering const CatalogHeader *h;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering int fd;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering void *p;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering struct stat st;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering assert(_fd);
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering assert(_st);
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering assert(_p);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering fd = open(database, O_RDONLY|O_CLOEXEC);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (fd < 0)
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering return -errno;
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering if (fstat(fd, &st) < 0) {
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering safe_close(fd);
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering return -errno;
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering }
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering if (st.st_size < (off_t) sizeof(CatalogHeader)) {
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering safe_close(fd);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -EINVAL;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering }
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering p = mmap(NULL, PAGE_ALIGN(st.st_size), PROT_READ, MAP_SHARED, fd, 0);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (p == MAP_FAILED) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering safe_close(fd);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -errno;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering h = p;
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) ||
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering h->incompatible_flags != 0 ||
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering le64toh(h->n_items) <= 0 ||
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering st.st_size < (off_t) (le64toh(h->header_size) + le64toh(h->catalog_item_size) * le64toh(h->n_items))) {
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering safe_close(fd);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering munmap(p, st.st_size);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -EBADMSG;
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering }
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering *_fd = fd;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering *_st = st;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering *_p = p;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering return 0;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poetteringstatic const char *find_id(void *p, sd_id128_t id) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering CatalogItem key, *f = NULL;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering const CatalogHeader *h = p;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering const char *loc;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering zero(key);
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering key.id = id;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering loc = setlocale(LC_MESSAGES, NULL);
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
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 if (!f) {
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering char *e;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering e = strchr(key.language, '_');
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering if (e) {
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering *e = 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);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering }
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering }
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering if (!f) {
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering zero(key.language);
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);
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering }
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!f)
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering return NULL;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering return (const char*) p +
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering le64toh(h->header_size) +
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering le64toh(h->n_items) * le64toh(h->catalog_item_size) +
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering le64toh(f->offset);
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering}
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poetteringint catalog_get(const char* database, sd_id128_t id, char **_text) {
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering _cleanup_close_ int fd = -1;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering void *p = NULL;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering struct stat st;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering char *text = NULL;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering int r;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering const char *s;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering assert(_text);
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering r = open_mmap(database, &fd, &st, &p);
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering if (r < 0)
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering return r;
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering s = find_id(p, id);
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering if (!s) {
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering r = -ENOENT;
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering goto finish;
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering }
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering text = strdup(s);
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering if (!text) {
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering r = -ENOMEM;
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering goto finish;
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering }
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering *_text = text;
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering r = 0;
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poetteringfinish:
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering if (p)
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering munmap(p, st.st_size);
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering return r;
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering}
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poetteringstatic char *find_header(const char *s, const char *header) {
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering for (;;) {
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering const char *v, *e;
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering v = startswith(s, header);
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering if (v) {
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering v += strspn(v, WHITESPACE);
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering return strndup(v, strcspn(v, NEWLINE));
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering }
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering /* End of text */
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering e = strchr(s, '\n');
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering if (!e)
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering return NULL;
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering
c19de71113f956809995fc68817e055e9f61f607Lennart Poettering /* End of header */
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering if (e == s)
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering return NULL;
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering s = e + 1;
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering }
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering}
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poetteringstatic void dump_catalog_entry(FILE *f, sd_id128_t id, const char *s, bool oneline) {
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering if (oneline) {
9030ca462bd13cd6536299814e4a71d5c5e85be9Lennart Poettering _cleanup_free_ char *subject = NULL, *defined_by = NULL;
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering subject = find_header(s, "Subject:");
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering defined_by = find_header(s, "Defined-By:");
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering fprintf(f, SD_ID128_FORMAT_STR " %s: %s\n",
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering SD_ID128_FORMAT_VAL(id),
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering strna(defined_by), strna(subject));
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering } else
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering fprintf(f, "-- " SD_ID128_FORMAT_STR "\n%s\n",
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering SD_ID128_FORMAT_VAL(id), s);
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering}
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering
40205d706e1210763ff4c98a317556375bd04bcdLennart Poetteringint catalog_list(FILE *f, const char *database, bool oneline) {
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering _cleanup_close_ int fd = -1;
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering void *p = NULL;
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering struct stat st;
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering const CatalogHeader *h;
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering const CatalogItem *items;
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering int r;
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering unsigned n;
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering sd_id128_t last_id;
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering bool last_id_set = false;
5f8cc96a0301c1177b11dd2e89370ef0b2ef577bLennart Poettering
5f8cc96a0301c1177b11dd2e89370ef0b2ef577bLennart Poettering r = open_mmap(database, &fd, &st, &p);
5f8cc96a0301c1177b11dd2e89370ef0b2ef577bLennart Poettering if (r < 0)
5f8cc96a0301c1177b11dd2e89370ef0b2ef577bLennart Poettering return r;
5f8cc96a0301c1177b11dd2e89370ef0b2ef577bLennart Poettering
5f8cc96a0301c1177b11dd2e89370ef0b2ef577bLennart Poettering h = p;
5f8cc96a0301c1177b11dd2e89370ef0b2ef577bLennart Poettering items = (const CatalogItem*) ((const uint8_t*) p + le64toh(h->header_size));
5f8cc96a0301c1177b11dd2e89370ef0b2ef577bLennart Poettering
5f8cc96a0301c1177b11dd2e89370ef0b2ef577bLennart Poettering for (n = 0; n < le64toh(h->n_items); n++) {
5f8cc96a0301c1177b11dd2e89370ef0b2ef577bLennart Poettering const char *s;
086821244b5113f00a0ef993b78dc56aae2a8f6cLennart Poettering
5f8cc96a0301c1177b11dd2e89370ef0b2ef577bLennart Poettering if (last_id_set && sd_id128_equal(last_id, items[n].id))
5f8cc96a0301c1177b11dd2e89370ef0b2ef577bLennart Poettering continue;
5f8cc96a0301c1177b11dd2e89370ef0b2ef577bLennart Poettering
5f8cc96a0301c1177b11dd2e89370ef0b2ef577bLennart Poettering assert_se(s = find_id(p, items[n].id));
5f8cc96a0301c1177b11dd2e89370ef0b2ef577bLennart Poettering
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering dump_catalog_entry(f, items[n].id, s, oneline);
5f8cc96a0301c1177b11dd2e89370ef0b2ef577bLennart Poettering
5f8cc96a0301c1177b11dd2e89370ef0b2ef577bLennart Poettering last_id_set = true;
49af9e1368571f4e423cde0fd45ee284451434d1Lennart Poettering last_id = items[n].id;
49af9e1368571f4e423cde0fd45ee284451434d1Lennart Poettering }
49af9e1368571f4e423cde0fd45ee284451434d1Lennart Poettering
49af9e1368571f4e423cde0fd45ee284451434d1Lennart Poettering munmap(p, st.st_size);
49af9e1368571f4e423cde0fd45ee284451434d1Lennart Poettering
49af9e1368571f4e423cde0fd45ee284451434d1Lennart Poettering return 0;
49af9e1368571f4e423cde0fd45ee284451434d1Lennart Poettering}
49af9e1368571f4e423cde0fd45ee284451434d1Lennart Poettering
49af9e1368571f4e423cde0fd45ee284451434d1Lennart Poetteringint catalog_list_items(FILE *f, const char *database, bool oneline, char **items) {
49af9e1368571f4e423cde0fd45ee284451434d1Lennart Poettering char **item;
49af9e1368571f4e423cde0fd45ee284451434d1Lennart Poettering int r = 0;
49af9e1368571f4e423cde0fd45ee284451434d1Lennart Poettering
49af9e1368571f4e423cde0fd45ee284451434d1Lennart Poettering STRV_FOREACH(item, items) {
49af9e1368571f4e423cde0fd45ee284451434d1Lennart Poettering sd_id128_t id;
49af9e1368571f4e423cde0fd45ee284451434d1Lennart Poettering int k;
49af9e1368571f4e423cde0fd45ee284451434d1Lennart Poettering _cleanup_free_ char *msg = NULL;
49af9e1368571f4e423cde0fd45ee284451434d1Lennart Poettering
49af9e1368571f4e423cde0fd45ee284451434d1Lennart Poettering k = sd_id128_from_string(*item, &id);
49af9e1368571f4e423cde0fd45ee284451434d1Lennart Poettering if (k < 0) {
49af9e1368571f4e423cde0fd45ee284451434d1Lennart Poettering log_error("Failed to parse id128 '%s': %s",
49af9e1368571f4e423cde0fd45ee284451434d1Lennart Poettering *item, strerror(-k));
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering if (r == 0)
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering r = k;
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering continue;
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering }
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering k = catalog_get(database, id, &msg);
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering if (k < 0) {
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering log_full(k == -ENOENT ? LOG_NOTICE : LOG_ERR,
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering "Failed to retrieve catalog entry for '%s': %s",
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering *item, strerror(-k));
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering if (r == 0)
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering r = k;
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering continue;
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering }
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering dump_catalog_entry(f, id, msg, oneline);
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering }
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering return r;
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering}
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering