diff --git a/inc/ini/ini.h b/inc/ini/ini.h index 43a6afdff5dfd0239ca46b333c55ddb5f08a0afb..449d2dce0d01f9d0dc8c60f89ee2c6fece17d9ce 100644 --- a/inc/ini/ini.h +++ b/inc/ini/ini.h @@ -1,15 +1,6 @@ /* inih -- simple .INI file parser - -SPDX-License-Identifier: BSD-3-Clause - -Copyright (C) 2009-2020, Ben Hoyt - -inih is released under the New BSD license (see LICENSE.txt). Go to the project -home page for more info: - -https://github.com/benhoyt/inih - -*/ + SPDX-License-Identifier: BSD-3-Clause + Copyright (C) 2009-2020, Ben Hoyt */ #ifndef __INI_H__ #define __INI_H__ diff --git a/init.sql b/init.sql index 2b2f9d39d01daab06a4cec8b3dcaf0a22e7e5d6c..c835e98a26731a1f1c4d884528c0cdbc87c820dd 100644 --- a/init.sql +++ b/init.sql @@ -31,7 +31,7 @@ CREATE TABLE IF NOT EXISTS kara_type , name TEXT NOT NULL ); -INSERT INTO kara_type (id, name) VALUES +INSERT OR REPLACE INTO kara_type (id, name) VALUES (1, 'vo'), (2, 'va'), (3, 'amv'), (4, 'cdg'), (5, 'autres'), ( 6, 'vocaloid'); CREATE TABLE IF NOT EXISTS kara_category @@ -39,7 +39,7 @@ CREATE TABLE IF NOT EXISTS kara_category , name TEXT NOT NULL ); -INSERT INTO kara_category (id, name) VALUES +INSERT OR REPLACE INTO kara_category (id, name) VALUES (1, 'ED/d*'), (2, 'OP/d*'), (3, 'AMV'), (4, 'IS'), (5, 'VOCA'), (6, 'LIVE'), (7, 'CDG'), (8, 'PV'), (9, 'MV'); @@ -48,7 +48,7 @@ CREATE TABLE IF NOT EXISTS language , name TEXT NOT NULL ); -INSERT INTO language (id, name) VALUES +INSERT OR REPLACE INTO language (id, name) VALUES (1, 'jp'), (2, 'fr'), (3, 'en'), (4, 'ru'), (5, 'sp'), (6, 'it'), (7, 'ch'), (8, 'latin'), (9, 'multi'), (10, 'undefined'); @@ -91,7 +91,7 @@ CREATE TABLE IF NOT EXISTS users , PRIMARY KEY (username, password) ) WITHOUT ROWID; -INSERT INTO users (username, password) VALUES ('sakura', 'hashire'); +INSERT INTO OR REPLACE users (username, password) VALUES ('sakura', 'hashire'); -- The stickers table @@ -129,7 +129,7 @@ CREATE TABLE IF NOT EXISTS misc , last_update INTEGER ); -INSERT INTO misc (id) VALUES (42); +INSERT OR REPLACE INTO misc (id) VALUES (42); -- A simple view to select things in the queue, where the order matters and diff --git a/meson.build b/meson.build index d2a9b13198dc8a6f0fe4b556dec2eaa97ccba990..99f26836c9a37a3050582269825d92f6d20a9134 100644 --- a/meson.build +++ b/meson.build @@ -74,7 +74,7 @@ srv = executable( meson.project_name() + 'd' # Admin executable metadata = executable( 'lktadm' - , files('src/main/lktadm.c') + , files('src/main/lktadm.c', 'src/cmd.c') , include_directories : includes , dependencies : bin_deps ) diff --git a/src/ini/ini.c b/src/ini/ini.c index 3a480689220d1811f80543b85f071c987f406ece..25e3870318e7efb1201ff8e3831067e1777f7e1e 100644 --- a/src/ini/ini.c +++ b/src/ini/ini.c @@ -1,15 +1,6 @@ /* inih -- simple .INI file parser - -SPDX-License-Identifier: BSD-3-Clause - -Copyright (C) 2009-2020, Ben Hoyt - -inih is released under the New BSD license (see LICENSE.txt). Go to the project -home page for more info: - -https://github.com/benhoyt/inih - -*/ + SPDX-License-Identifier: BSD-3-Clause + Copyright (C) 2009-2020, Ben Hoyt */ #include <stdio.h> #include <ctype.h> diff --git a/src/main/lktadm.c b/src/main/lktadm.c index 17ea343bf50c1a216ede55c2e7f4987518e96a3c..cb4a68bd24f944484547066f4a6957547ff0f40f 100644 --- a/src/main/lktadm.c +++ b/src/main/lktadm.c @@ -1,255 +1,297 @@ #define _POSIX_C_SOURCE 200809L #define _DEFAULT_SOURCE +#include <lektor/macro.h> +#include <lektor/defines.h> +#include <lektor/cmd.h> #include <lektor/config.h> #include <lektor/mkv.h> #include <lektor/database.h> #include <lektor/repo.h> #include <lektor/utils.h> + #include <stdio.h> -#include <string.h> -#include <strings.h> -#include <errno.h> -#include <stdbool.h> #include <stdlib.h> -#include <regex.h> #include <unistd.h> -#include <pwd.h> +#include <errno.h> #include <fcntl.h> -#include <linux/limits.h> -#include <sys/types.h> +#include <dirent.h> +#include <string.h> #include <sys/wait.h> -#include <sys/stat.h> + +static noreturn inline void +fail(const char *format, ...) +{ + va_list ap; + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + write(2, "\n", 1); + exit(EXIT_FAILURE); +} /* ----------------- * * The main function * * ----------------- */ -int -main(int argc, char *argv[]) -{ - int i, num; - sqlite3 *db; - bool ret = true; - char kara_dir[PATH_MAX], *db_path, mkvpropedit[PATH_MAX], buf[100]; - struct kara_metadata data; - struct lkt_repo repo; - - if (argc < 2) - goto print_help; - - /* Read the config file. */ - - if (!database_new(&db)) { - fprintf(stderr, " ! Failed to initialize memory database\n"); - return 1; - } - - if (config_open(db)) { - fprintf(stderr, " ! could not load configuration\n"); - return 1; - } +static sqlite3 *db = NULL; +static char kara_dir[PATH_MAX], db_path[PATH_MAX], mkvpropedit[PATH_MAX], sqlite3_bin[PATH_MAX], + init_script[PATH_MAX], buf[100]; - /* In any case, we won't free the mkvpropedit, this is not a daemon. */ - if (!database_config_get_text(db, "externals", "mkvpropedit", mkvpropedit, PATH_MAX)) { - fprintf(stderr, " ! could not get the 'mkvpropedit property from the externals section\n'"); - return 1; - } +void +open_db(void) +{ + if (!database_new(&db)) + fail("Failed to init memory db"); - /* Arguments handle. */ + if (config_open(db)) + fail("Could not load configuration"); - if (strcmp(argv[1], "--init") == 0) { - if (!database_config_get_text(db, "database", "kara_dir", kara_dir, PATH_MAX)) { - fprintf(stderr, " ! failed to get the kara directory\n"); - return 10; - } + if (!database_config_get_text(db, "externals", "mkvpropedit", mkvpropedit, PATH_MAX)) + fail("Not found externals->mkvpropedit"); - return metadata_set_directory(kara_dir, mkvpropedit); - } + if (!database_config_get_text(db, "externals", "sqlite3", sqlite3_bin, PATH_MAX)) + fail("Not found externals->sqlite3"); - else if (strcmp(argv[1], "--populate-all") == 0) { - db_path = (char *) calloc(PATH_MAX, sizeof(char)); + if (!database_config_get_text(db, "database", "db_path", db_path, PATH_MAX)) + fail("Not found database->db_path"); - if (!database_config_get_text(db, "database", "db_path", db_path, PATH_MAX)) { - fprintf(stderr, " ! Failed to get database path\n"); - goto end_populate; - } + if (!database_config_get_text(db, "database", "kara_dir", kara_dir, PATH_MAX)) + fail("Not found database->kara_dir"); - if (!database_config_get_text(db, "database", "kara_dir", kara_dir, PATH_MAX)) { - fprintf(stderr, " ! Failed to get kara directory\n"); - goto end_populate; - } + if (!database_config_get_text(db, "database", "init_script", init_script, PATH_MAX)) + fail("Not found database->init_script"); +} - if (!database_open(db, db_path)) { - fprintf(stderr, " ! lkt_listen: Failed to open database\n"); - return 1; - } +noreturn void +help(void) +{ + printf("Usage for lktadm:\n\n" + " --init: init metadata for all the database according to the root of\n" + " the root of the base\n\n" + " --file <file.mkv, ...>: set automatically metadata for the file file.mkv\n\n" + " --prompt-file <file.mkv, ...>: prompt metadata to put for the file file.mkv\n\n" + " --populate-all: populate the database with whate is found in the fs\n\n" + " --cat <file.mkv, ...>: print the metadata of files\n\n" + " --get-id <id>: print metadata from kurisu with an id\n\n" + " --down-id <id> <path>: download a kara from kurisu to a path\n\n" + " --default-conf: output to stdout the default configuration file\n\n"); + exit(EXIT_SUCCESS); +} - database_update(db, kara_dir); - sqlite3_close(db); +noreturn void +conf__(struct lkt_cmd_args *args) +{ + (void) args; + fprintf(stdout, "%s\n", lkt_default_config_file); + fprintf(stderr, "You may redirect this output to ~/.config/lektor/lektor.ini\n"); + exit(EXIT_SUCCESS); +} - ret = 0; -end_populate: - free(db_path); - return ret; +noreturn void +cat__(struct lkt_cmd_args *args) +{ + int i; + struct kara_metadata data; + for (i = 0; i < args->argc; ++i) { + if (kara_metadata_read(&data, args->argv[i])) + fail("Failed to read metadata of file %s", args->argv[i]); + printf("Kara path: %s\n" + " Song source: %s\n" + " Song title: %s\n" + " Category: %s\n" + " Type: %s (number %d)\n" + " Author: %s\n" + " Language: %s\n", + args->argv[i], data.source_name, data.song_name, data.category, + data.song_type, data.song_number, data.author_name, data.language); } + exit(EXIT_SUCCESS); +} - else if (strcmp(argv[1], "--file") == 0) { - ret = 0; - for (i = 2; i < argc; ++i) - ret |= metadata_set_file(argv[i], mkvpropedit); - return ret; - } +noreturn void +init_metadata__(struct lkt_cmd_args *args) +{ + (void) args; + open_db(); + metadata_set_directory(kara_dir, mkvpropedit); + exit(EXIT_SUCCESS); +} - else if (strcmp(argv[1], "--prompt-file") == 0) { - ret = 0; - for (i = 2; i < argc; ++i) { - fprintf(stdout, "Asking for file '%s':\n", argv[i]); +noreturn void +init_populate__(struct lkt_cmd_args *args) +{ + (void) args; + open_db(); + database_update(db, kara_dir); + sqlite3_close(db); + exit(EXIT_SUCCESS); +} - if (get_stdin_line(" song_name (TITLE): ", data.song_name, LEKTOR_TAG_MAX)) - goto input_error; +noreturn void +init_file__(struct lkt_cmd_args *args) +{ + int i; + for (i = 0; i < args->argc; ++i) + metadata_set_file((char *) args->argv[i], mkvpropedit); + exit(EXIT_SUCCESS); +} - if (get_stdin_line(" source_name (NAME): ", data.source_name, LEKTOR_TAG_MAX)) - goto input_error; +noreturn void +init_file_prompt__(struct lkt_cmd_args *args) +{ + int i, num; + struct kara_metadata data; + for (i = 0; i < args->argc; ++i) { + fprintf(stdout, "Asking for file '%s':\n", args->argv[i]); - if (get_stdin_line(" category (cdg, vo, ...): ", data.category, LEKTOR_TAG_MAX)) - goto input_error; + if (get_stdin_line(" song_name (TITLE): ", data.song_name, LEKTOR_TAG_MAX)) + fail("Input error"); - if (get_stdin_line(" type (OP, AMV, ...): ", data.song_type, LEKTOR_TAG_MAX)) - goto input_error; + if (get_stdin_line(" source_name (NAME): ", data.source_name, LEKTOR_TAG_MAX)) + fail("Input error"); - if (get_stdin_line(" language (jp, fr, undefined, ...): ", data.language, LEKTOR_TAG_MAX)) - goto input_error; + if (get_stdin_line(" category (cdg, vo, ...): ", data.category, LEKTOR_TAG_MAX)) + fail("Input error"); - if (get_stdin_line(" author_name (Your peudal): ", data.author_name, LEKTOR_TAG_MAX)) - goto input_error; + if (get_stdin_line(" type (OP, AMV, ...): ", data.song_type, LEKTOR_TAG_MAX)) + fail("Input error"); - if (!get_stdin_line(" type's number(1, 2, ...): ", buf, 100)) - data.song_number = ((num = atoi(buf)) <= 0) ? 1 : num; + if (get_stdin_line(" language (jp, fr, undefined, ...): ", data.language, LEKTOR_TAG_MAX)) + fail("Input error"); - else - goto input_error; + if (get_stdin_line(" author_name (Your peudal): ", data.author_name, LEKTOR_TAG_MAX)) + fail("Input error"); - ret |= kara_metadata_write(&data, argv[i], mkvpropedit); - } + if (!get_stdin_line(" type's number(1, 2, ...): ", buf, 100)) + data.song_number = ((num = atoi(buf)) <= 0) ? 1 : num; + else + fail("Input error"); + kara_metadata_write(&data, args->argv[i], mkvpropedit); fprintf(stdout, "You may name this kara with the following name: '%s - %s%d - %s'\n", data.source_name, data.song_type, data.song_number, data.song_name); - - return ret; -input_error: - fprintf(stderr, "\n ! error occured while reading input\n"); - return 1; } + exit(EXIT_SUCCESS); +} - else if (strcmp(argv[1], "--cat") == 0) { - for (i = 2; i < argc; ++i) { - if (kara_metadata_read(&data, argv[2])) { - printf("Failed to read metadata of file %s\n", argv[2]); - return 1; - } - - printf("Kara path: %s\n" - " Song source: %s\n" - " Song title: %s\n" - " Category: %s\n" - " Type: %s (number %d)\n" - " Author: %s\n" - " Language: %s\n", - argv[i], data.source_name, data.song_name, data.category, - data.song_type, data.song_number, data.author_name, - data.language - ); - } - return 0; - } +noreturn void +get__(struct lkt_cmd_args *args) +{ + struct kara_metadata data; + struct lkt_repo repo; - else if (strcmp(argv[1], "--get-id") == 0) { + if (args->argc != 1) + fail("Invalid argument"); - if (argc != 3) { - fprintf(stderr, " ! invalid argument, just need one id\n"); - return 1; - } + int i = atoi(args->argv[0]); - i = atoi(argv[2]); + if (repo_new(&repo, "kurisu", "https://kurisu.iiens.net")) + fail("Cound not create repo"); - if (repo_new(&repo, "kurisu", "https://kurisu.iiens.net")) { - fprintf(stderr, " ! could not create the repo\n"); - return 60; - } + if (repo_get_id(&repo, i, &data)) + fail("Cound not download json for kara %d", i); - if (repo_get_id(&repo, i, &data)) { - fprintf(stderr, " ! could not download json for kara %d\n", i); - return 61; - } + printf("Kara id: %d\n" + " Song source: %s\n" + " Song title: %s\n" + " Category: %s\n" + " Type: %s (number %d)\n" + " Author: %s\n" + " Language: %s\n", + i, data.source_name, data.song_name, data.category, + data.song_type, data.song_number, data.author_name, + data.language); + exit(EXIT_SUCCESS); +} - printf("Kara id: %d\n" - " Song source: %s\n" - " Song title: %s\n" - " Category: %s\n" - " Type: %s (number %d)\n" - " Author: %s\n" - " Language: %s\n", - i, data.source_name, data.song_name, data.category, - data.song_type, data.song_number, data.author_name, - data.language - ); +noreturn void +init_database__(struct lkt_cmd_args *args) +{ + (void) args; + pid_t pid; + int wstatus, status, fd; + char *sqlite_args[] = { sqlite3_bin, db_path }; - return 0; - } + if ((pid = fork()) == 0) { + if ((fd = open(init_script, O_RDONLY)) < 0) + fail("Can't open %s in O_RDONLY", init_script); - else if (strcmp(argv[1], "--down-id") == 0) { + if (dup2(fd, 0) < 0) + fail("Failed to duplicate %s to stdin", init_script); - if (argc != 4) - goto print_help; + execv(sqlite3_bin, sqlite_args); + fail("Failed to execute %s", sqlite3_bin); + } - i = atoi(argv[2]); + else if (pid < 0) + fail("Failed to fork: %s", strerror(errno)); - if (repo_new(&repo, "kurisu", "https://kurisu.iiens.net")) { - fprintf(stderr, " ! could not create the repo\n"); - return 60; - } + else { + do + if (waitpid(pid, &wstatus, WUNTRACED | WCONTINUED) == -1) + fail("Failed to wait children: %s\n", strerror(errno)); + while (!WIFEXITED(wstatus) && !WIFSIGNALED(wstatus)); - if (repo_download_id_sync(&repo, NULL, i, argv[3], &data)) { - fprintf(stderr, " ! could not download json for kara %d\n", i); - return 61; - } + if ((status = WEXITSTATUS(wstatus))) + fail("Children failed with status %d", status); + } - printf("Kara %d at %s\n" - " Song source: %s\n" - " Song title: %s\n" - " Category: %s\n" - " Type: %s (number %d)\n" - " Author: %s\n" - " Language: %s\n", - i, argv[3], data.source_name, data.song_name, data.category, - data.song_type, data.song_number, data.author_name, data.language - ); + exit(EXIT_SUCCESS); +} +noreturn void +download__(struct lkt_cmd_args *args) +{ + if (args->argc != 2) + fail("Invalud argument"); - return 0; - } + struct lkt_repo repo; + struct kara_metadata data; + int i = atoi(args->argv[0]); + + if (repo_new(&repo, "kurisu", "https://kurisu.iiens.net")) + fail("Could not create the repo"); + + if (repo_download_id_sync(&repo, NULL, i, args->argv[1], &data)) + fail("Cound not download json for kara %d", i); + + printf("Kara %d at %s\n" + " Song source: %s\n" + " Song title: %s\n" + " Category: %s\n" + " Type: %s (number %d)\n" + " Author: %s\n" + " Language: %s\n", + i, args->argv[1], data.source_name, data.song_name, data.category, + data.song_type, data.song_number, data.author_name, data.language); + exit(EXIT_SUCCESS); +} - else if (strcmp(argv[1], "--default-conf") == 0) { - fprintf(stdout, "%s\n", lkt_default_config_file); - fprintf(stderr, "You may redirect this output to ~/.config/lektor/lektor.ini\n"); - return 0; - } +static struct lkt_cmd_opt options_init[] = { + { .name = "database", .call = init_database__ }, + { .name = "populate", .call = init_populate__ }, + { .name = "metadata", .call = init_metadata__ }, + LKT_OPT_NULL, +}; - /* The help. */ +noreturn void +init__(struct lkt_cmd_args *args) +{ + lkt_cmd_parse(options_init, args->argc, args->argv, help); +} -print_help: - printf("Usage for %s:\n\n" - " --init: init metadata for all the database according to the root of\n" - " the root of the base\n\n" - " --file <file.mkv, ...>: set automatically metadata for the file file.mkv\n\n" - " --prompt-file <file.mkv, ...>: prompt metadata to put for the file file.mkv\n\n" - " --populate-all: populate the database with whate is found in the fs\n\n" - " --cat <file.mkv, ...>: print the metadata of files\n\n" - " --get-id <id>: print metadata from kurisu with an id\n\n" - " --down-id <id> <path>: download a kara from kurisu to a path\n\n" - " --default-conf: output to stdout the default configuration file\n\n", - argv[0]); +static struct lkt_cmd_opt options[] = { + { .name = "init", .call = init__ }, + { .name = "get", .call = get__, }, + { .name = "download", .call = download__ }, + { .name = "cat", .call = cat__, }, + { .name = "conf", .call = conf__, }, + LKT_OPT_NULL, +}; - return 0; +int +main(int argc, const char **argv) +{ + lkt_cmd_parse(options, argc, argv, help); } diff --git a/src/net/listen.c b/src/net/listen.c index dbb96795d8dd8e54580f4dbc82f0e87539d21590..5727ada3116dc8c76f4e6486c59c81ca3a27523b 100644 --- a/src/net/listen.c +++ b/src/net/listen.c @@ -361,7 +361,6 @@ handle_incoming_data(struct lkt_state *srv, size_t i) for (;;) { /* Recieve some data. */ -recv: n = recv(srv->fds[i].fd, cli->buffer_in + cli->buffer_in_len, LKT_MESSAGE_MAX - cli->buffer_in_len, 0); if (n < 0) { @@ -378,7 +377,7 @@ recv: for (;;) { size_t line_len = strcspn(buf, "\n"); if (line_len >= cli->buffer_in_len) - goto recv; + break; buf[line_len] = 0; struct lkt_command cmd = lkt_command_parse(buf);