catalog.c revision 709f6e46a35ec492b70eb92943d82a8d838ce918
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering/***
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering This file is part of systemd.
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering Copyright 2012 Lennart Poettering
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering systemd is free software; you can redistribute it and/or modify it
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering under the terms of the GNU Lesser General Public License as published by
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering (at your option) any later version.
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering systemd is distributed in the hope that it will be useful, but
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering Lesser General Public License for more details.
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering You should have received a copy of the GNU Lesser General Public License
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering***/
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include <errno.h>
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include <fcntl.h>
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include <locale.h>
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include <stdio.h>
a9cdc94f7ff40f22a3cf9472f612a80730a1b010Dave Reisner#include <string.h>
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include <sys/mman.h>
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen#include <unistd.h>
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen#include "sd-id128.h"
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include "alloc-util.h"
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include "catalog.h"
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include "conf-files.h"
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include "fd-util.h"
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include "fileio.h"
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include "hashmap.h"
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include "log.h"
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering#include "mkdir.h"
7085053a437456ab87d726f3697002dd811fdf7aDaniel Wallace#include "path-util.h"
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering#include "siphash24.h"
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include "sparse-endian.h"
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include "strbuf.h"
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include "string-util.h"
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include "strv.h"
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include "util.h"
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
1b12a7b5896f94bdf33b3a6661ebabd761ea6adcHarald Hoyerconst char * const catalog_file_dirs[] = {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering "/usr/local/lib/systemd/catalog/",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering "/usr/lib/systemd/catalog/",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering NULL
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering};
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#define CATALOG_SIGNATURE (uint8_t[]) { 'R', 'H', 'H', 'H', 'K', 'S', 'L', 'P' }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poetteringtypedef struct CatalogHeader {
46e65dcc3a522b5e992e165b5e61d14254026859Lennart Poettering uint8_t signature[8]; /* "RHHHKSLP" */
46e65dcc3a522b5e992e165b5e61d14254026859Lennart Poettering le32_t compatible_flags;
46e65dcc3a522b5e992e165b5e61d14254026859Lennart Poettering le32_t incompatible_flags;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering le64_t header_size;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering le64_t n_items;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering le64_t catalog_item_size;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering} CatalogHeader;
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sieverstypedef struct CatalogItem {
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers sd_id128_t id;
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers char language[32];
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers le64_t offset;
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers} CatalogItem;
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sieversstatic void catalog_hash_func(const void *p, struct siphash *state) {
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers const CatalogItem *i = p;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering siphash24_compress(&i->id, sizeof(i->id), state);
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers siphash24_compress(i->language, strlen(i->language), state);
f18ca9dcdeda247e208f7143e834fd2fb2070d80Kay Sievers}
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poetteringstatic int catalog_compare_func(const void *a, const void *b) {
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landden const CatalogItem *i = a, *j = b;
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering unsigned k;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering for (k = 0; k < ELEMENTSOF(j->id.bytes); k++) {
599659860c770058f2eb04d578c521c16e0b1853Lennart Poettering if (i->id.bytes[k] < j->id.bytes[k])
599659860c770058f2eb04d578c521c16e0b1853Lennart Poettering return -1;
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering if (i->id.bytes[k] > j->id.bytes[k])
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering return 1;
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering }
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering
2311eb2ff0c3ff80ec3645b02c97170c9a565454Kay Sievers return strcmp(i->language, j->language);
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering}
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poetteringconst struct hash_ops catalog_hash_ops = {
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering .hash = catalog_hash_func,
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering .compare = catalog_compare_func
3e5e74d5b7f6fcbeff7b6e4e06abd931aab14c48Shawn Landden};
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landden
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landdenstatic int finish_item(
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landden Hashmap *h,
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering struct strbuf *sb,
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landden sd_id128_t id,
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landden const char *language,
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landden const char *payload) {
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering ssize_t offset;
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landden _cleanup_free_ CatalogItem *i = NULL;
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek int r;
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek assert(h);
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek assert(sb);
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek assert(payload);
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landden
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landden offset = strbuf_add_string(sb, payload, strlen(payload));
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landden if (offset < 0)
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landden return log_oom();
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers i = new0(CatalogItem, 1);
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers if (!i)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering return log_oom();
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek i->id = id;
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek if (language) {
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers assert(strlen(language) > 1 && strlen(language) < 32);
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landden strcpy(i->language, language);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek i->offset = htole64((uint64_t) offset);
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek
2667cc25896a15f82f9f1583e80d416beb1316e1Thomas Hindoe Paaboel Andersen r = hashmap_put(h, i, i);
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering if (r == -EEXIST) {
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering log_warning("Duplicate entry for " SD_ID128_FORMAT_STR ".%s, ignoring.",
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering SD_ID128_FORMAT_VAL(id), language ? language : "C");
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering return 0;
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering } else if (r < 0)
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering return r;
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering i = NULL;
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering return 0;
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering}
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek
b90930c73b1c82a3dc4d4f2603799993f042aaffLennart Poetteringint catalog_file_lang(const char* filename, char **lang) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering char *beg, *end, *_lang;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek end = endswith(filename, ".catalog");
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers if (!end)
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers return 0;
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering beg = end - 1;
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers while (beg > filename && *beg != '.' && *beg != '/' && end - beg < 32)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering beg --;
c264aeab4b0e7b69f469e12e78d4a48b3ed7a66eKay Sievers
c264aeab4b0e7b69f469e12e78d4a48b3ed7a66eKay Sievers if (*beg != '.' || end <= beg + 1)
c264aeab4b0e7b69f469e12e78d4a48b3ed7a66eKay Sievers return 0;
c264aeab4b0e7b69f469e12e78d4a48b3ed7a66eKay Sievers
07a062a79374406e8f6b5a1e2f80c80baf031567Jason St. John _lang = strndup(beg + 1, end - beg - 1);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (!_lang)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering return -ENOMEM;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek *lang = _lang;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers return 1;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers}
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sieversstatic int catalog_entry_lang(const char* filename, int line,
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers const char* t, const char* deflang, char **lang) {
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers size_t c;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers c = strlen(t);
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers if (c == 0) {
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers log_error("[%s:%u] Language too short.", filename, line);
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers return -EINVAL;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen if (c > 31) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering log_error("[%s:%u] language too long.", filename, line);
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers return -EINVAL;
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers }
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers if (deflang) {
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers if (streq(t, deflang)) {
adacb9575a09981fcf11279f2f661e3fc21e58ffLennart Poettering log_warning("[%s:%u] language specified unnecessarily",
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt filename, line);
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers return 0;
adacb9575a09981fcf11279f2f661e3fc21e58ffLennart Poettering } else
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering log_warning("[%s:%u] language differs from default for file",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering filename, line);
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers }
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers *lang = strdup(t);
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers if (!*lang)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering return -ENOMEM;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen return 0;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen}
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poetteringint catalog_import_file(Hashmap *h, struct strbuf *sb, const char *path) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering _cleanup_fclose_ FILE *f = NULL;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering _cleanup_free_ char *payload = NULL;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering unsigned n = 0;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering sd_id128_t id;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering _cleanup_free_ char *deflang = NULL, *lang = NULL;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering bool got_id = false, empty_line = true;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering int r;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering assert(h);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering assert(sb);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering assert(path);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering f = fopen(path, "re");
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen if (!f)
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen return log_error_errno(errno, "Failed to open file %s: %m", path);
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen r = catalog_file_lang(path, &deflang);
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen if (r < 0)
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen log_error_errno(r, "Failed to determine language for file %s: %m", path);
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen if (r == 1)
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen log_debug("File %s has language %s.", path, deflang);
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen for (;;) {
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen char line[LINE_MAX];
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen size_t a, b, c;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering char *t;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen if (!fgets(line, sizeof(line), f)) {
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen if (feof(f))
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen break;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering log_error_errno(errno, "Failed to read file %s: %m", path);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering return -errno;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering n++;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen truncate_nl(line);
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen if (line[0] == 0) {
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen empty_line = true;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen continue;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen }
e5609878d8802e2469c433be418bcbcf55fbe63bLennart Poettering
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen if (strchr(COMMENTS "\n", line[0]))
07a062a79374406e8f6b5a1e2f80c80baf031567Jason St. John continue;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen if (empty_line &&
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering strlen(line) >= 2+1+32 &&
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering line[0] == '-' &&
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen line[1] == '-' &&
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen line[2] == ' ' &&
e5609878d8802e2469c433be418bcbcf55fbe63bLennart Poettering (line[2+1+32] == ' ' || line[2+1+32] == '\0')) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering bool with_language;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering sd_id128_t jd;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering /* New entry */
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
e5609878d8802e2469c433be418bcbcf55fbe63bLennart Poettering with_language = line[2+1+32] != '\0';
e5609878d8802e2469c433be418bcbcf55fbe63bLennart Poettering line[2+1+32] = '\0';
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
e5609878d8802e2469c433be418bcbcf55fbe63bLennart Poettering if (sd_id128_from_string(line + 2 + 1, &jd) >= 0) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (got_id) {
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen r = finish_item(h, sb, id, lang ?: deflang, payload);
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen if (r < 0)
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen return r;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen lang = mfree(lang);
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen }
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen
e5609878d8802e2469c433be418bcbcf55fbe63bLennart Poettering if (with_language) {
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen t = strstrip(line + 2 + 1 + 32 + 1);
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen r = catalog_entry_lang(path, n, t, deflang, &lang);
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen if (r < 0)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering return r;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen got_id = true;
e5609878d8802e2469c433be418bcbcf55fbe63bLennart Poettering empty_line = false;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering id = jd;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (payload)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering payload[0] = '\0';
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering continue;
e5609878d8802e2469c433be418bcbcf55fbe63bLennart Poettering }
e5609878d8802e2469c433be418bcbcf55fbe63bLennart Poettering }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
e5609878d8802e2469c433be418bcbcf55fbe63bLennart Poettering /* Payload */
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (!got_id) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering log_error("[%s:%u] Got payload before ID.", path, n);
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen return -EINVAL;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen }
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen a = payload ? strlen(payload) : 0;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen b = strlen(line);
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen c = a + (empty_line ? 1 : 0) + b + 1 + 1;
e5609878d8802e2469c433be418bcbcf55fbe63bLennart Poettering t = realloc(payload, c);
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen if (!t)
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen return log_oom();
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen if (empty_line) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering t[a] = '\n';
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering memcpy(t + a + 1, line, b);
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen t[a+b+1] = '\n';
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering t[a+b+2] = 0;
7568345034f2890af745747783c5abfbf6eccf0fLennart Poettering } else {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering memcpy(t + a, line, b);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering t[a+b] = '\n';
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering t[a+b+1] = 0;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
7568345034f2890af745747783c5abfbf6eccf0fLennart Poettering
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt payload = t;
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt empty_line = false;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
7c2d80944afb4196f2eff614e8da1450dffcbeaaThomas Hindoe Paaboel Andersen if (got_id) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering r = finish_item(h, sb, id, lang ?: deflang, payload);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (r < 0)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering return r;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
601185b43da638b1c74153deae01dbd518680889Zbigniew Jędrzejewski-Szmek
7591abd48079edc1f2adbd922e4b83eb73abeabeLennart Poettering return 0;
7591abd48079edc1f2adbd922e4b83eb73abeabeLennart Poettering}
07a062a79374406e8f6b5a1e2f80c80baf031567Jason St. John
4f8f66cb4236783cd3cbee97fefc9aaa8469ac08Zbigniew Jędrzejewski-Szmekstatic int64_t write_catalog(const char *database, struct strbuf *sb,
4f8f66cb4236783cd3cbee97fefc9aaa8469ac08Zbigniew Jędrzejewski-Szmek CatalogItem *items, size_t n) {
4f8f66cb4236783cd3cbee97fefc9aaa8469ac08Zbigniew Jędrzejewski-Szmek CatalogHeader header;
4f8f66cb4236783cd3cbee97fefc9aaa8469ac08Zbigniew Jędrzejewski-Szmek _cleanup_fclose_ FILE *w = NULL;
4f8f66cb4236783cd3cbee97fefc9aaa8469ac08Zbigniew Jędrzejewski-Szmek int r;
4f8f66cb4236783cd3cbee97fefc9aaa8469ac08Zbigniew Jędrzejewski-Szmek _cleanup_free_ char *d, *p = NULL;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering size_t k;
4f8f66cb4236783cd3cbee97fefc9aaa8469ac08Zbigniew Jędrzejewski-Szmek
4f8f66cb4236783cd3cbee97fefc9aaa8469ac08Zbigniew Jędrzejewski-Szmek d = dirname_malloc(database);
07a062a79374406e8f6b5a1e2f80c80baf031567Jason St. John if (!d)
07a062a79374406e8f6b5a1e2f80c80baf031567Jason St. John return log_oom();
4f8f66cb4236783cd3cbee97fefc9aaa8469ac08Zbigniew Jędrzejewski-Szmek
3906ab4adf0aa7b952e39100262a11acd55cd79bRonny Chevalier r = mkdir_p(d, 0775);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (r < 0)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering return log_error_errno(r, "Recursive mkdir %s: %m", d);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering r = fopen_temporary(database, &w, &p);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (r < 0)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering return log_error_errno(r, "Failed to open database for writing: %s: %m",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering database);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
c978343015c787713651dff571acb5207367f5f2Lennart Poettering zero(header);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering memcpy(header.signature, CATALOG_SIGNATURE, sizeof(header.signature));
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering header.header_size = htole64(ALIGN_TO(sizeof(CatalogHeader), 8));
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering header.catalog_item_size = htole64(sizeof(CatalogItem));
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering header.n_items = htole64(n);
c978343015c787713651dff571acb5207367f5f2Lennart Poettering
c978343015c787713651dff571acb5207367f5f2Lennart Poettering r = -EIO;
c978343015c787713651dff571acb5207367f5f2Lennart Poettering
c978343015c787713651dff571acb5207367f5f2Lennart Poettering k = fwrite(&header, 1, sizeof(header), w);
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen if (k != sizeof(header)) {
c978343015c787713651dff571acb5207367f5f2Lennart Poettering log_error("%s: failed to write header.", p);
c978343015c787713651dff571acb5207367f5f2Lennart Poettering goto error;
eb9da376d76b48585b3b63b4f91903b54f7abd36Lennart Poettering }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering k = fwrite(items, 1, n * sizeof(CatalogItem), w);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (k != n * sizeof(CatalogItem)) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering log_error("%s: failed to write database.", p);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering goto error;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
601185b43da638b1c74153deae01dbd518680889Zbigniew Jędrzejewski-Szmek k = fwrite(sb->buf, 1, sb->len, w);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (k != sb->len) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering log_error("%s: failed to write strings.", p);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering goto error;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
601185b43da638b1c74153deae01dbd518680889Zbigniew Jędrzejewski-Szmek
601185b43da638b1c74153deae01dbd518680889Zbigniew Jędrzejewski-Szmek r = fflush_and_check(w);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (r < 0) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering log_error_errno(r, "%s: failed to write database: %m", p);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering goto error;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering fchmod(fileno(w), 0644);
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen if (rename(p, database) < 0) {
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen r = log_error_errno(errno, "rename (%s -> %s) failed: %m", p, database);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering goto error;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen
de33fc625725d199629ed074d6278504deb23debLennart Poettering return ftello(w);
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poetteringerror:
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering (void) unlink(p);
546158bc6f46f8004cc11e81d19d223e0da56730Jan Janssen return r;
546158bc6f46f8004cc11e81d19d223e0da56730Jan Janssen}
546158bc6f46f8004cc11e81d19d223e0da56730Jan Janssen
546158bc6f46f8004cc11e81d19d223e0da56730Jan Janssenint catalog_update(const char* database, const char* root, const char* const* dirs) {
c978343015c787713651dff571acb5207367f5f2Lennart Poettering _cleanup_strv_free_ char **files = NULL;
c978343015c787713651dff571acb5207367f5f2Lennart Poettering char **f;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering struct strbuf *sb = NULL;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering _cleanup_hashmap_free_free_ Hashmap *h = NULL;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering _cleanup_free_ CatalogItem *items = NULL;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering CatalogItem *i;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering Iterator j;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering unsigned n;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering int r;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering int64_t sz;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering h = hashmap_new(&catalog_hash_ops);
eb9da376d76b48585b3b63b4f91903b54f7abd36Lennart Poettering sb = strbuf_new();
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (!h || !sb) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering r = log_oom();
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering goto finish;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering r = conf_files_list_strv(&files, ".catalog", root, dirs);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (r < 0) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering log_error_errno(r, "Failed to get catalog files: %m");
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering goto finish;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering STRV_FOREACH(f, files) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering log_debug("Reading file '%s'", *f);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering r = catalog_import_file(h, sb, *f);
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen if (r < 0) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering log_error_errno(r, "Failed to import file '%s': %m", *f);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering goto finish;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (hashmap_size(h) <= 0) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering log_info("No items in catalog.");
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering goto finish;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering } else
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering log_debug("Found %u items in catalog.", hashmap_size(h));
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering strbuf_complete(sb);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering items = new(CatalogItem, hashmap_size(h));
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (!items) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering r = log_oom();
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering goto finish;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering n = 0;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering HASHMAP_FOREACH(i, h, j) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering log_debug("Found " SD_ID128_FORMAT_STR ", language %s",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering SD_ID128_FORMAT_VAL(i->id),
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering isempty(i->language) ? "C" : i->language);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering items[n++] = *i;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering assert(n == hashmap_size(h));
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering qsort_safe(items, n, sizeof(CatalogItem), catalog_compare_func);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering sz = write_catalog(database, sb, items, n);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (sz < 0)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering r = log_error_errno(sz, "Failed to write %s: %m", database);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering else {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering r = 0;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering log_debug("%s: wrote %u items, with %zu bytes of strings, %"PRIi64" total size.",
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering database, n, sb->len, sz);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poetteringfinish:
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering strbuf_cleanup(sb);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering return r;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering}
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poetteringstatic int open_mmap(const char *database, int *_fd, struct stat *_st, void **_p) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering const CatalogHeader *h;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering int fd;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering void *p;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering struct stat st;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering assert(_fd);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering assert(_st);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering assert(_p);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering fd = open(database, O_RDONLY|O_CLOEXEC);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (fd < 0)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering return -errno;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (fstat(fd, &st) < 0) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering safe_close(fd);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering return -errno;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (st.st_size < (off_t) sizeof(CatalogHeader)) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering safe_close(fd);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering return -EINVAL;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering p = mmap(NULL, PAGE_ALIGN(st.st_size), PROT_READ, MAP_SHARED, fd, 0);
249968612f16a71df909d6e73785c18a9ff36a65Lennart Poettering if (p == MAP_FAILED) {
84f6181c2ac99a0514ca5e0c8fc8c8e284caf789Lennart Poettering safe_close(fd);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering return -errno;
a9cdc94f7ff40f22a3cf9472f612a80730a1b010Dave Reisner }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering h = p;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (memcmp(h->signature, CATALOG_SIGNATURE, sizeof(h->signature)) != 0 ||
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering le64toh(h->header_size) < sizeof(CatalogHeader) ||
84f6181c2ac99a0514ca5e0c8fc8c8e284caf789Lennart Poettering le64toh(h->catalog_item_size) < sizeof(CatalogItem) ||
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering h->incompatible_flags != 0 ||
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering le64toh(h->n_items) <= 0 ||
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen st.st_size < (off_t) (le64toh(h->header_size) + le64toh(h->catalog_item_size) * le64toh(h->n_items))) {
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen safe_close(fd);
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt munmap(p, st.st_size);
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen return -EBADMSG;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering }
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen *_fd = fd;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering *_st = st;
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen *_p = p;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering return 0;
84f6181c2ac99a0514ca5e0c8fc8c8e284caf789Lennart Poettering}
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
static const char *find_id(void *p, sd_id128_t id) {
CatalogItem key, *f = NULL;
const CatalogHeader *h = p;
const char *loc;
zero(key);
key.id = id;
loc = setlocale(LC_MESSAGES, NULL);
if (loc && loc[0] && !streq(loc, "C") && !streq(loc, "POSIX")) {
strncpy(key.language, loc, sizeof(key.language));
key.language[strcspn(key.language, ".@")] = 0;
f = bsearch(&key, (const uint8_t*) p + le64toh(h->header_size), le64toh(h->n_items), le64toh(h->catalog_item_size), catalog_compare_func);
if (!f) {
char *e;
e = strchr(key.language, '_');
if (e) {
*e = 0;
f = bsearch(&key, (const uint8_t*) p + le64toh(h->header_size), le64toh(h->n_items), le64toh(h->catalog_item_size), catalog_compare_func);
}
}
}
if (!f) {
zero(key.language);
f = bsearch(&key, (const uint8_t*) p + le64toh(h->header_size), le64toh(h->n_items), le64toh(h->catalog_item_size), catalog_compare_func);
}
if (!f)
return NULL;
return (const char*) p +
le64toh(h->header_size) +
le64toh(h->n_items) * le64toh(h->catalog_item_size) +
le64toh(f->offset);
}
int catalog_get(const char* database, sd_id128_t id, char **_text) {
_cleanup_close_ int fd = -1;
void *p = NULL;
struct stat st = {};
char *text = NULL;
int r;
const char *s;
assert(_text);
r = open_mmap(database, &fd, &st, &p);
if (r < 0)
return r;
s = find_id(p, id);
if (!s) {
r = -ENOENT;
goto finish;
}
text = strdup(s);
if (!text) {
r = -ENOMEM;
goto finish;
}
*_text = text;
r = 0;
finish:
if (p)
munmap(p, st.st_size);
return r;
}
static char *find_header(const char *s, const char *header) {
for (;;) {
const char *v, *e;
v = startswith(s, header);
if (v) {
v += strspn(v, WHITESPACE);
return strndup(v, strcspn(v, NEWLINE));
}
/* End of text */
e = strchr(s, '\n');
if (!e)
return NULL;
/* End of header */
if (e == s)
return NULL;
s = e + 1;
}
}
static void dump_catalog_entry(FILE *f, sd_id128_t id, const char *s, bool oneline) {
if (oneline) {
_cleanup_free_ char *subject = NULL, *defined_by = NULL;
subject = find_header(s, "Subject:");
defined_by = find_header(s, "Defined-By:");
fprintf(f, SD_ID128_FORMAT_STR " %s: %s\n",
SD_ID128_FORMAT_VAL(id),
strna(defined_by), strna(subject));
} else
fprintf(f, "-- " SD_ID128_FORMAT_STR "\n%s\n",
SD_ID128_FORMAT_VAL(id), s);
}
int catalog_list(FILE *f, const char *database, bool oneline) {
_cleanup_close_ int fd = -1;
void *p = NULL;
struct stat st;
const CatalogHeader *h;
const CatalogItem *items;
int r;
unsigned n;
sd_id128_t last_id;
bool last_id_set = false;
r = open_mmap(database, &fd, &st, &p);
if (r < 0)
return r;
h = p;
items = (const CatalogItem*) ((const uint8_t*) p + le64toh(h->header_size));
for (n = 0; n < le64toh(h->n_items); n++) {
const char *s;
if (last_id_set && sd_id128_equal(last_id, items[n].id))
continue;
assert_se(s = find_id(p, items[n].id));
dump_catalog_entry(f, items[n].id, s, oneline);
last_id_set = true;
last_id = items[n].id;
}
munmap(p, st.st_size);
return 0;
}
int catalog_list_items(FILE *f, const char *database, bool oneline, char **items) {
char **item;
int r = 0;
STRV_FOREACH(item, items) {
sd_id128_t id;
int k;
_cleanup_free_ char *msg = NULL;
k = sd_id128_from_string(*item, &id);
if (k < 0) {
log_error_errno(k, "Failed to parse id128 '%s': %m", *item);
if (r == 0)
r = k;
continue;
}
k = catalog_get(database, id, &msg);
if (k < 0) {
log_full_errno(k == -ENOENT ? LOG_NOTICE : LOG_ERR, k,
"Failed to retrieve catalog entry for '%s': %m", *item);
if (r == 0)
r = k;
continue;
}
dump_catalog_entry(f, id, msg, oneline);
}
return r;
}