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/main/lktadm.c b/src/main/lktadm.c
index 17ea343bf50c1a216ede55c2e7f4987518e96a3c..2cc95f682dfb11b68bf64a4378f62c53996262bb 100644
--- a/src/main/lktadm.c
+++ b/src/main/lktadm.c
@@ -1,255 +1,266 @@
 #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 <fcntl.h>
-#include <linux/limits.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <sys/stat.h>
 
 /* ----------------- *
  * 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. */
+static sqlite3 *db = NULL;
+static char kara_dir[PATH_MAX], db_path[PATH_MAX], mkvpropedit[PATH_MAX], buf[100];
 
+void
+open_db(void)
+{
     if (!database_new(&db)) {
         fprintf(stderr, " ! Failed to initialize memory database\n");
-        return 1;
+        exit(EXIT_FAILURE);
     }
 
     if (config_open(db)) {
         fprintf(stderr, " ! could not load configuration\n");
-        return 1;
+        exit(EXIT_FAILURE);
     }
 
-    /* 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;
+        exit(EXIT_FAILURE);
     }
 
-    /* Arguments handle. */
-
-    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, "database", "db_path", db_path, PATH_MAX)) {
+        fprintf(stderr, " ! Failed to get database path\n");
+        exit(EXIT_FAILURE);
+    }
 
-        return metadata_set_directory(kara_dir, mkvpropedit);
+    if (!database_config_get_text(db, "database", "kara_dir", kara_dir, PATH_MAX)) {
+        fprintf(stderr, " ! Failed to get kara directory\n");
+        exit(EXIT_FAILURE);
     }
 
-    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)) {
-            fprintf(stderr, " ! Failed to get database path\n");
-            goto end_populate;
-        }
+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);
+}
 
-        if (!database_config_get_text(db, "database", "kara_dir", kara_dir, PATH_MAX)) {
-            fprintf(stderr, " ! Failed to get kara directory\n");
-            goto end_populate;
-        }
+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);
+}
 
-        if (!database_open(db, db_path)) {
-            fprintf(stderr, " ! lkt_listen: Failed to open database\n");
-            return 1;
+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])) {
+            printf("Failed to read metadata of file %s\n", args->argv[i]);
+            exit(EXIT_FAILURE);
         }
-
-        database_update(db, kara_dir);
-        sqlite3_close(db);
-
-        ret = 0;
-end_populate:
-        free(db_path);
-        return ret;
+        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();
+    if (!database_config_get_text(db, "database", "kara_dir", kara_dir, PATH_MAX)) {
+        fprintf(stderr, " ! failed to get the kara directory\n");
+        exit(EXIT_FAILURE);
     }
+    metadata_set_directory(kara_dir, mkvpropedit);
+    exit(EXIT_SUCCESS);
+}
+
+noreturn void
+init_populate__(struct lkt_cmd_args *args)
+{
+    (void) args;
+    open_db();
+    database_update(db, kara_dir);
+    sqlite3_close(db);
+    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_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(" song_name (TITLE): ", data.song_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(" source_name (NAME): ", data.source_name, LEKTOR_TAG_MAX))
-                goto input_error;
+        if (get_stdin_line(" song_name (TITLE): ", data.song_name, LEKTOR_TAG_MAX))
+            exit(EXIT_FAILURE);
 
-            if (get_stdin_line(" category (cdg, vo, ...): ", data.category, LEKTOR_TAG_MAX))
-                goto input_error;
+        if (get_stdin_line(" source_name (NAME): ", data.source_name, LEKTOR_TAG_MAX))
+            exit(EXIT_FAILURE);
 
-            if (get_stdin_line(" type (OP, AMV, ...): ", data.song_type, LEKTOR_TAG_MAX))
-                goto input_error;
+        if (get_stdin_line(" category (cdg, vo, ...): ", data.category, LEKTOR_TAG_MAX))
+            exit(EXIT_FAILURE);
 
-            if (get_stdin_line(" language (jp, fr, undefined, ...): ", data.language, LEKTOR_TAG_MAX))
-                goto input_error;
+        if (get_stdin_line(" type (OP, AMV, ...): ", data.song_type, LEKTOR_TAG_MAX))
+            exit(EXIT_FAILURE);
 
-            if (get_stdin_line(" author_name (Your peudal): ", data.author_name, LEKTOR_TAG_MAX))
-                goto input_error;
+        if (get_stdin_line(" language (jp, fr, undefined, ...): ", data.language, LEKTOR_TAG_MAX))
+            exit(EXIT_FAILURE);
 
-            if (!get_stdin_line(" type's number(1, 2, ...): ", buf, 100))
-                data.song_number = ((num = atoi(buf)) <= 0) ? 1 : num;
+        if (get_stdin_line(" author_name (Your peudal): ", data.author_name, LEKTOR_TAG_MAX))
+            exit(EXIT_FAILURE);
 
-            else
-                goto input_error;
+        if (!get_stdin_line(" type's number(1, 2, ...): ", buf, 100))
+            data.song_number = ((num = atoi(buf)) <= 0) ? 1 : num;
 
-            ret |= kara_metadata_write(&data, argv[i], mkvpropedit);
-        }
+        else
+            exit(EXIT_FAILURE);
 
+        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;
-    }
-
-    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;
     }
 
-    else if (strcmp(argv[1], "--get-id") == 0) {
-
-        if (argc != 3) {
-            fprintf(stderr, " ! invalid argument, just need one id\n");
-            return 1;
-        }
-
-        i = atoi(argv[2]);
-
-        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)) {
-            fprintf(stderr, " ! could not download json for kara %d\n", i);
-            return 61;
-        }
+    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
+get__(struct lkt_cmd_args *args)
+{
+    int i;
+    struct kara_metadata data;
+    struct lkt_repo repo;
 
-        return 0;
+    if (args->argc != 1) {
+        fprintf(stderr, " ! invalid argument, just need one id\n");
+        exit(EXIT_FAILURE);
     }
 
-    else if (strcmp(argv[1], "--down-id") == 0) {
-
-        if (argc != 4)
-            goto print_help;
+    i = atoi(args->argv[0]);
 
-        i = atoi(argv[2]);
+    if (repo_new(&repo, "kurisu", "https://kurisu.iiens.net")) {
+        fprintf(stderr, " ! could not create the repo\n");
+        exit(EXIT_FAILURE);
+    }
 
-        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)) {
+        fprintf(stderr, " ! could not download json for kara %d\n", i);
+        exit(EXIT_FAILURE);
+    }
 
-        if (repo_download_id_sync(&repo, NULL, i, argv[3], &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 %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
-              );
+noreturn void
+download__(struct lkt_cmd_args *args)
+{
+    if (args->argc != 2)
+        exit(EXIT_FAILURE);
 
+    struct lkt_repo repo;
+    struct kara_metadata data;
+    int i = atoi(args->argv[0]);
 
-        return 0;
+    if (repo_new(&repo, "kurisu", "https://kurisu.iiens.net")) {
+        fprintf(stderr, " ! could not create the repo\n");
+        exit(EXIT_FAILURE);
     }
 
-    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;
+    if (repo_download_id_sync(&repo, NULL, i, args->argv[1], &data)) {
+        fprintf(stderr, " ! could not download json for kara %d\n", i);
+        exit(EXIT_FAILURE);
     }
 
-    /* The help. */
+    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);
+}
 
-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_init[] = {
+//    { .name = "database",   .call = init_database__ },
+    { .name = "populate",   .call = init_populate__ },
+    { .name = "metadata",   .call = init_metadata__ },
+    LKT_OPT_NULL,
+};
+
+noreturn void
+init__(struct lkt_cmd_args *args)
+{
+    lkt_cmd_parse(options_init, args->argc, args->argv, help);
+}
+
+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, char *argv[])
+{
+    lkt_cmd_parse(options, argc, (const char **) argv, help);
 }
+