aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt3
-rwxr-xr-xres/check_ck1
-rw-r--r--src/actionparser.c7
-rw-r--r--src/actions.c24
-rw-r--r--src/ck.c21
-rw-r--r--src/ckutil.c68
-rw-r--r--src/ckutil.h38
-rw-r--r--src/confparser.c17
-rw-r--r--src/confparser.h2
-rw-r--r--src/dblayer.c30
-rw-r--r--src/dblayer.h8
-rw-r--r--src/engine.c62
-rw-r--r--src/engine.h26
-rw-r--r--tests/add81
14 files changed, 332 insertions, 56 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b0eeb7e..e38e8e2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -26,6 +26,7 @@ set(ckLib_src
${SRC_DIR}/dblayer.c
${SRC_DIR}/dbhelper.c
${SRC_DIR}/ckutil.c
+ ${SRC_DIR}/engine.c
)
set(ckLib_hdr
${SRC_DIR}/actionparser.h
@@ -34,6 +35,7 @@ set(ckLib_hdr
${SRC_DIR}/dblayer.h
${SRC_DIR}/dbhelper.h
${SRC_DIR}/ckutil.h
+ ${SRC_DIR}/engine.h
)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${RES_DIR}/cmake)
@@ -61,6 +63,7 @@ target_link_libraries (ck ${SQLITE3_LIBRARIES})
set(BIN_TESTS_DIR ${CMAKE_BINARY_DIR}/res/tests)
set(PROJECT_TESTING_GROUNDS ${CMAKE_BINARY_DIR}/test_files)
configure_file(${TESTS_DIR}/init ${BIN_TESTS_DIR}/init @ONLY)
+configure_file(${TESTS_DIR}/add ${BIN_TESTS_DIR}/add @ONLY)
# check_ck
configure_file(${RES_DIR}/check_ck check_ck @ONLY)
diff --git a/res/check_ck b/res/check_ck
index 14ec5ba..fc80bd2 100755
--- a/res/check_ck
+++ b/res/check_ck
@@ -5,4 +5,5 @@ for i in $( ls $DIR ); do
ERROR="TEST "$i" FAILED:"
PASS="TEST "$i" PASSED"
source $DIR/$i
+ wait $!
done
diff --git a/src/actionparser.c b/src/actionparser.c
index 207a089..0dca98c 100644
--- a/src/actionparser.c
+++ b/src/actionparser.c
@@ -203,11 +203,10 @@ void get_config(UserOpt *opt) {
return;
}
}
- char * defaultConf = "/.ck";
+ char * defaultConf = ".ck";
char * home = getenv("HOME");
- opt->confDir = malloc(strlen(defaultConf)+strlen(home)+1);
- strcpy(opt->confDir, home);
- strcat(opt->confDir, defaultConf);
+ opt->confDir = malloc(strlen(defaultConf) + 1 /* '/' */ + strlen(home)+1);
+ str_join_dirname_with_basename(opt->confDir, home, defaultConf);
// rewind
pos = pos - 1;
diff --git a/src/actions.c b/src/actions.c
index 77680eb..318c86b 100644
--- a/src/actions.c
+++ b/src/actions.c
@@ -11,11 +11,13 @@
#include "actions.h"
#include "dblayer.h"
#include "ckutil.h"
+#include "engine.h"
int run_INIT(UserOpt * opt, Conf *conf) {
+ UNUSED(conf);
if (db_exists(opt)) {
printf("Current configuration file location: %s\n", opt->confDir);
- PRINT_ERR("ck is already initialized.\n");
+ PRINT_ERR("ck is already initialized.");
return 0;
}
if (init_create_config_file(opt)) {
@@ -30,6 +32,7 @@ int run_INIT(UserOpt * opt, Conf *conf) {
}
AddOpt make_add_options(const int argc, char **argv) {
+ /* since we are here, the first two argumens must exist */
AddOpt addOpt = {
.progName = argv[0],
.confPath = NULL,
@@ -38,7 +41,6 @@ AddOpt make_add_options(const int argc, char **argv) {
.err = ADD_NO_ERR
};
- /* the first two argumens have to exist since we are here */
if (!util_is_file_rw(argv[1])) {
addOpt.err = ADD_ERR_WRONG_CONFIG;
return addOpt;
@@ -90,29 +92,34 @@ int run_ADD(UserOpt * opt, Conf *conf) {
DB db = open_DB(opt);
if (db.ptr == NULL) {
if (db.error == SQL_ERR_NO_TABLES) {
- PRINT_ERR("The database file is currupted. Run ck init anew.\n");
+ PRINT_ERR("The database file is currupted. Run ck init anew.");
}
+ return 0;
}
AddOpt addOpt = make_add_options(opt->argc, opt->argv);
switch (addOpt.err) {
case ADD_NO_ERR:
break;
case ADD_ERR_WRONG_CONFIG:
- PRINT_ERR("The config file specified doesn't exist.\n");
+ PRINT_ERR("The config file specified doesn't exist.");
close_DB(&db);
return 0;
case ADD_ERR_WRONG_FLAGS:
- PRINT_ERR("Flags are: -s for secret and -p for primary.\n");
+ PRINT_ERR("Flags are: -s for secret and -p for primary.");
close_DB(&db);
return 0;
}
add_print_opts(&addOpt);
- if (add_transaction_begin(&db, addOpt.progName,
- addOpt.confPath, addOpt.secret, addOpt.prime) == 0) {
+ if (add_transaction_begin(&db, &addOpt) == 0) {
return 0;
}
- // do the linking
close_DB(&db);
+ engine_add_make_link(&addOpt, conf);
+ char err[STR_M];
+ if (engine_err_message(err)) {
+ PRINT_ERR(err);
+ return 0;
+ }
return 1;
}
@@ -133,6 +140,7 @@ int run_LIST(UserOpt * opt, Conf *conf) {
if (db.error == SQL_ERR_NO_TABLES) {
printf("no tables\n");
}
+ return 0;
}
for (int i = 0; i < opt->argc; i++) {
printf("[%d]: %s\n", i, opt->argv[i]);
diff --git a/src/ck.c b/src/ck.c
index a63eb63..ef499a9 100644
--- a/src/ck.c
+++ b/src/ck.c
@@ -32,30 +32,39 @@
#include "dblayer.h"
#include "ckutil.h"
+void free_res(UserOpt *opt, Conf *conf) {
+ if (opt) {
+ free_user_opt(opt);
+ }
+ if (conf) {
+ free_conf(conf);
+ }
+}
+
int main(int argc, char *argv[]) {
UserOpt opt;
switch(parse_action(argc, argv, &opt)) {
case APR_HELP:
- free_user_opt(&opt);
+ free_res(&opt, NULL);
print_parser_help();
return 0;
case APR_ERR:
print_parser_error(&opt);
- free_user_opt(&opt);
+ free_res(&opt, NULL);
return 1;
case APR_OK:
break;
}
- Conf conf;
+ Conf conf = {.VC_dir = NULL, .SCRT_dir = NULL};
if (opt.action != CKA_INIT) {
if (!db_exists(&opt)) {
printf("ck is not initialized in %s.\nRun ck init first.\n", opt.confDir);
- free_user_opt(&opt);
+ free_res(&opt, NULL);
return 1;
}
if (!config_file_parse(&conf, &opt)) {
- free_user_opt(&opt);
+ free_res(&opt, &conf);
return 1;
}
}
@@ -71,6 +80,6 @@ int main(int argc, char *argv[]) {
default:
break;
}
- free_user_opt(&opt);
+ free_res(&opt, &conf);
return 0;
}
diff --git a/src/ckutil.c b/src/ckutil.c
index fc6d4b0..a77aa01 100644
--- a/src/ckutil.c
+++ b/src/ckutil.c
@@ -8,8 +8,11 @@
* GPLv3 (see LICENCE for the full notice)
*
* -------------------------------------------------------------------------- */
-#include <dirent.h>
#include <ctype.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <sys/sendfile.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -25,13 +28,15 @@ int util_is_dir(const char *path) {
return 1;
}
-int util_is_str_empty(const char *s) {
+void util_replace_slash_with_uscore(char *s) {
+ int i = 0;
while (*s != '\0') {
- if (!isspace((unsigned char)*s))
- return 0;
+ if (*s == '/' && i != 0) {
+ *s = '_';
+ }
s++;
+ i++;
}
- return 1;
}
int util_file_exists(const char* path) {
@@ -52,3 +57,56 @@ int util_is_file_rw(const char* path) {
void util_mkdir(const char *name) {
mkdir(name, 0755);
}
+
+int util_move_file(const char *path, const char* dest) {
+ int srcFile = open(path, O_RDONLY);
+ int destFile = open(dest, O_WRONLY | O_CREAT);
+ struct stat st, newSt;
+
+ fstat(srcFile, &st);
+ sendfile(destFile, srcFile, NULL, st.st_size);
+ close(srcFile);
+
+ fchmod(destFile, st.st_mode);
+
+ fstat(destFile, &newSt);
+ if (st.st_size == newSt.st_size) {
+ unlink(path);
+ close(destFile);
+ return 0;
+ }
+ close(destFile);
+ return -1;
+}
+
+int util_symlink_file(const char *path, const char* dest) {
+ return symlink(path, dest);
+}
+
+void str_make_new_config_name(char *ret, const char *path,
+ const char *progName) {
+ char *basec = strdup(path);
+ char *bname = basename(basec);
+
+ strcpy(ret, progName);
+ strcat(ret, "_");
+ strcat(ret, bname);
+ free(basec);
+}
+
+void str_join_dirname_with_basename(char *ret, const char *dirname,
+ const char *basename) {
+ strcpy(ret, dirname);
+ strcat(ret, "/");
+ strcat(ret, basename);
+}
+
+int str_is_empty(const char *s) {
+ while (*s != '\0') {
+ if (!isspace((unsigned char)*s)) {
+ return 0;
+ }
+ s++;
+ }
+ return 1;
+}
diff --git a/src/ckutil.h b/src/ckutil.h
index 4c873d6..9955440 100644
--- a/src/ckutil.h
+++ b/src/ckutil.h
@@ -24,7 +24,9 @@
#include <string.h>
#define PRINT_ERR(ERROR) \
- printf("--[ Error ]--\n%s", ERROR);
+ printf("--[ Error ]--\n%s\n", ERROR);
+
+#define UNUSED(x) (void)(x)
/********************/
/* global constants */
@@ -39,6 +41,23 @@
/* String length - Large */
#define STR_L 400
+/********************/
+/* string functions */
+/********************/
+
+/* Create the config name to be used when storing a new config to
+ * the VC or SCRT dir */
+extern void str_make_new_config_name(char *ret, const char *path,
+ const char *progName);
+
+/* Joins the two strings into ret, with a '/' in between */
+extern void str_join_dirname_with_basename(char *ret, const char *path,
+ const char *progName);
+
+/* Returns 1 if str contains only whitespace, or nothing,
+ * else returns 0. */
+extern int str_is_empty(const char *s);
+
/*********************/
/* utility functions */
/*********************/
@@ -49,13 +68,20 @@ extern int util_is_dir(const char *path);
/* Returns 1 if file(or dir) exists, else returns 0. */
extern int util_file_exists(const char *path);
+/* Returns 1 if file(or dir) is readable and writable,
+ * else returns 0. */
extern int util_is_file_rw(const char *path);
-extern int util_is_cli_flag();
-/* Returns 1 if str contains only whitespace, or nothing,
- * else returns 0. */
-extern int util_is_str_empty();
-extern int util_remove_newlibe();
+extern void util_replace_slash_with_uscore(char *s);
+/* Wrapper around mkdir with 0775 permissions */
extern void util_mkdir(const char *path);
+
+/* Moves file from path, to destination
+ * keeping the same permissions.
+ * Only deletes original on successful copy */
+extern int util_move_file(const char *path, const char* dest);
+
+/* Wrapper around symlink() */
+extern int util_symlink_file(const char *path, const char* dest);
#endif // CKUTIL_H
diff --git a/src/confparser.c b/src/confparser.c
index 0f193e0..80120c8 100644
--- a/src/confparser.c
+++ b/src/confparser.c
@@ -43,7 +43,7 @@ int read_next_line(char *line, FILE *f) {
}
ConfVar match_variables(char *line, char matched[]) {
- if (line[0] == '#' || util_is_str_empty(line)) {
+ if (line[0] == '#' || str_is_empty(line)) {
return CV_NO_VAL_OR_COMMENT;
}
#define X(var, str, name) \
@@ -74,7 +74,7 @@ ConfigParserResult parse(Conf *conf, UserOpt *opt) {
int flag = 1;
char line[STR_L];
char matched[STR_L];
- while (read_next_line(line, confPtr)) {
+ while (read_next_line(line, confPtr) == 0) {
if (strlen(line) > STR_L) {
return CPR_WRONG_CONFIG;
}
@@ -84,7 +84,6 @@ ConfigParserResult parse(Conf *conf, UserOpt *opt) {
conf->var = malloc(strlen(matched)+1); \
strcpy(conf->var, matched); \
if (!util_is_dir(matched)) { \
- free(conf->var); \
return CPR_WRONG_##var; \
} \
break;
@@ -111,9 +110,10 @@ int config_file_parse(Conf *conf, UserOpt *opt) {
switch (parse(conf, opt)) {
#define X(var,str,name) \
case CPR_WRONG_##var: \
- printf("Config error:\n" \
+ printf("--[ Config error ]--\n" \
"%s: %s\n" \
"defined in config does not exist\n", name, conf->var); \
+ free(conf->var); \
return 0; \
break;
CONFIG_VARIABLES_TABLE
@@ -128,6 +128,15 @@ int config_file_parse(Conf *conf, UserOpt *opt) {
}
}
+void free_conf(Conf *conf) {
+ if (conf->VC_dir) {
+ free(conf->VC_dir);
+ }
+ if (conf->SCRT_dir) {
+ free(conf->SCRT_dir);
+ }
+}
+
int init_create_config_file(UserOpt *opt) {
char tmp[200];
if (!util_file_exists(opt->argv[0])) {
diff --git a/src/confparser.h b/src/confparser.h
index 076cb0f..a07972b 100644
--- a/src/confparser.h
+++ b/src/confparser.h
@@ -54,5 +54,5 @@ struct ConfigValues {
extern int config_file_parse(Conf *conf, UserOpt *opt);
extern int init_create_config_file(UserOpt *opt);
-
+extern void free_conf(Conf *conf);
#endif // CONFPARSER_H
diff --git a/src/dblayer.c b/src/dblayer.c
index bde712b..d9284df 100644
--- a/src/dblayer.c
+++ b/src/dblayer.c
@@ -157,7 +157,7 @@ int insert_to_program_table(DB *db, const char *name) {
rc = sqlite3_prepare_v2(db->ptr, sql, -1, &stmt, 0);
if (rc != SQLITE_OK) {
- PRINT_ERR("while preparing insert to program sql.\n");
+ PRINT_ERR("while preparing insert to program sql.");
db->error = SQL_ERR_SQLITE;
return -1;
}
@@ -169,7 +169,7 @@ int insert_to_program_table(DB *db, const char *name) {
sqlite3_bind_int(stmt, 1, id);
sqlite3_bind_text(stmt, 2, name, strlen(name), 0);
if (sqlite3_step(stmt) != SQLITE_DONE) {
- PRINT_ERR("while excecuting insert to program sql.\n");
+ PRINT_ERR("while excecuting insert to program sql.");
db->error = SQL_ERR_SQLITE;
return -1;
}
@@ -185,7 +185,7 @@ int insert_to_config_table(DB *db, const char *path, const int secret, const int
dbh_form_query_insert_config(sql);
rc = sqlite3_prepare_v2(db->ptr, sql, -1, &stmt, 0);
if (rc != SQLITE_OK) {
- PRINT_ERR("Error while preparing insert to config sql.\n");
+ PRINT_ERR("Error while preparing insert to config sql.");
db->error = SQL_ERR_SQLITE;
return -1;
}
@@ -199,7 +199,7 @@ int insert_to_config_table(DB *db, const char *path, const int secret, const int
sqlite3_bind_int(stmt, 3, secret);
sqlite3_bind_int(stmt, 4, prime);
if (sqlite3_step(stmt) != SQLITE_DONE) {
- PRINT_ERR("Error while excecuting insert to config sql.\n");
+ PRINT_ERR("Error while excecuting insert to config sql.");
db->error = SQL_ERR_SQLITE;
return-1;
}
@@ -216,14 +216,14 @@ int insert_to_rel_table(DB *db, const int pid, const int cid) {
rc = sqlite3_prepare_v2(db->ptr, sql, -1, &stmt, 0);
if (rc != SQLITE_OK) {
db->error = SQL_ERR_SQLITE;
- PRINT_ERR("while preparing insert to rel sql.\n");
+ PRINT_ERR("while preparing insert to rel sql.");
return -1;
}
sqlite3_bind_int(stmt, 1, pid);
sqlite3_bind_int(stmt, 2, cid);
if (sqlite3_step(stmt) != SQLITE_DONE) {
db->error = SQL_ERR_SQLITE;
- PRINT_ERR("while excecuting insert to rel sql.\n");
+ PRINT_ERR("while excecuting insert to rel sql.");
return-1;
}
sqlite3_finalize(stmt);
@@ -239,7 +239,7 @@ int program_exists(DB *db, const char* name) {
rc = sqlite3_prepare_v2(db->ptr, sql, -1, &stmt, 0);
if (rc != SQLITE_OK) {
- PRINT_ERR("Error while preparing program_exists sql.\n");
+ PRINT_ERR("Error while preparing program_exists sql.");
return -2;
}
sqlite3_bind_text(stmt, 1, name, strlen(name), 0);
@@ -252,7 +252,7 @@ int program_exists(DB *db, const char* name) {
return id;
}
-int config_exists(DB *db, const int pid, const char* path) {
+int config_exists(DB *db, const char* path) {
sqlite3_stmt *stmt;
int rc;
@@ -261,7 +261,7 @@ int config_exists(DB *db, const int pid, const char* path) {
rc = sqlite3_prepare_v2(db->ptr, sql, -1, &stmt, 0);
if (rc != SQLITE_OK) {
- PRINT_ERR("while preparing config_exists sql.\n");
+ PRINT_ERR("while preparing config_exists sql.");
return -2;
}
sqlite3_bind_text(stmt, 1, path, strlen(path), 0);
@@ -293,7 +293,7 @@ int program_has_primary_config(DB *db, const int pid) {
rc = sqlite3_prepare_v2(db->ptr, sql, -1, &stmt, 0);
if (rc != SQLITE_OK) {
- PRINT_ERR("while preparing program_has_primary_exists sql.\n");
+ PRINT_ERR("while preparing program_has_primary_exists sql.");
return -2;
}
sqlite3_bind_int(stmt, 1, pid);
@@ -309,7 +309,7 @@ int program_has_primary_config(DB *db, const int pid) {
}
int add_get_or_insert_config_to_db(DB *db, const int pid, const char *path, const int secret, const int prime) {
- int cid = config_exists(db, pid, path);
+ int cid = config_exists(db, path);
if (cid == -2) {
db->error = SQL_ERR_SQLITE;
return -1;
@@ -340,17 +340,15 @@ int add_get_or_insert_program_to_db(DB *db, const char *name) {
return pid;
}
-int add_transaction_begin(DB *db, const char *progName,
- const char* confPath, const int secret,
- const int prime) {
+int add_transaction_begin(DB *db, const AddOpt * const opt) {
__BEGIN_TRANSACTION__
- int pid = add_get_or_insert_program_to_db(db, progName);
+ int pid = add_get_or_insert_program_to_db(db, opt->progName);
if (db->error == SQL_ERR_SQLITE) {
PRINT_ERR("Could not insert program to db.\n");
close_DB(db);
return 0;
}
- int cid = add_get_or_insert_config_to_db(db, pid, confPath, secret, prime);
+ int cid = add_get_or_insert_config_to_db(db, pid, opt->confPath, opt->secret, opt->prime);
if (db->error == SQL_ERR_SQLITE) {
PRINT_ERR("Could not insert config to db.\n");
close_DB(db);
diff --git a/src/dblayer.h b/src/dblayer.h
index 40b7dfb..e44ea72 100644
--- a/src/dblayer.h
+++ b/src/dblayer.h
@@ -17,7 +17,7 @@
#include <sqlite3.h>
-#include "actionparser.h"
+#include "actions.h"
typedef enum SqlErrors SqlError;
enum SqlErrors {
@@ -55,9 +55,5 @@ extern DB init_make_DB(const UserOpt *opt);
/* add */
/*******/
-extern int add_transaction_begin(DB *db, const char *progName,
- const char* confPath, const int secret,
- const int prime);
-extern int add_insert_program_to_db(DB *db, const char * name);
-extern int add_insert_config_to_db(DB *db, const int pid, const char *path, const int secret, const int prime);
+extern int add_transaction_begin(DB *db, const AddOpt * const opt);
#endif /* DBLAYER_H */
diff --git a/src/engine.c b/src/engine.c
new file mode 100644
index 0000000..3505fd0
--- /dev/null
+++ b/src/engine.c
@@ -0,0 +1,62 @@
+/* engine.c - manages the linking and copying of configs ---------------*- C -*-
+ *
+ * This file is part of ck, the config keeper
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2018 Anastasis Grammenos
+ * GPLv3 (see LICENCE for the full notice)
+ *
+ * -----------------------------------------------------------------------------
+ *
+ *
+ *
+ * -------------------------------------------------------------------------- */
+#include "engine.h"
+
+char engine_err[STR_M] = "";
+
+int engine_err_message(char *err) {
+ if (!str_is_empty(engine_err)) {
+ if (err) {
+ strcpy(err, engine_err);
+ }
+ return 1;
+ }
+ return 0;
+}
+
+int copy_config(char *path);
+
+
+void link_config(const AddOpt *opt, const char* newPath) {
+ printf("Linking %s -> %s\n", opt->confPath, newPath);
+ if (util_symlink_file(newPath, opt->confPath) != 0) {
+ strcpy(engine_err, "Could not link file.");
+ }
+}
+
+void move_config(const AddOpt *opt, const Conf *conf, char *ret) {
+ char newName[STR_M];
+ str_make_new_config_name(newName, opt->confPath, opt->progName);
+ char newPath[STR_L];
+ str_join_dirname_with_basename(newPath, opt->secret ? conf->SCRT_dir : conf->VC_dir, newName);
+ printf("Moving %s -> %s\n", opt->confPath, newPath);
+ strcpy(ret, newPath);
+ if (util_move_file(opt->confPath, newPath) != 0) {
+ strcpy(engine_err, "Could not move file.");
+ }
+}
+
+void engine_add_make_link(const AddOpt *opt,
+ const Conf *conf) {
+ char newPath[STR_L];
+ move_config(opt, conf, newPath);
+ if (engine_err_message(NULL)) {
+ return;
+ }
+ link_config(opt, newPath);
+ if (engine_err_message(NULL)) {
+ return;
+ }
+}
diff --git a/src/engine.h b/src/engine.h
new file mode 100644
index 0000000..f3a3b00
--- /dev/null
+++ b/src/engine.h
@@ -0,0 +1,26 @@
+/* engine.h - manages the linking and copying of configs ---------------*- C -*-
+ *
+ * This file is part of ck, the config keeper
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2018 Anastasis Grammenos
+ * GPLv3 (see LICENCE for the full notice)
+ *
+ * -----------------------------------------------------------------------------
+ *
+ *
+ *
+ * -------------------------------------------------------------------------- */
+#include "actions.h"
+#include "ckutil.h"
+
+/* if engine_err is set return true
+ * along with a copy of the error message.
+ * Pass NULL if you don't care about the message */
+extern int engine_err_message(char *err);
+
+extern void engine_add_make_link(const AddOpt *opt,
+ const Conf *conf);
+
+
diff --git a/tests/add b/tests/add
new file mode 100644
index 0000000..e65cc77
--- /dev/null
+++ b/tests/add
@@ -0,0 +1,81 @@
+#!/bin/bash
+BIN=@CMAKE_BINARY_DIR@
+
+# initialize
+TEST_LOCATION=@PROJECT_TESTING_GROUNDS@
+mkdir -p $TEST_LOCATION/vc
+mkdir $TEST_LOCATION/sec
+
+exec $BIN/ck conf $BIN init $TEST_LOCATION/vc $TEST_LOCATION/sec &
+wait $!
+
+# setup test configs
+echo "Test 1" > $BIN/test1.conf
+echo "Test 2" > $BIN/test2.conf
+echo "Test 3" > $BIN/test3.conf
+
+# add configs to ck
+exec $BIN/ck conf $BIN add prog1 $BIN/test1.conf -p &
+wait $!
+
+# check db
+if [ $(sqlite3 $BIN/ckdb "select name from program where name = 'prog1'" | wc -l) -ne 1 ]; then
+ echo -e $ERROR"prog1 is not in the db"
+ exit 1
+fi
+
+if [ $(sqlite3 $BIN/ckdb "select path from config where path = '"$BIN"/test1.conf'" | wc -l) -ne 1 ]; then
+ echo -e $ERROR"test1.conf is not in the db"
+ exit 1
+fi
+
+# check files
+if [ ! -f $TEST_LOCATION/vc/prog1_test1.conf ]; then
+ echo -e $ERROR"test1.conf failed (add -p)"
+ exit 1
+fi
+
+# repeat
+exec $BIN/ck conf $BIN add prog2 $BIN/test2.conf -s &
+wait $!
+
+if [ ! -f $TEST_LOCATION/sec/prog2_test2.conf ]; then
+ echo -e $ERROR"test2.conf failed (add -s)"
+ exit 1
+fi
+
+if [ $(sqlite3 $BIN/ckdb "select name from program where name = 'prog2'" | wc -l) -ne 1 ]; then
+ echo -e $ERROR"prog2 is not in the db"
+ exit 1
+fi
+
+if [ $(sqlite3 $BIN/ckdb "select path from config where path = '"$BIN"/test2.conf'" | wc -l) -ne 1 ]; then
+ echo -e $ERROR"test2.conf is not in the db"
+ exit 1
+fi
+
+exec $BIN/ck conf $BIN add prog3 $BIN/test3.conf -p -s &
+wait $!
+
+if [ ! -f $TEST_LOCATION/sec/prog3_test3.conf ]; then
+ echo -e $ERROR"test3.conf failed (add -p -s)"
+ exit 1
+fi
+
+if [ $(sqlite3 $BIN/ckdb "select name from program where name = 'prog3'" | wc -l) -ne 1 ]; then
+ echo -e $ERROR"prog3 is not in the db"
+ exit 1
+fi
+
+if [ $(sqlite3 $BIN/ckdb "select path from config where path = '"$BIN"/test3.conf'" | wc -l) -ne 1 ]; then
+ echo -e $ERROR"test3.conf is not in the db"
+ exit 1
+fi
+
+rm $BIN/ckrc
+rm $BIN/ckdb
+rm $BIN/test1.conf
+rm $BIN/test2.conf
+rm $BIN/test3.conf
+rm -rf $TEST_LOCATION
+echo -e $PASS