/* dblayer.c - Database layer for ck -----------------------------------*- C -*-
*
* This file is part of ck, the config keeper
*
* -----------------------------------------------------------------------------
*
* Copyright (C) 2019 Anastasis Grammenos
* GPLv3 (see LICENCE for the full notice)
*
* -------------------------------------------------------------------------- */
#include <libgen.h>
#include "dblayer.h"
#include "ckerrlog.h"
ERRLOG(ckdb);
static const char * const DB_FILE_NAME = "/ckdb";
/* figure out the database name */
static void make_db_name(char *ret, const char *confPath) {
char db_path[STR_L] = "";
strcpy(db_path, confPath);
strcat(db_path, DB_FILE_NAME);
strcpy(ret, db_path);
}
/* Check if the db file exists*/
int db_exists(const UserOpt *opt) {
char db_path[STR_L] = "";
make_db_name(db_path, opt->confDir);
return util_is_file_rw(db_path);
}
/* check if db has the correct tables */
static int check_initialized_DB(sqlite3 *db) {
char sql[STR_M] = "";
dbh_form_query_select_all_tables(sql);
sqlite3_stmt *stmt;
sqlite3_prepare_v2(db, sql, (int)strlen(sql), &stmt, NULL);
int program_table_ok, config_table_ok, rel_table_ok = 0;
while (sqlite3_step(stmt) != SQLITE_DONE) {
const unsigned char *tmpbuf = sqlite3_column_text(stmt, 1);
if (strcmp((char *)tmpbuf, TBL_PROGRAM) == 0) {
program_table_ok = 1;
}
if (strcmp((char *)tmpbuf, TBL_CONFIG) == 0) {
config_table_ok = 1;
}
if (strcmp((char *)tmpbuf, TBL_REL) == 0) {
rel_table_ok = 1;
}
}
if (!program_table_ok
|| !config_table_ok
|| !rel_table_ok ) {
return 1;
}
sqlite3_finalize(stmt);
return 0;
}
void close_DB(DB *db) {
sqlite3_close(db->ptr);
}
int open_DB(DB *db, const UserOpt *opt) {
if (!db || !opt) {
return -1;
}
int rc;
char db_path[STR_L] = "";
make_db_name(db_path, opt->confDir);
rc = sqlite3_open(db_path, &db->ptr);
if (rc) {
ERR("%s is not a path to an sqlite3 database.", db_path);
return -1;
}
if (opt->action != CKA_INIT) {
if (check_initialized_DB(db->ptr)) {
ERR("The database file is currupted. Run ck init anew.");
return -1;
}
}
LOG("Opened %s", db_path);
return 0;
}
int get_program_id(DB *db, const char* name) {
sqlite3_stmt *stmt;
int rc;
char sql[STR_M] = "";
dhb_form_query_find_program(sql);
rc = sqlite3_prepare_v2(db->ptr, sql, -1, &stmt, 0);
if (rc != SQLITE_OK) {
PRINT_ERR("Error while preparing get_program_id sql.");
return -2;
}
sqlite3_bind_text(stmt, 1, name, (int)strlen(name), 0);
int id = -1;
while (sqlite3_step(stmt) == SQLITE_ROW) {
id = sqlite3_column_int(stmt, 0);
break;
}
sqlite3_finalize(stmt);
return id;
}
int program_exists(DB *db, const char *pName) {
if (get_program_id(db, pName) == -1) {
return 0;
}
return 1;
}
int get_config_id(DB *db, const char* path) {
sqlite3_stmt *stmt;
int rc;
char sql[STR_M] = "";
dhb_form_query_find_config(sql);
rc = sqlite3_prepare_v2(db->ptr, sql, -1, &stmt, 0);
if (rc != SQLITE_OK) {
PRINT_ERR("while preparing get_config_id sql.");
return -2;
}
sqlite3_bind_text(stmt, 1, path, (int)strlen(path), 0);
int id = -1;
while (sqlite3_step(stmt) == SQLITE_ROW) {
id = sqlite3_column_int(stmt, 0);
break;
}
sqlite3_finalize(stmt);
return id;
}
int program_has_primary_config(DB *db, const int pid, char *ret, int *sec) {
sqlite3_stmt *stmt;
int rc;
char sql[STR_L] = "";
char condition[STR_S] = TBL_PROGRAM;
strcat(condition, ".");
strcat(condition, COL_PROGRAM_ID);
char selection[STR_M] = COL_CONFIG_PRIMARY;
strcat(selection, ", ");
strcat(selection, COL_CONFIG_PATH);
strcat(selection, ", ");
strcat(selection, COL_CONFIG_SECRET);
dbh_form_query_select_from_joined_eq(sql, selection, condition);
rc = sqlite3_prepare_v2(db->ptr, sql, -1, &stmt, 0);
if (rc != SQLITE_OK) {
PRINT_ERR("whinnle preparing program_has_primary_exists sql.");
return -2;
}
sqlite3_bind_int(stmt, 1, pid);
while (sqlite3_step(stmt) == SQLITE_ROW) {
if (sqlite3_column_int(stmt, 0) == 1) {
if (ret) {
strcpy(ret,(char *)sqlite3_column_text(stmt, 1));
}
if (sec) {
*sec = sqlite3_column_int(stmt, 2);
}
sqlite3_finalize(stmt);
return 1;
}
}
sqlite3_finalize(stmt);
return 0;
}
int get_program_relations(DB *db, int pid) {
int count = -1;
sqlite3_stmt *stmt;
int rc;
char sql[STR_M] = "";
dbh_form_query_count_program_relations(sql);
rc = sqlite3_prepare_v2(db->ptr, sql, -1, &stmt, 0);
if (rc != SQLITE_OK) {
return -1;
}
sqlite3_bind_int(stmt, 1, pid);
while (sqlite3_step(stmt) == SQLITE_ROW) {
count = sqlite3_column_int(stmt, 0);
}
if (rc != SQLITE_OK) {
return -1;
}
sqlite3_finalize(stmt);
return count;
}
int get_config_number(DB *db, char* pName) {
int pid = get_program_id(db, pName);
/* program exists */
if (pid > -1) {
return get_program_relations(db, pid);
}
return -1;
}
int get_pid_from_cid(DB *db, int cid) {
int pid = -1;
sqlite3_stmt *stmt;
int rc;
char sql[STR_M] = "";
dbh_form_query_get_pid_from_cid(sql);
rc = sqlite3_prepare_v2(db->ptr, sql, -1, &stmt, 0);
if (rc != SQLITE_OK) {
return -1;
}
sqlite3_bind_int(stmt, 1, cid);
while (sqlite3_step(stmt) == SQLITE_ROW) {
pid = sqlite3_column_int(stmt, 0);
}
if (rc != SQLITE_OK) {
return -1;
}
sqlite3_finalize(stmt);
return pid;
}
void print_suggested_configs(DB *db, const char *pName) {
char name[STR_M] = "";
strcat(name, pName);
strcat(name, ":");
cklist *paths = list_make_and_add(name);
get_program_paths(db, paths, pName, 1, 0, NULL);
list_print(paths);
list_free(paths);
}
int get_program_paths(DB *db, cklist *ckl, const char* pName, int bname, int attr, const char *home) {
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);
strcat(selection, ",");
strcat(selection, COL_CONFIG_PRIMARY);
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;
}
while (sqlite3_step(stmt) == SQLITE_ROW) {
char *tmp = strdup((char *)sqlite3_column_text(stmt, 0));
char entry[STR_M] = "";
if (bname) {
strcat(entry, basename(tmp));
}
else {
char tpath[STR_L] = "";
if (swap_tilde_with_home(tpath, tmp, home)) {
strcat(entry, tpath);
}
else {
strcat(entry, tmp);
}
}
if (attr) {
decorate_entry(entry, sqlite3_column_int(stmt, 1),
sqlite3_column_int(stmt, 2),
(char *)sqlite3_column_text(stmt, 0));
}
list_add(ckl, entry);
free(tmp);
}
sqlite3_finalize(stmt);
return 0;
}
return -1;
}
int secret_enabled(DB *db) {
sqlite3_stmt *stmt;
int rc;
char sql[STR_M] = "";
dbh_form_query_secret_enabled(sql);
rc = sqlite3_prepare_v2(db->ptr, sql, -1, &stmt, 0);
if (rc != SQLITE_OK) {
ERR("while preparing secret_enabled sql.");
return -2;
}
int enabled = 1;
while (sqlite3_step(stmt) == SQLITE_ROW) {
enabled = sqlite3_column_int(stmt, 0);
break;
}
sqlite3_finalize(stmt);
return enabled;
}