/* edit.c - the edit action --------------------------------------------*- C -*- * * This file is part of ck, the config keeper * * ----------------------------------------------------------------------------- * * Copyright (C) 2019 Anastasis Grammenos * GPLv3 (see LICENCE for the full notice) * * -------------------------------------------------------------------------- */ #include #include "dblayer.h" #include "ckerrlog.h" ERRLOG(edit); static int edit_get_prime_config_from_program(DB *db, char *pName, char *ret, int *secret) { int pid = get_program_id(db, pName); /* error */ if (pid == -2) { return -1; } /* program exists */ if (pid > -1) { char path[STR_M] = ""; if (program_has_primary_config(db, pid, path, secret) == 1) { if (!str_is_empty(path)) { if (ret) { str_make_ck_config_name(ret, path, pName); } return 0; } } } /* No prime config found */ return -1; } static int edit_get_config(DB *db, const char *pName, char *ret, const char *cName, int *sec) { int pid = get_program_id(db, pName); /* error */ if (pid == -2) { return -1; } /* program exists */ if (pid > -1) { sqlite3_stmt *stmt; int rc; char selection[STR_M] = COL_CONFIG_PATH; strcat(selection, ", "); strcat(selection, COL_CONFIG_SECRET); char condition[STR_M] = TBL_PROGRAM; strcat(condition, "."); strcat(condition, COL_PROGRAM_ID); char sql[STR_L] = ""; dbh_form_query_select_from_joined_eq(sql, selection, condition); rc = sqlite3_prepare_v2(db->ptr, sql, -1, &stmt, 0); sqlite3_bind_int(stmt, 1, pid); if (rc != SQLITE_OK) { return -2; } int flag = -1; while (sqlite3_step(stmt) == SQLITE_ROW) { char confName[STR_M] = ""; if (cName) { char *tmp = strdup((char *)sqlite3_column_text(stmt, 0)); if (strcmp(cName, basename(tmp)) == 0) { flag = 0; str_make_ck_config_name(confName, (char *)sqlite3_column_text(stmt, 0), pName); strcpy(ret, confName); if (sec) { *sec = sqlite3_column_int(stmt, 1); } } free(tmp); } else { /* Since we are here, it means there is only 1 config for the selected program */ flag = 0; str_make_ck_config_name(confName, (char *)sqlite3_column_text(stmt, 0), pName); strcpy(ret, confName); if (sec) { *sec = sqlite3_column_int(stmt, 1); } break; } } sqlite3_finalize(stmt); return flag; } return -1; } static EditOpt edit_make_options(cklist *args) { list_rewind(args); EditOpt editOpt = { .pName = NULL, .cBasename = NULL, .editor = NULL, .cmd = NULL, .sudo = 0, .err = 0 }; if (list_size(args)) { editOpt.pName = list_get(args); } else { editOpt.err = 1; sERR("Please specify the program to edit.") goto done; } if (list_next(args)) { /* if the next argument doesn't start with `-` treat it as a config basename */ if (strncmp("-", list_get(args), strlen("-")) != 0) { editOpt.cBasename = list_get(args); if (!list_next(args)) { goto done; } } do { if (strcmp(list_get(args), "-s") == 0) { editOpt.sudo = 1; } else if (strcmp(list_get(args), "--editor") == 0) { if (editOpt.cmd) { sERR("Use only one of --command and --editor"); editOpt.err = 1; break; } if (!list_next(args)) { sERR("Specify the editor to use.") editOpt.err = 1; break; } editOpt.editor = list_get(args); } else if (strcmp(list_get(args), "--command") == 0) { if (editOpt.editor) { sERR("Use only one of --command and --editor"); editOpt.err = 1; break; } if (!list_next(args)) { sERR("Specify the command to use.") editOpt.err = 1; break; } editOpt.cmd = list_get(args); } else { editOpt.err = 1; ERR("Unknown argument %s", list_get(args)); break; } } while(list_next(args)); } done: list_rewind(args); return editOpt; } static char * form_edit_command(char *ret, const EditOpt *editOpt, const char *confPath) { char command[STR_L] = ""; if (editOpt->editor) { char tmp[STR_L] = "which "; strcat(tmp, editOpt->editor); strcat(tmp, " > /dev/null 2>&1"); if (system(tmp) != 0) { ERR("Editor %s not found.", editOpt->editor); HELP("If you want to run the command either way use --command instead of --editor.") return NULL; } else { strcpy(command, editOpt->editor); } } else if (editOpt->cmd) { strcpy(command, editOpt->cmd); } else { char *editor = getenv("EDITOR"); if (str_is_empty(editor)) { if (system("which emacs > /dev/null 2>&1") != 0) { ERR("No editor avaliable."); HELP("Emacs not found. Please set $EDITOR to your desired editor,"); HELP("or use the --editor flag.") return NULL; } strcpy(command, "nano"); } else { strcpy(command, editor); } } strcat(command, " "); strcat(command, confPath); if (editOpt->sudo) { char tmp[STR_L] = "sudo "; strcat(tmp, command); return strcpy(ret, tmp); } return strcpy(ret, command); } int run_EDIT(UserOpt *opt, Conf *conf) { char confPath[STR_L] = ""; char confName[STR_M] = ""; int secret = 0; DB db; if (open_DB(&db, opt)) { return -1; } EditOpt editOpt = edit_make_options(opt->args); if (editOpt.err) { goto error; } if (!program_exists(&db, editOpt.pName)) { ERR("Program %s doesn't exist in the database.", editOpt.pName); goto error; } /* If there is no config basename */ if (!editOpt.cBasename) { /* If there is no primary config*/ if (edit_get_prime_config_from_program(&db, editOpt.pName, confName, &secret) == -1) { /* If the program has only one config */ if (get_config_number(&db, editOpt.pName) == 1) { if (edit_get_config(&db, editOpt.pName, confName, NULL, &secret)) { ERR("Coudln't find config file for %s", editOpt.pName); goto error; } } /* If the program has many configs */ else { HELP("Ambiguous config. Please type the config name after the program."); print_suggested_configs(&db, editOpt.pName); goto error; } } } /* If there are more arguments */ else { if (edit_get_config(&db, editOpt.pName, confName, editOpt.cBasename, &secret)) { ERR("Program %s doesn't have a config named %s", editOpt.pName, editOpt.cBasename); print_suggested_configs(&db, editOpt.pName); goto error; } } close_DB(&db); str_join_dirname_with_basename(confPath, secret ? conf->scrt_dir : conf->vc_dir, confName); char command[STR_L] = ""; if (form_edit_command(command, &editOpt, confPath)) { hLOG("Running: %s", command); return system(command); } error: close_DB(&db); return -1; } void print_EDIT_help() { HELP("ck edit PROGRAM_NAME [CONFIG_BASENAME] [--editor EDITOR] [--command COMMAND] [-s]"); }