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);