catalog.c revision 54b7254c1fa629937f92fd6fa34bdf127b696a00
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering This file is part of systemd.
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering Copyright 2012 Lennart Poettering
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering systemd is free software; you can redistribute it and/or modify it
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering under the terms of the GNU Lesser General Public License as published by
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering (at your option) any later version.
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering systemd is distributed in the hope that it will be useful, but
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering Lesser General Public License for more details.
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering You should have received a copy of the GNU Lesser General Public License
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringstatic const char * const conf_file_dirs[] = {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering#define CATALOG_SIGNATURE (uint8_t[]) { 'R', 'H', 'H', 'H', 'K', 'S', 'L', 'P' }
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poetteringstatic unsigned catalog_hash_func(const void *p) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering assert_cc(sizeof(unsigned) == sizeof(uint8_t)*4);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering return (((unsigned) i->id.bytes[0] << 24) |
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringstatic int catalog_compare_func(const void *a, const void *b) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering const CatalogItem *i = a, *j = b;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering for (k = 0; k < ELEMENTSOF(j->id.bytes); k++) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering return strncmp(i->language, j->language, sizeof(i->language));
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering offset = strbuf_add_string(sb, payload, strlen(payload));
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering strncpy(i->language, language, sizeof(i->language));
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_warning("Duplicate entry for " SD_ID128_FORMAT_STR ".%s, ignoring.", SD_ID128_FORMAT_VAL(id), language ? language : "C");
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringstatic int import_file(Hashmap *h, struct strbuf *sb, const char *path) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering unsigned n = 0;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_error("Failed to open file %s: %m", path);
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack if (line[0] == 0) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering (line[2+1+32] == ' ' || line[2+1+32] == 0)) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* New entry */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (sd_id128_from_string(line + 2 + 1, &jd) >= 0) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering r = finish_item(h, sb, id, language, payload);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_error("[%s:%u] Language too short.", path, n);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (c > sizeof(language)) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_error("[%s:%u] language too long.", path, n);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_error("[%s:%u] Got payload before ID.", path, n);
3f9da416457c4265b8f1179516a32ad1a987ff7dLennart Poettering c = a + (empty_line ? 1 : 0) + b + 1 + 1;
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack t[a] = '\n';
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering t[a+b] = '\n';
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering r = finish_item(h, sb, id, language, payload);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering#define CATALOG_DATABASE CATALOG_PATH "/database"
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering _cleanup_free_ CatalogItem *items = NULL;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering h = hashmap_new(catalog_hash_func, catalog_compare_func);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering r = conf_files_list_strv(&files, ".catalog", NULL, (const char **) conf_file_dirs);
8f077bf94e129fa1b6f0159e3140c4326f1066cfZbigniew Jędrzejewski-Szmek log_error("Failed to get catalog files: %s", strerror(-r));
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_debug("Found %u items in catalog.", hashmap_size(h));
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering items = new(CatalogItem, hashmap_size(h));
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering log_debug("Found " SD_ID128_FORMAT_STR ", language %s", SD_ID128_FORMAT_VAL(i->id), isempty(i->language) ? "C" : i->language);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering qsort(items, n, sizeof(CatalogItem), catalog_compare_func);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_error("Recursive mkdir %s: %s", CATALOG_PATH, strerror(-r));
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering r = fopen_temporary(CATALOG_DATABASE, &w, &p);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_error("Failed to open database for writing: %s: %s",
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering memcpy(header.signature, CATALOG_SIGNATURE, sizeof(header.signature));
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering header.header_size = htole64(ALIGN_TO(sizeof(CatalogHeader), 8));
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering header.catalog_item_size = htole64(sizeof(CatalogItem));
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering header.n_items = htole64(hashmap_size(h));
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering k = fwrite(&header, 1, sizeof(header), w);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (k != sizeof(header)) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering log_error("%s: failed to write header.", p);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering k = fwrite(items, 1, n * sizeof(CatalogItem), w);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (k != n * sizeof(CatalogItem)) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering log_error("%s: failed to write database.", p);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_error("%s: failed to write strings.", p);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_error("%s: failed to write database.", p);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering log_error("rename (%s -> %s) failed: %m", p, CATALOG_DATABASE);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering log_debug("%s: wrote %u items, with %zu bytes of strings, %ld total size.",
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poetteringstatic int open_mmap(int *_fd, struct stat *_st, void **_p) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering fd = open(CATALOG_DATABASE, O_RDONLY|O_CLOEXEC);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (st.st_size < (off_t) sizeof(CatalogHeader)) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering p = mmap(NULL, PAGE_ALIGN(st.st_size), PROT_READ, MAP_SHARED, fd, 0);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (memcmp(h->signature, CATALOG_SIGNATURE, sizeof(h->signature)) != 0 ||
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering le64toh(h->header_size) < sizeof(CatalogHeader) ||
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering le64toh(h->catalog_item_size) < sizeof(CatalogItem) ||
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering st.st_size < (off_t) (le64toh(h->header_size) + le64toh(h->catalog_item_size) * le64toh(h->n_items))) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringstatic const char *find_id(void *p, sd_id128_t id) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering if (loc && loc[0] && !streq(loc, "C") && !streq(loc, "POSIX")) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering strncpy(key.language, loc, sizeof(key.language));
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering key.language[strcspn(key.language, ".@")] = 0;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering f = bsearch(&key, (const uint8_t*) p + le64toh(h->header_size), le64toh(h->n_items), le64toh(h->catalog_item_size), catalog_compare_func);
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering f = bsearch(&key, (const uint8_t*) p + le64toh(h->header_size), le64toh(h->n_items), le64toh(h->catalog_item_size), catalog_compare_func);
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack f = bsearch(&key, (const uint8_t*) p + le64toh(h->header_size), le64toh(h->n_items), le64toh(h->catalog_item_size), catalog_compare_func);
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack return (const char*) p +
5892a914d173e4b968d2a14fbf717373dee3999aDaniel Mack le64toh(h->n_items) * le64toh(h->catalog_item_size) +
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringint catalog_get(sd_id128_t id, char **_text) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering const char *s;
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poetteringstatic char *find_header(const char *s, const char *header) {
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering const char *v, *e;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* End of text */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering /* End of header */
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringstatic void dump_catalog_entry(FILE *f, sd_id128_t id, const char *s, bool oneline) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering _cleanup_free_ char *subject = NULL, *defined_by = NULL;
ff975efb2e88dcd5221a2f0d76c4c87e85b821a8Lennart Poettering defined_by = find_header(s, "Defined-By:");
16ac401407959cbc62312e61c2dd76dbc3a0793bLennart Poettering fprintf(f, SD_ID128_FORMAT_STR " %s: %s\n",
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering fprintf(f, "-- " SD_ID128_FORMAT_STR "\n%s\n",
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering items = (const CatalogItem*) ((const uint8_t*) p + le64toh(h->header_size));
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering for (n = 0; n < le64toh(h->n_items); n++) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering const char *s;
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering if (last_id_set && sd_id128_equal(last_id, items[n].id))
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering dump_catalog_entry(f, items[n].id, s, oneline);
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poetteringint catalog_list_items(FILE *f, bool oneline, char **items) {
e821075a23fdfa3ca7738fc30bb2d4c430fe10c0Lennart Poettering log_error("Failed to parse id128 '%s': %s",
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering log_full(k == -ENOENT ? LOG_NOTICE : LOG_ERR,
a4152e3fe28b53b8919cc404dd7eca7ead1bf9bdLennart Poettering "Failed to retrieve catalog entry for '%s': %s",