/* * Prepare the sql statement */ static ERL_NIF_TERM esqlite_prepare(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { esqlite_connection *conn; esqlite_command *cmd = NULL; ErlNifPid pid; if(argc != 4) return enif_make_badarg(env); if(!enif_get_resource(env, argv[0], esqlite_connection_type, (void **) &conn)) return enif_make_badarg(env); if(!enif_is_ref(env, argv[1])) return make_error_tuple(env, "invalid_ref"); if(!enif_get_local_pid(env, argv[2], &pid)) return make_error_tuple(env, "invalid_pid"); cmd = command_create(); if(!cmd) return make_error_tuple(env, "command_create_failed"); cmd->type = cmd_prepare; cmd->ref = enif_make_copy(cmd->env, argv[1]); cmd->pid = pid; cmd->arg = enif_make_copy(cmd->env, argv[3]); return push_command(env, conn, cmd); }
/* * Step to a prepared statement */ static ERL_NIF_TERM esqlite_column_names(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { esqlite_statement *stmt; esqlite_command *cmd = NULL; ErlNifPid pid; if(argc != 3) return enif_make_badarg(env); if(!enif_get_resource(env, argv[0], esqlite_statement_type, (void **) &stmt)) return enif_make_badarg(env); if(!enif_is_ref(env, argv[1])) return make_error_tuple(env, "invalid_ref"); if(!enif_get_local_pid(env, argv[2], &pid)) return make_error_tuple(env, "invalid_pid"); if(!stmt->statement) return make_error_tuple(env, "no_prepared_statement"); cmd = command_create(); if(!cmd) return make_error_tuple(env, "command_create_failed"); cmd->type = cmd_column_names; cmd->ref = enif_make_copy(cmd->env, argv[1]); cmd->pid = pid; cmd->stmt = stmt->statement; if(!stmt->connection) return make_error_tuple(env, "no_connection"); if(!stmt->connection->commands) return make_error_tuple(env, "no_command_queue"); return push_command(env, stmt->connection, cmd); }
static void destruct_esqlite_connection(ErlNifEnv *env, void *arg) { esqlite_connection *db = (esqlite_connection *) arg; esqlite_command *cmd = command_create(); /* Send the stop command */ cmd->type = cmd_stop; queue_push(db->commands, cmd); queue_send(db->commands, cmd); /* Wait for the thread to finish */ enif_thread_join(db->tid, NULL); enif_thread_opts_destroy(db->opts); /* The thread has finished... now remove the command queue, and close * the datbase (if it was still open). */ queue_destroy(db->commands); if(db->db) sqlite3_close(db->db); }
/* * Open the database */ static ERL_NIF_TERM esqlite_open(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { esqlite_connection *db; esqlite_command *cmd = NULL; ErlNifPid pid; if(argc != 4) return enif_make_badarg(env); if(!enif_get_resource(env, argv[0], esqlite_connection_type, (void **) &db)) return enif_make_badarg(env); if(!enif_is_ref(env, argv[1])) return make_error_tuple(env, "invalid_ref"); if(!enif_get_local_pid(env, argv[2], &pid)) return make_error_tuple(env, "invalid_pid"); /* Note, no check is made for the type of the argument */ cmd = command_create(); if(!cmd) return make_error_tuple(env, "command_create_failed"); cmd->type = cmd_open; cmd->ref = enif_make_copy(cmd->env, argv[1]); cmd->pid = pid; cmd->arg = enif_make_copy(cmd->env, argv[3]); return push_command(env, db, cmd); }
void test_register(void) { struct external_command *ext_command = NULL; int author = 42, persistent = 0; char cmd_name[21]; int expected_command_index = 0; registered_commands_init(20); while ( expected_command_index < 60 ) { /*Verify that auto-growing the register works*/ (void)snprintf(cmd_name, 21, "ADD_HOST_COMMENT_%d", expected_command_index+1); ext_command = command_create(cmd_name, test__add_host_comment_handler, "This is a description for a command named ADD_HOST_COMMENT", NULL); command_argument_add(ext_command, "host", STRING, NULL, NULL); b_val = 0; command_argument_add(ext_command, "persistent", BOOL, &b_val, NULL); i_val = 42; command_argument_add(ext_command, "author", INTEGER, &i_val, NULL); s_val = "No comment"; command_argument_add(ext_command, "comment", STRING, s_val, NULL); ok(expected_command_index == command_register(ext_command, -1), "command registration is successful"); ok((NULL == command_argument_get_value(ext_command, "host")), "Host (null) default value saved properly"); ok(persistent == *(int *)command_argument_get_value(ext_command, "persistent"), "Persistent (bool) default value saved properly"); ok(author == *(int *)command_argument_get_value(ext_command, "author"), "Author (int) default value saved properly"); ok(!strcmp("No comment", command_argument_get_value(ext_command, "comment")), "Comment (str) default value saved properly"); ++expected_command_index; } registered_commands_deinit(); }
void update_callback(void *arg, int sqlite_operation_type, char const *sqlite_database, char const *sqlite_table, sqlite3_int64 sqlite_rowid) { esqlite_connection *db = (esqlite_connection *)arg; esqlite_command *cmd = NULL; ERL_NIF_TERM type, table, rowid; cmd = command_create(); if(db == NULL) return; if(!cmd) return; rowid = enif_make_int64(cmd->env, sqlite_rowid); table = enif_make_string(cmd->env, sqlite_table, ERL_NIF_LATIN1); switch(sqlite_operation_type) { case SQLITE_INSERT: type = make_atom(cmd->env, "insert"); break; case SQLITE_DELETE: type = make_atom(cmd->env, "delete"); break; case SQLITE_UPDATE: type = make_atom(cmd->env, "update"); break; default: return; } cmd->type = cmd_notification; cmd->arg = enif_make_tuple3(cmd->env, type, table, rowid); push_command(cmd->env, db, cmd); }
static struct stasis_app_command *exec_command_on_condition( struct stasis_app_control *control, stasis_app_command_cb command_fn, void *data, app_command_can_exec_cb can_exec_fn) { int retval; struct stasis_app_command *command; command_fn = command_fn ? : noop_cb; command = command_create(command_fn, data); if (!command) { return NULL; } ao2_lock(control->command_queue); if (can_exec_fn && (retval = can_exec_fn(control))) { ao2_unlock(control->command_queue); command_complete(command, retval); return command; } ao2_link_flags(control->command_queue, command, OBJ_NOLOCK); ast_cond_signal(&control->wait_cond); ao2_unlock(control->command_queue); return command; }
/* * Multi step to a prepared statement */ static ERL_NIF_TERM esqlite_multi_step(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) { esqlite_connection *conn; esqlite_statement *stmt; esqlite_command *cmd = NULL; ErlNifPid pid; int chunk_size = 0; if(argc != 5) return enif_make_badarg(env); if(!enif_get_resource(env, argv[0], esqlite_connection_type, (void **) &conn)) return enif_make_badarg(env); if(!enif_get_resource(env, argv[1], esqlite_statement_type, (void **) &stmt)) return enif_make_badarg(env); if(!enif_get_int(env, argv[2], &chunk_size)) return make_error_tuple(env, "invalid_chunk_size"); if(!enif_is_ref(env, argv[3])) return make_error_tuple(env, "invalid_ref"); if(!enif_get_local_pid(env, argv[4], &pid)) return make_error_tuple(env, "invalid_pid"); if(!stmt->statement) return make_error_tuple(env, "no_prepared_statement"); cmd = command_create(); if(!cmd) return make_error_tuple(env, "command_create_failed"); cmd->type = cmd_multi_step; cmd->ref = enif_make_copy(cmd->env, argv[3]); cmd->pid = pid; cmd->stmt = enif_make_copy(cmd->env, argv[1]); cmd->arg = enif_make_copy(cmd->env, argv[2]); return push_command(env, conn, cmd); }
static struct stasis_app_command *exec_command( struct stasis_app_control *control, stasis_app_command_cb command_fn, void *data) { RAII_VAR(struct stasis_app_command *, command, NULL, ao2_cleanup); command_fn = command_fn ? : noop_cb; command = command_create(command_fn, data); if (!command) { return NULL; } ao2_lock(control->command_queue); ao2_link_flags(control->command_queue, command, OBJ_NOLOCK); ast_cond_signal(&control->wait_cond); ao2_unlock(control->command_queue); ao2_ref(command, +1); return command; }
int main(int argc, char **argv) { handle_t sh_hdl; command_init(myputc); sh_hdl = shell_create(shell_work_memory, sizeof(shell_work_memory), myputc, mygetc, myexecute, myhook); if (!sh_hdl) { fprintf(stderr, "Shell Handle is NULL!\n"); return -1; } cmd_hdl = command_create(command_work_memory, sizeof(command_work_memory)); if (!cmd_hdl) { fprintf(stderr, "Command Handle is NULL!\n"); return -1; } command_add(cmd_hdl, "hello", cmd_hello, NULL); command_add(cmd_hdl, "goodbye", cmd_goodbye, NULL); shell_start(sh_hdl); return 0; }
int main(int argc, char *argv[]) { char buf[1024]; int i; #ifdef TIOCGWINSZ struct winsize ws; if (ioctl(fileno(stdout), TIOCGWINSZ, &ws) == 0 && ws.ws_col > 0) TERMWIDTH = ws.ws_col; #endif /* Start handling the arguments. * monetdb [monetdb_options] command [options] [database [...]] * this means we first scout for monetdb_options which stops as soon * as we find a non-option argument, which then must be command */ /* first handle the simple no argument case */ if (argc <= 1) { command_help(0, NULL); return(1); } /* handle monetdb_options */ for (i = 1; argc > i && argv[i][0] == '-'; i++) { switch (argv[i][1]) { case 'v': command_version(); return(0); case 'q': monetdb_quiet = 1; break; case 'h': if (strlen(&argv[i][2]) > 0) { mero_host = &argv[i][2]; } else { if (i + 1 < argc) { mero_host = argv[++i]; } else { fprintf(stderr, "monetdb: -h needs an argument\n"); return(1); } } break; case 'p': if (strlen(&argv[i][2]) > 0) { mero_port = atoi(&argv[i][2]); } else { if (i + 1 < argc) { mero_port = atoi(argv[++i]); } else { fprintf(stderr, "monetdb: -p needs an argument\n"); return(1); } } break; case 'P': /* take care we remove the password from argv so it * doesn't show up in e.g. ps -ef output */ if (strlen(&argv[i][2]) > 0) { mero_pass = strdup(&argv[i][2]); memset(&argv[i][2], 0, strlen(mero_pass)); } else { if (i + 1 < argc) { mero_pass = strdup(argv[++i]); memset(argv[i], 0, strlen(mero_pass)); } else { fprintf(stderr, "monetdb: -P needs an argument\n"); return(1); } } break; case '-': /* skip -- */ if (argv[i][2] == '\0') break; if (strcmp(&argv[i][2], "version") == 0) { command_version(); return(0); } else if (strcmp(&argv[i][2], "help") == 0) { command_help(0, NULL); return(0); } default: fprintf(stderr, "monetdb: unknown option: %s\n", argv[i]); command_help(0, NULL); return(1); break; } } /* check consistency of -h -p and -P args */ if (mero_pass != NULL && (mero_host == NULL || *mero_host == '/')) { fprintf(stderr, "monetdb: -P requires -h to be used with a TCP hostname\n"); exit(1); } else if (mero_host != NULL && *mero_host != '/' && mero_pass == NULL) { fprintf(stderr, "monetdb: -h requires -P to be used\n"); exit(1); } /* see if we still have arguments at this stage */ if (i >= argc) { command_help(0, NULL); return(1); } /* commands that do not need merovingian to be running */ if (strcmp(argv[i], "help") == 0) { command_help(argc - i, &argv[i]); return(0); } else if (strcmp(argv[i], "version") == 0) { command_version(); return(0); } /* use UNIX socket if no hostname given */ if (mero_host == NULL || *mero_host == '/') { /* a socket looks like /tmp/.s.merovingian.<tcpport>, try * finding such port. If mero_host is set, it is the location * where we should search, which defaults to '/tmp' */ if (mero_host == NULL) mero_host = "/tmp"; /* first try the port given (or else its default) */ snprintf(buf, sizeof(buf), "%s/.s.merovingian.%d", mero_host, mero_port == -1 ? 50000 : mero_port); if (control_ping(buf, -1, NULL) == 0) { mero_host = buf; } else { /* if port wasn't given, we can try and search * for available sockets */ if (mero_port == -1) { DIR *d; struct dirent *e; struct stat s; d = opendir(mero_host); if (d == NULL) { fprintf(stderr, "monetdb: cannot find a control socket, use -h and/or -p\n"); exit(1); } while ((e = readdir(d)) != NULL) { if (strncmp(e->d_name, ".s.merovingian.", 15) != 0) continue; snprintf(buf, sizeof(buf), "%s/%s", mero_host, e->d_name); if (stat(buf, &s) == -1) continue; if (S_ISSOCK(s.st_mode)) { if (control_ping(buf, -1, NULL) == 0) { mero_host = buf; break; } } } closedir(d); } } if (mero_host != buf) { fprintf(stderr, "monetdb: cannot find a control socket, use -h and/or -p\n"); exit(1); } /* don't confuse control_send lateron */ mero_port = -1; } /* for TCP connections */ if (mero_host != NULL && *mero_host != '/' && mero_port == -1) mero_port = 50000; /* handle regular commands */ if (strcmp(argv[i], "create") == 0) { command_create(argc - i, &argv[i]); } else if (strcmp(argv[i], "destroy") == 0) { command_destroy(argc - i, &argv[i]); } else if (strcmp(argv[i], "lock") == 0) { command_lock(argc - i, &argv[i]); } else if (strcmp(argv[i], "release") == 0) { command_release(argc - i, &argv[i]); } else if (strcmp(argv[i], "status") == 0) { command_status(argc - i, &argv[i]); } else if (strcmp(argv[i], "start") == 0) { command_startstop(argc - i, &argv[i], START); } else if (strcmp(argv[i], "stop") == 0) { command_startstop(argc - i, &argv[i], STOP); } else if (strcmp(argv[i], "kill") == 0) { command_startstop(argc - i, &argv[i], KILL); } else if (strcmp(argv[i], "set") == 0) { command_set(argc - i, &argv[i], SET); } else if (strcmp(argv[i], "get") == 0) { command_get(argc - i, &argv[i]); } else if (strcmp(argv[i], "inherit") == 0) { command_set(argc - i, &argv[i], INHERIT); } else if (strcmp(argv[i], "discover") == 0) { command_discover(argc - i, &argv[i]); } else { fprintf(stderr, "monetdb: unknown command: %s\n", argv[i]); command_help(0, NULL); } if (mero_pass != NULL) free(mero_pass); return(0); }
// 1. Figure out actor index, create one if it does not exist // 2. check info for evnum/evterm data int sqlite3WalOpen(sqlite3_vfs *pVfs, sqlite3_file *pDbFd, const char *zWalName,int bNoShm, i64 mxWalSize, Wal **ppWal) { MDB_val key, data; int rc; #if ATOMIC db_thread *thr = g_tsd_thread; db_connection *conn = g_tsd_conn; #else db_thread* thr = enif_tsd_get(g_tsd_thread); db_connection* conn = enif_tsd_get(g_tsd_conn); #endif mdbinf * const mdb = &thr->mdb; Wal *pWal = &conn->wal; MDB_dbi actorsdb, infodb; MDB_txn *txn = mdb->txn; int offset = 0, cutoff = 0, nmLen = 0; actorsdb = mdb->actorsdb; infodb = mdb->infodb; if (zWalName[0] == '/') offset = 1; nmLen = strlen(zWalName+offset); if (zWalName[offset+nmLen-1] == 'l' && zWalName[offset+nmLen-2] == 'a' && zWalName[offset+nmLen-3] == 'w' && zWalName[offset+nmLen-4] == '-') cutoff = 4; DBG("Wal name=%s %lld",zWalName,(i64)txn); // shorten size to ignore "-wal" at the end key.mv_size = nmLen-cutoff; key.mv_data = (void*)(zWalName+offset);//thr->curConn->dbpath; rc = mdb_get(txn,actorsdb,&key,&data); // This is new actor, assign an index if (rc == MDB_NOTFOUND) { i64 index = 0; // MDB_val key1 = {1,(void*)"?"}; #ifndef _TESTAPP_ qitem *item; db_command *cmd; item = command_create(conn->wthreadind,-1,g_pd); cmd = (db_command*)item->cmd; cmd->type = cmd_actorsdb_add; #if ATOMIC index = atomic_fetch_add_explicit(&g_pd->actorIndexes[thr->nEnv], 1, memory_order_relaxed); #else enif_mutex_lock(g_pd->actorIndexesMtx[thr->nEnv]); index = g_pd->actorIndexes[thr->nEnv]++; enif_mutex_unlock(g_pd->actorIndexesMtx[thr->nEnv]); #endif pWal->index = index; cmd->arg = enif_make_string(item->env,zWalName,ERL_NIF_LATIN1); cmd->arg1 = enif_make_uint64(item->env, index); push_command(conn->wthreadind, -1, g_pd, item); #else if (thr->isreadonly) { return SQLITE_ERROR; } else { #if ATOMIC char filename[MAX_PATHNAME]; sprintf(filename,"%.*s",(int)(nmLen-cutoff),zWalName+offset); index = atomic_fetch_add_explicit(&g_pd->actorIndexes[thr->nEnv], 1, memory_order_relaxed); pWal->index = index; if (register_actor(index, filename) != SQLITE_OK) return SQLITE_ERROR; #else return SQLITE_ERROR; #endif } #endif } // Actor exists, read evnum/evterm info else if (rc == MDB_SUCCESS) { // data contains index key = data; pWal->index = *(i64*)data.mv_data; DBG("Actor at index %lld",pWal->index); rc = mdb_get(txn,infodb,&key,&data); if (rc == MDB_SUCCESS) { if (*(u8*)data.mv_data != 1) { return SQLITE_ERROR; } memcpy(&pWal->firstCompleteTerm, ((u8*)data.mv_data)+1, sizeof(u64)); memcpy(&pWal->firstCompleteEvnum,((u8*)data.mv_data)+1+sizeof(u64), sizeof(u64)); memcpy(&pWal->lastCompleteTerm, ((u8*)data.mv_data)+1+sizeof(u64)*2, sizeof(u64)); memcpy(&pWal->lastCompleteEvnum, ((u8*)data.mv_data)+1+sizeof(u64)*3, sizeof(u64)); memcpy(&pWal->inProgressTerm, ((u8*)data.mv_data)+1+sizeof(u64)*4, sizeof(u64)); memcpy(&pWal->inProgressEvnum, ((u8*)data.mv_data)+1+sizeof(u64)*5, sizeof(u64)); memcpy(&pWal->mxPage, ((u8*)data.mv_data)+1+sizeof(u64)*6, sizeof(u32)); memcpy(&pWal->allPages, ((u8*)data.mv_data)+1+sizeof(u64)*6+sizeof(u32),sizeof(u32)); pWal->readSafeTerm = pWal->lastCompleteTerm; pWal->readSafeEvnum = pWal->lastCompleteEvnum; pWal->readSafeMxPage = pWal->mxPage; // if (pWal->inProgressTerm != 0) // { // doundo(pWal,NULL,NULL,1); // } } else if (rc == MDB_NOTFOUND) { // DBG("Info for actor not found")); } } else { DBG("Error open=%d",rc); thr->forceCommit = 2; return SQLITE_ERROR; } conn->changed = 1; if (ppWal != NULL) (*ppWal) = pWal; return SQLITE_OK; }
int main(int argc, char *argv[]) { err e; int argp; char dbfarm[1024]; char *pidfilename = NULL; char *p; FILE *pidfile = NULL; char control_usock[1024]; char mapi_usock[1024]; dpair d = NULL; struct _dpair dpcons; struct _dpair dpmero; struct _dpair dpdisc; struct _dpair dpcont; int pfd[2]; pthread_t tid = 0; struct sigaction sa; int ret; int lockfd = -1; int sock = -1; int usock = -1; int unsock = -1; int socku = -1; unsigned short port = 0; char discovery = 0; struct stat sb; FILE *oerr = NULL; pthread_mutexattr_t mta; int thret; char merodontfork = 0; confkeyval ckv[] = { {"logfile", strdup("merovingian.log"), 0, STR}, {"pidfile", strdup("merovingian.pid"), 0, STR}, {"sockdir", strdup("/tmp"), 0, STR}, {"port", strdup(MERO_PORT), atoi(MERO_PORT), INT}, {"exittimeout", strdup("60"), 60, INT}, {"forward", strdup("proxy"), 0, OTHER}, {"discovery", strdup("true"), 1, BOOLEAN}, {"discoveryttl", strdup("600"), 600, INT}, {"control", strdup("false"), 0, BOOLEAN}, {"passphrase", NULL, 0, STR}, { NULL, NULL, 0, INVALID} }; confkeyval *kv; int retfd = -1; /* seed the randomiser for when we create a database, send responses * to HELO, etc */ srand(time(NULL)); /* figure out our hostname */ gethostname(_mero_hostname, 128); /* where is the mserver5 binary we fork on demand? * first try to locate it based on our binary location, fall-back to * hardcoded bin-dir */ _mero_mserver = get_bin_path(); if (_mero_mserver != NULL) { /* replace the trailing monetdbd by mserver5, fits nicely since * they happen to be of same length */ char *s = strrchr(_mero_mserver, '/'); if (s != NULL && strcmp(s + 1, "monetdbd") == 0) { s++; *s++ = 'm'; *s++ = 's'; *s++ = 'e'; *s++ = 'r'; *s++ = 'v'; *s++ = 'e'; *s++ = 'r'; *s++ = '5'; if (stat(_mero_mserver, &sb) == -1) _mero_mserver = NULL; } } /* setup default database properties, constants: unlike historical * versions, we do not want changing defaults any more */ _mero_db_props = getDefaultProps(); kv = findConfKey(_mero_db_props, "shared"); kv->val = strdup("yes"); kv = findConfKey(_mero_db_props, "readonly"); kv->val = strdup("no"); kv = findConfKey(_mero_db_props, "nclients"); kv->val = strdup("64"); kv = findConfKey(_mero_db_props, "type"); kv->val = strdup("database"); kv = findConfKey(_mero_db_props, "optpipe"); kv->val = strdup("default_pipe"); { /* nrthreads */ int ncpus = -1; char cnt[8]; #if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN) /* this works on Linux, Solaris and AIX */ ncpus = sysconf(_SC_NPROCESSORS_ONLN); #elif defined(HAVE_SYS_SYSCTL_H) && defined(HW_NCPU) /* BSD */ size_t len = sizeof(int); int mib[3]; /* Everyone should have permission to make this call, * if we get a failure something is really wrong. */ mib[0] = CTL_HW; mib[1] = HW_NCPU; mib[2] = -1; sysctl(mib, 3, &ncpus, &len, NULL, 0); #elif defined(WIN32) SYSTEM_INFO sysinfo; GetSystemInfo(&sysinfo); ncpus = sysinfo.dwNumberOfProcessors; #endif if (ncpus > 0) { snprintf(cnt, sizeof(cnt), "%d", ncpus); kv = findConfKey(_mero_db_props, "nthreads"); kv->val = strdup(cnt); } } *dbfarm = '\0'; if (argc > 1) { if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "help") == 0) { exit(command_help(argc - 1, &argv[1])); } else if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-v") == 0 || strcmp(argv[1], "version") == 0) { exit(command_version()); } else if (strcmp(argv[1], "create") == 0) { exit(command_create(argc - 1, &argv[1])); } else if (strcmp(argv[1], "get") == 0) { exit(command_get(ckv, argc - 1, &argv[1])); } else if (strcmp(argv[1], "set") == 0) { exit(command_set(ckv, argc - 1, &argv[1])); } else if (strcmp(argv[1], "start") == 0) { if (argc > 3 && strcmp(argv[2], "-n") == 0) merodontfork = 1; if (argc == 3 + merodontfork) { int len; len = snprintf(dbfarm, sizeof(dbfarm), "%s", argv[2 + merodontfork]); if (len > 0 && (size_t)len >= sizeof(dbfarm)) { Mfprintf(stderr, "fatal: dbfarm exceeds allocated " \ "path length, please file a bug at " \ "http://bugs.monetdb.org/\n"); exit(1); } } else { command_help(argc, argv); exit(1); } } else if (strcmp(argv[1], "stop") == 0) { exit(command_stop(ckv, argc - 1, &argv[1])); } else { fprintf(stderr, "monetdbd: unknown command: %s\n", argv[1]); command_help(0, NULL); exit(1); } } else { command_help(0, NULL); exit(1); } assert(*dbfarm != '\0'); /* fork into background before doing anything more */ if (!merodontfork) { char buf[4]; /* Fork into the background immediately. By doing this our child * can simply do everything it needs to do itself. Via a pipe it * will tell us if it is happy or not. */ if (pipe(pfd) == -1) { Mfprintf(stderr, "unable to create pipe: %s\n", strerror(errno)); return(1); } switch (fork()) { case -1: /* oops, forking went wrong! */ Mfprintf(stderr, "unable to fork into background: %s\n", strerror(errno)); return(1); case 0: /* detach client from controlling tty, we only write to the * pipe to daddy */ if (setsid() < 0) Mfprintf(stderr, "hmmm, can't detach from controlling tty, " "continuing anyway\n"); retfd = open("/dev/null", O_RDONLY); dup2(retfd, 0); close(retfd); close(pfd[0]); /* close unused read end */ retfd = pfd[1]; /* store the write end */ break; default: /* the parent, we want it to die, after we know the child * has a good time */ close(pfd[1]); /* close unused write end */ if (read(pfd[0], &buf, 1) != 1) { Mfprintf(stderr, "unable to retrieve startup status\n"); return(1); } close(pfd[0]); return(buf[0]); /* whatever the child returned, we return */ } } /* use after the logger thread has started */ #define MERO_EXIT(status) if (!merodontfork) { \ char s = status; \ if (write(retfd, &s, 1) != 1 || close(retfd) != 0) { \ Mfprintf(stderr, "could not write to parent\n"); \ } \ if (status != 0) { \ Mfprintf(stderr, "fatal startup condition encountered, " \ "aborting startup\n"); \ goto shutdown; \ } \ } else { \ if (status != 0) { \ Mfprintf(stderr, "fatal startup condition encountered, " \ "aborting startup\n"); \ goto shutdown; \ } \ } /* use before logger thread has started */ #define MERO_EXIT_CLEAN(status) if (!merodontfork) { \ char s = status; \ if (write(retfd, &s, 1) != 1 || close(retfd) != 0) { \ Mfprintf(stderr, "could not write to parent\n"); \ } \ exit(s); \ } else { \ exit(status); \ } /* check if dbfarm actually exists */ if (stat(dbfarm, &sb) == -1) { Mfprintf(stderr, "dbfarm directory '%s' does not exist, " "use monetdbd create first\n", dbfarm); MERO_EXIT_CLEAN(1); } /* chdir to dbfarm so we are at least in a known to exist location */ if (chdir(dbfarm) < 0) { Mfprintf(stderr, "could not move to dbfarm '%s': %s\n", dbfarm, strerror(errno)); MERO_EXIT_CLEAN(1); } /* absolutise dbfarm if it isn't yet (we're in it now) */ if (dbfarm[0] != '/') { if (getcwd(dbfarm, sizeof(dbfarm)) == NULL) { if (errno == ERANGE) { Mfprintf(stderr, "current path exceeds allocated path length" \ "please file a bug at http://bugs.monetdb.org\n"); } else { Mfprintf(stderr, "could not get dbfarm working directory: %s\n", strerror(errno)); } MERO_EXIT_CLEAN(1); } } if (_mero_mserver == NULL) { _mero_mserver = BINDIR "/mserver5"; if (stat(_mero_mserver, &sb) == -1) { /* exit early if this is not going to work well */ Mfprintf(stderr, "cannot stat %s executable: %s\n", _mero_mserver, strerror(errno)); MERO_EXIT_CLEAN(1); } } /* read the merovingian properties from the dbfarm */ if (readProps(ckv, ".") != 0) { Mfprintf(stderr, "cannot find or read properties file, was " "this dbfarm created by `monetdbd create`?\n"); MERO_EXIT_CLEAN(1); } _mero_props = ckv; pidfilename = getConfVal(_mero_props, "pidfile"); p = getConfVal(_mero_props, "forward"); if (strcmp(p, "redirect") != 0 && strcmp(p, "proxy") != 0) { Mfprintf(stderr, "invalid forwarding mode: %s, defaulting to proxy\n", p); kv = findConfKey(_mero_props, "forward"); setConfVal(kv, "proxy"); writeProps(_mero_props, "."); } kv = findConfKey(_mero_props, "port"); if (kv->ival <= 0 || kv->ival > 65535) { Mfprintf(stderr, "invalid port number: %s, defaulting to %s\n", kv->val, MERO_PORT); setConfVal(kv, MERO_PORT); writeProps(_mero_props, "."); } port = (unsigned short)kv->ival; discovery = getConfNum(_mero_props, "discovery"); /* check and trim the hash-algo from the passphrase for easy use * lateron */ kv = findConfKey(_mero_props, "passphrase"); if (kv->val != NULL) { char *h = kv->val + 1; if ((p = strchr(h, '}')) == NULL) { Mfprintf(stderr, "warning: incompatible passphrase (not hashed as " MONETDB5_PASSWDHASH "), disabling passphrase\n"); } else { *p = '\0'; if (strcmp(h, MONETDB5_PASSWDHASH) != 0) { Mfprintf(stderr, "warning: passphrase hash '%s' incompatible, " "expected '%s', disabling passphrase\n", h, MONETDB5_PASSWDHASH); } else { setConfVal(kv, p + 1); } } } /* set up UNIX socket paths for control and mapi */ p = getConfVal(_mero_props, "sockdir"); snprintf(control_usock, sizeof(control_usock), "%s/" CONTROL_SOCK "%d", p, port); snprintf(mapi_usock, sizeof(control_usock), "%s/" MERO_SOCK "%d", p, port); /* lock such that we are alone on this world */ if ((lockfd = MT_lockf(".merovingian_lock", F_TLOCK, 4, 1)) == -1) { /* locking failed */ Mfprintf(stderr, "another monetdbd is already running\n"); MERO_EXIT_CLEAN(1); } else if (lockfd == -2) { /* directory or something doesn't exist */ Mfprintf(stderr, "unable to create %s/.merovingian_lock file: %s\n", dbfarm, strerror(errno)); MERO_EXIT_CLEAN(1); } _mero_topdp = &dpcons; _mero_topdp->pid = 0; _mero_topdp->type = MERO; _mero_topdp->dbname = NULL; /* where should our msg output go to? */ p = getConfVal(_mero_props, "logfile"); /* write to the given file */ _mero_topdp->out = open(p, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR); if (_mero_topdp->out == -1) { Mfprintf(stderr, "unable to open '%s': %s\n", p, strerror(errno)); MT_lockf(".merovingian_lock", F_ULOCK, 4, 1); close(lockfd); MERO_EXIT_CLEAN(1); } _mero_topdp->err = _mero_topdp->out; _mero_logfile = fdopen(_mero_topdp->out, "a"); d = _mero_topdp->next = &dpmero; /* redirect stdout */ if (pipe(pfd) == -1) { Mfprintf(stderr, "unable to create pipe: %s\n", strerror(errno)); MERO_EXIT(1); } d->out = pfd[0]; dup2(pfd[1], 1); close(pfd[1]); /* redirect stderr */ if (pipe(pfd) == -1) { Mfprintf(stderr, "unable to create pipe: %s\n", strerror(errno)); MERO_EXIT(1); } /* before it is too late, save original stderr */ oerr = fdopen(dup(2), "w"); d->err = pfd[0]; dup2(pfd[1], 2); close(pfd[1]); d->pid = getpid(); d->type = MERO; d->dbname = "merovingian"; /* separate entry for the neighbour discovery service */ d = d->next = &dpdisc; if (pipe(pfd) == -1) { Mfprintf(stderr, "unable to create pipe: %s\n", strerror(errno)); MERO_EXIT(1); } d->out = pfd[0]; _mero_discout = fdopen(pfd[1], "a"); if (pipe(pfd) == -1) { Mfprintf(stderr, "unable to create pipe: %s\n", strerror(errno)); MERO_EXIT(1); } d->err = pfd[0]; _mero_discerr = fdopen(pfd[1], "a"); d->pid = getpid(); d->type = MERO; d->dbname = "discovery"; d->next = NULL; /* separate entry for the control runner */ d = d->next = &dpcont; if (pipe(pfd) == -1) { Mfprintf(stderr, "unable to create pipe: %s\n", strerror(errno)); MERO_EXIT(1); } d->out = pfd[0]; _mero_ctlout = fdopen(pfd[1], "a"); if (pipe(pfd) == -1) { Mfprintf(stderr, "unable to create pipe: %s\n", strerror(errno)); MERO_EXIT(1); } d->err = pfd[0]; _mero_ctlerr = fdopen(pfd[1], "a"); d->pid = getpid(); d->type = MERO; d->dbname = "control"; d->next = NULL; /* allow a thread to relock this mutex */ pthread_mutexattr_init(&mta); pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&_mero_topdp_lock, &mta); if ((thret = pthread_create(&tid, NULL, (void *(*)(void *))logListener, (void *)NULL)) != 0) { Mfprintf(oerr, "%s: FATAL: unable to create logthread: %s\n", argv[0], strerror(thret)); MERO_EXIT(1); } sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sa.sa_handler = handler; if ( sigaction(SIGINT, &sa, NULL) == -1 || sigaction(SIGQUIT, &sa, NULL) == -1 || sigaction(SIGTERM, &sa, NULL) == -1) { Mfprintf(oerr, "%s: FATAL: unable to create signal handlers: %s\n", argv[0], strerror(errno)); MERO_EXIT(1); } sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sa.sa_handler = huphandler; if (sigaction(SIGHUP, &sa, NULL) == -1) { Mfprintf(oerr, "%s: FATAL: unable to create signal handlers: %s\n", argv[0], strerror(errno)); MERO_EXIT(1); } sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sa.sa_handler = segvhandler; if (sigaction(SIGSEGV, &sa, NULL) == -1) { Mfprintf(oerr, "%s: FATAL: unable to create signal handlers: %s\n", argv[0], strerror(errno)); MERO_EXIT(1); } sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sa.sa_handler = SIG_IGN; if (sigaction(SIGPIPE, &sa, NULL) == -1) { Mfprintf(oerr, "%s: FATAL: unable to create signal handlers: %s\n", argv[0], strerror(errno)); MERO_EXIT(1); } sa.sa_flags = SA_SIGINFO; sigemptyset(&sa.sa_mask); sa.sa_sigaction = childhandler; if (sigaction(SIGCHLD, &sa, NULL) == -1) { Mfprintf(oerr, "%s: FATAL: unable to create signal handlers: %s\n", argv[0], strerror(errno)); MERO_EXIT(1); } /* make sure we will be able to write our pid */ if ((pidfile = fopen(pidfilename, "w")) == NULL) { Mfprintf(stderr, "unable to open '%s%s%s' for writing: %s\n", pidfilename[0] != '/' ? dbfarm : "", pidfilename[0] != '/' ? "/" : "", pidfilename, strerror(errno)); MERO_EXIT(1); } msab_dbfarminit(dbfarm); /* write out the pid */ Mfprintf(pidfile, "%d\n", (int)d->pid); fclose(pidfile); Mfprintf(stdout, "Merovingian %s (%s) starting\n", MERO_VERSION, MONETDB_RELEASE); Mfprintf(stdout, "monitoring dbfarm %s\n", dbfarm); /* open up connections */ if ( (e = openConnectionTCP(&sock, port, stdout)) == NO_ERR && /* coverity[operator_confusion] */ (unlink(control_usock) | unlink(mapi_usock) | 1) && (e = openConnectionUNIX(&socku, mapi_usock, 0, stdout)) == NO_ERR && (discovery == 0 || (e = openConnectionUDP(&usock, port)) == NO_ERR) && (e = openConnectionUNIX(&unsock, control_usock, S_IRWXO, _mero_ctlout)) == NO_ERR ) { pthread_t ctid = 0; pthread_t dtid = 0; if (discovery == 1) { _mero_broadcastsock = socket(AF_INET, SOCK_DGRAM, 0); ret = 1; if ((setsockopt(_mero_broadcastsock, SOL_SOCKET, SO_BROADCAST, &ret, sizeof(ret))) == -1) { Mfprintf(stderr, "cannot create broadcast package, " "discovery services disabled\n"); close(usock); usock = -1; } _mero_broadcastaddr.sin_family = AF_INET; _mero_broadcastaddr.sin_addr.s_addr = htonl(INADDR_BROADCAST); /* the target port is our configured port, not elegant, but how * else can we do it? can't broadcast to all ports or something */ _mero_broadcastaddr.sin_port = htons(port); } /* From this point merovingian considers itself to be in position to * start running, so flag the parent we will have fun. */ MERO_EXIT(0); /* Paranoia umask, but good, because why would people have to sniff * our private parts? */ umask(S_IRWXG | S_IRWXO); /* handle control commands */ if ((thret = pthread_create(&ctid, NULL, (void *(*)(void *))controlRunner, (void *)&unsock)) != 0) { Mfprintf(stderr, "unable to create control command thread: %s\n", strerror(thret)); ctid = 0; } /* start neighbour discovery and notification thread */ if (usock >= 0 && (thret = pthread_create(&dtid, NULL, (void *(*)(void *))discoveryRunner, (void *)&usock)) != 0) { Mfprintf(stderr, "unable to start neighbour discovery thread: %s\n", strerror(thret)); dtid = 0; } /* handle external connections main loop */ e = acceptConnections(sock, socku); /* wait for the control runner and discovery thread to have * finished announcing they're going down */ close(unsock); if (ctid != 0) pthread_join(ctid, NULL); if (usock >= 0) { close(usock); if (dtid != 0) pthread_join(dtid, NULL); } } /* control channel is already closed at this point */ if (unsock != -1 && unlink(control_usock) == -1) Mfprintf(stderr, "unable to unlink control socket '%s': %s\n", control_usock, strerror(errno)); if (socku != -1 && unlink(mapi_usock) == -1) Mfprintf(stderr, "unable to unlink mapi socket '%s': %s\n", mapi_usock, strerror(errno)); if (e != NO_ERR) { /* console */ Mfprintf(oerr, "%s: %s\n", argv[0], e); /* logfile */ Mfprintf(stderr, "%s\n", e); MERO_EXIT(1); } shutdown: /* stop started mservers */ kv = findConfKey(ckv, "exittimeout"); if (d->next != NULL && atoi(kv->val) > 0) { dpair t; threadlist tl = NULL, tlw = tl; pthread_mutex_lock(&_mero_topdp_lock); t = d->next; while (t != NULL) { if (tl == NULL) { tl = tlw = malloc(sizeof(struct _threadlist)); } else { tlw = tlw->next = malloc(sizeof(struct _threadlist)); } tlw->next = NULL; if ((thret = pthread_create(&(tlw->tid), NULL, (void *(*)(void *))terminateProcess, (void *)t)) != 0) { Mfprintf(stderr, "%s: unable to create thread to terminate " "database '%s': %s\n", argv[0], t->dbname, strerror(thret)); tlw->tid = 0; } t = t->next; } pthread_mutex_unlock(&_mero_topdp_lock); /* wait for all processes to be terminated */ tlw = tl; while (tlw != NULL) { if (tlw->tid != 0 && (argp = pthread_join(tlw->tid, NULL)) != 0) { Mfprintf(stderr, "failed to wait for termination thread: " "%s\n", strerror(argp)); } tl = tlw->next; free(tlw); tlw = tl; } } /* need to do this here, since the logging thread is shut down as * next thing */ Mfprintf(stdout, "Merovingian %s stopped\n", MERO_VERSION); _mero_keep_logging = 0; if (tid != 0 && (argp = pthread_join(tid, NULL)) != 0) { Mfprintf(oerr, "failed to wait for logging thread: %s\n", strerror(argp)); } if (_mero_topdp != NULL) { close(_mero_topdp->out); if (_mero_topdp->out != _mero_topdp->err) close(_mero_topdp->err); } /* remove files that suggest our existence */ unlink(".merovingian_lock"); if (pidfilename != NULL) { unlink(pidfilename); free(pidfilename); } /* mostly for valgrind... */ freeConfFile(ckv); if (_mero_db_props != NULL) { freeConfFile(_mero_db_props); free(_mero_db_props); } if (lockfd >= 0) { MT_lockf(".merovingian_lock", F_ULOCK, 4, 1); close(lockfd); } /* the child's return code at this point doesn't matter, as noone * will see it */ return(0); }
void test_parsing(void) { struct external_command *ext_command = NULL; contact *created_contact = NULL; contact *fetched_contact = NULL; const char *cmdstr = "[1234567890] ADD_HOST_COMMENT;my_host;0;15;this is my comment, there are many like it but this one is mine"; registered_commands_init(20); { g_clear_error(&error); ok(NULL == command_parse(cmdstr, COMMAND_SYNTAX_NOKV, &error), "We can't parse commands when none are registered"); ok(g_error_matches(error, NM_COMMAND_ERROR, CMD_ERROR_UNKNOWN_COMMAND), "The error code looks like expected"); ext_command = command_create("ADD_HOST_COMMENT", test__add_host_comment_handler, "This is a description for a command named ADD_HOST_COMMENT", NULL); command_argument_add(ext_command, "host", STRING, NULL, NULL); b_val = 0; command_argument_add(ext_command, "persistent", BOOL, &b_val, NULL); i_val = 42; command_argument_add(ext_command, "author", INTEGER, &i_val, NULL); s_val = "No comment"; command_argument_add(ext_command, "comment", STRING, s_val, NULL); command_register(ext_command, -1); g_clear_error(&error); ext_command = command_parse("[] UNKNOWN_COMMAND", COMMAND_SYNTAX_NOKV, &error); ok(g_error_matches(error, NM_COMMAND_ERROR, CMD_ERROR_MALFORMED_COMMAND), "Malformed command error is raised for malformed commands"); ok(NULL == ext_command, "No command returned for malformed command"); g_clear_error(&error); ext_command = command_parse("[UNKNOWN_COMMAND", COMMAND_SYNTAX_NOKV, &error); ok(g_error_matches(error, NM_COMMAND_ERROR, CMD_ERROR_MALFORMED_COMMAND), "Malformed command error is raised for malformed commands"); ok(NULL == ext_command, "No command returned for malformed command"); g_clear_error(&error); ext_command = command_parse("[139414354] UNKNOWN_COMMAND", COMMAND_SYNTAX_NOKV, &error); ok(g_error_matches(error, NM_COMMAND_ERROR, CMD_ERROR_UNKNOWN_COMMAND), "Unknown command error is raised for unknown commands"); ok(NULL == ext_command, "No command returned for unknown command"); g_clear_error(&error); ext_command = command_parse(cmdstr, COMMAND_SYNTAX_NOKV, &error); ok(error == NULL, "The command parses without error"); ok(!strcmp("my_host", command_argument_get_value(ext_command, "host")), "Host value parsed successfully"); ok(0 == *(int *)command_argument_get_value(ext_command, "persistent"), "Persistent value parsed successfully"); ok(15 == *(int *)command_argument_get_value(ext_command, "author"), "Author value parsed successfully"); ok(!strcmp("this is my comment, there are many like it but this one is mine", command_argument_get_value(ext_command, "comment")), "Comment value parsed successfully"); command_destroy(ext_command); g_clear_error(&error); ext_command = command_parse("[1234567890] ADD_HOST_COMMENT;my_host;0;15;this is my newline\n, there are many like it but this one is\n m\ni\nn\ne", COMMAND_SYNTAX_NOKV, &error); ok(error == NULL, "Command containing newlines parses without error"); ok(!strcmp("this is my newline\n, there are many like it but this one is\n m\ni\nn\ne", command_argument_get_value(ext_command, "comment")), "Comment containing newlines parsed successfully"); command_destroy(ext_command); g_clear_error(&error); ext_command = command_parse(cmdstr, COMMAND_SYNTAX_NOKV, &error); ok(0 == command_execute_handler(ext_command), "Callback exit value properly passed on"); ok(!strcmp("my_host", received_host), "Host value passed to callback"); ok(0 == *received_persistent, "Persistent value passed to callback"); ok(received_entry_time == 1234567890, "Entry time passed correctly to callback"); command_destroy(ext_command); free(received_host); free(received_persistent); g_clear_error(&error); ext_command = command_parse("[1234567890] ADD_HOST_COMMENT;;1", COMMAND_SYNTAX_NOKV, &error); ok(g_error_matches(error, NM_COMMAND_ERROR, CMD_ERROR_PARSE_MISSING_ARG), "Missing arguments are complained about"); ok(ext_command == NULL, "No command returned for command with missing arguments"); g_clear_error(&error); ext_command = command_parse("[15341345] ADD_HOST_COMMENT", COMMAND_SYNTAX_NOKV, &error); ok(g_error_matches(error, NM_COMMAND_ERROR, CMD_ERROR_PARSE_MISSING_ARG), "Missing arguments are complained about (no arguments supplied)"); ok(ext_command == NULL, "No command returned for command with missing arguments"); g_clear_error(&error); ext_command = command_parse("[1234567890] ADD_HOST_COMMENT;my_host;0;441;this is my comment, there are many like it but this one is mine;Post-semi-colon stuff", COMMAND_SYNTAX_NOKV, &error); ok(error == NULL, "Last string argument may contain semi-colons"); ok(ext_command != NULL, "A command should be returned when last string-argument has semi-colons"); command_destroy(ext_command); g_clear_error(&error); ext_command = command_parse("[1234567890] ADD_HOST_COMMENT;my_host;0;Dora the Explora';this is my comment, there are many like it but this one is mine", COMMAND_SYNTAX_NOKV, &error); ok(g_error_matches(error, NM_COMMAND_ERROR, CMD_ERROR_PARSE_TYPE_MISMATCH), "Type errors are complained about"); ok(ext_command == NULL, "No command returned for command with argument type errors"); g_clear_error(&error); ext_command = command_parse("[1234567890] ADD_HOST_COMMENT;my_host;1;4lyfe;this is my comment, there are many like it but this one is mine", COMMAND_SYNTAX_NOKV, &error); ok(g_error_matches(error, NM_COMMAND_ERROR, CMD_ERROR_PARSE_TYPE_MISMATCH), "Junk characters after integer arguments are complained about"); ok(ext_command == NULL, "No command returned for command with argument type mismatch errors"); g_clear_error(&error); ext_command = command_create("ADD_HOST_COMMENT_WITH_TIMESTAMP", test__add_host_comment_handler, "This is a description for a command named ADD_HOST_COMMENT", NULL); command_argument_add(ext_command, "host", STRING, NULL, NULL); command_argument_add(ext_command, "persistent", BOOL, NULL, NULL); i_val = 42; command_argument_add(ext_command, "author", INTEGER, &i_val, NULL); s_val = "No comment"; command_argument_add(ext_command, "comment", STRING, s_val, NULL); t_val = 0; command_argument_add(ext_command, "timestamp", TIMESTAMP, &t_val, NULL); command_register(ext_command, -1); g_clear_error(&error); ext_command = command_parse("[1234567890] ADD_HOST_COMMENT_WITH_TIMESTAMP;my_host;1;441;this is my comment, there are many like it but this one is mine;1234987650", COMMAND_SYNTAX_NOKV, &error); ok(error == NULL, "No error when parsing proper commands"); ok(1234987650 == *(time_t *)command_argument_get_value(ext_command, "timestamp"), "Timestamp value parsed successfully"); command_destroy(ext_command); g_clear_error(&error); ext_command = command_parse("[1234567890] ADD_HOST_COMMENT_WITH_TIMESTAMP;my_host;4;441;this is my comment, there are many like it but this one is mine;1234987650", COMMAND_SYNTAX_NOKV, &error); ok(g_error_matches(error, NM_COMMAND_ERROR, CMD_ERROR_VALIDATION_FAILURE), "Invalid BOOL value (4) is complained about"); ok(NULL == ext_command, "No command returned for command with invalid argument values"); g_clear_error(&error); ext_command = command_parse("[1234567890] ADD_HOST_COMMENT_WITH_TIMESTAMP;my_host;1;441;this is my comment, there are many like it but this one is mine;14:49", COMMAND_SYNTAX_NOKV, &error); ok(g_error_matches(error, NM_COMMAND_ERROR, CMD_ERROR_PARSE_TYPE_MISMATCH), "Malformed timestamp value is complained about"); ok(NULL == ext_command, "No command returned for command with argument type mismatch"); g_clear_error(&error); ext_command = command_parse("[1234567890] ADD_HOST_COMMENT_WITH_TIMESTAMP;my_host;1;441;;", COMMAND_SYNTAX_NOKV, &error); ok(error == NULL, "Missing arguments which have default values are not complained about"); ok(!strcmp("No comment", command_argument_get_value(ext_command, "comment")), "Default value is used for missing argument"); ok(t_val == *(time_t *)command_argument_get_value(ext_command, "timestamp"), "Default value is used for missing argument at end of arg string"); command_destroy(ext_command); g_clear_error(&error); ext_command = command_parse("[1234567890] ADD_HOST_COMMENT_WITH_TIMESTAMP;some_host;;441;;13485799", COMMAND_SYNTAX_NOKV, &error); ok(g_error_matches(error, NM_COMMAND_ERROR, CMD_ERROR_PARSE_MISSING_ARG), "Missing arguments which don't have default values are complained about"); ok(NULL == ext_command, "No command returned for command with missing argument and no default"); g_clear_error(&error); ext_command = command_create("ADD_SVC_COMMENT", test__add_service_comment_handler, "This is a description for a command named CMD_ADD_SVC_COMMENT", NULL); command_argument_add(ext_command, "service", SERVICE, NULL, NULL); command_argument_add(ext_command, "persistent", BOOL, &b_val, NULL); command_argument_add(ext_command, "author", INTEGER, &i_val, NULL); command_argument_add(ext_command, "comment", STRING, s_val, NULL); command_register(ext_command, -1); g_clear_error(&error); ext_command = command_parse("[1234567890] ADD_SVC_COMMENT;my_host;NO_SUCH_SERVICE;1;441;this is my service comment, there are many like it but this one is mine", COMMAND_SYNTAX_NOKV, &error); ok(g_error_matches(error, NM_COMMAND_ERROR, CMD_ERROR_VALIDATION_FAILURE), "Invalid service is complained about"); ok(NULL == ext_command, "No command returned for command with invalid service"); g_clear_error(&error); ext_command = command_create("ADD_SVC_COMMENT_2", test__add_service_comment_handler, "This is a description for a command with a custom service validator", NULL); command_argument_add(ext_command, "service", SERVICE, NULL, custom_service_validator); command_argument_add(ext_command, "persistent", BOOL, &b_val, NULL); command_argument_add(ext_command, "author", INTEGER, &i_val, NULL); command_argument_add(ext_command, "comment", STRING, s_val, NULL); command_register(ext_command, -1); g_clear_error(&error); ext_command = command_parse("[1234567890] ADD_SVC_COMMENT_2;my_host;LETS_PRETEND_THIS_EXISTS;1;441;this is my service comment, there are many like it but this one is mine", COMMAND_SYNTAX_NOKV, &error); ok(error == NULL, "Custom validator does not decline our invalid service"); command_destroy(ext_command); g_clear_error(&error); ext_command = command_create("DEL_HOST_COMMENT", test__del_host_comment_handler, "This command is used to delete a specific host comment.", NULL); command_argument_add(ext_command, "comment_id", ULONG, NULL, NULL); command_register(ext_command, -1); g_clear_error(&error); ext_command = command_parse("[1234567890] DEL_HOST_COMMENT;10;Excess argument;snurre", COMMAND_SYNTAX_NOKV, &error); ok(g_error_matches(error, NM_COMMAND_ERROR, CMD_ERROR_PARSE_EXCESS_ARG), "Excess arguments are complained about"); ok(ext_command == NULL, "No command returned for commands with excess arguments"); g_clear_error(&error); ext_command = command_parse("[1234567890] DEL_HOST_COMMENT;10", COMMAND_SYNTAX_NOKV, &error); ok((unsigned long) 10 == *(unsigned long *)command_argument_get_value(ext_command, "comment_id"), "ULONG argument parsed correctly"); command_destroy(ext_command); ext_command = command_create("DEL_HOST_COMMENT_2", test__del_host_comment_handler, "This command is used to delete a specific host comment.", "int=comment_id;str=string_arg"); command_register(ext_command, -1); g_clear_error(&error); ext_command = command_parse("[1234567890] DEL_HOST_COMMENT_2;10;foobar", COMMAND_SYNTAX_NOKV, &error); ok(error == NULL, "No error when parsing command created with argspec"); ok(!strcmp("foobar", command_argument_get_value(ext_command, "string_arg")), "Can parse command created with argspec (string arg)"); ok(10 == *(int *)command_argument_get_value(ext_command, "comment_id"), "Can parse command created with argspec (int arg)"); command_destroy(ext_command); g_clear_error(&error); ext_command = command_parse("[1234567890] DEL_HOST_COMMENT_2;1;", COMMAND_SYNTAX_NOKV, &error); ok (ext_command == NULL, "Missing argument at end of arg string is complained about"); ok(g_error_matches(error, NM_COMMAND_ERROR, CMD_ERROR_PARSE_MISSING_ARG), "Missing argument at end of arg string raises the correct error"); g_clear_error(&error); ext_command = command_create("DISABLE_NOTIFICATIONS", test__disable_notifications_handler, "Disables host and service notifications on a program-wide basis.", NULL); command_register(ext_command, -1); ext_command = command_parse("[1234567890] DISABLE_NOTIFICATIONS", COMMAND_SYNTAX_NOKV, &error); ok(ext_command != NULL, "No problem parsing commands with no arguments (when none required)"); command_destroy(ext_command); g_clear_error(&error); ext_command = command_create("DO_THING_WITH_TIMEPERIOD", test__do_thing_with_timeperiod_handler, "Does a thing with a timeperiod", NULL); command_argument_add(ext_command, "timeperiod", TIMEPERIOD, NULL, NULL); command_register(ext_command, -1); g_clear_error(&error); ext_command = command_parse("[1234567890] DO_THING_WITH_TIMEPERIOD;24x8", COMMAND_SYNTAX_NOKV, &error); ok(ext_command == NULL, "No command returned when timeperiod arg is invalid"); ok(g_error_matches(error, NM_COMMAND_ERROR, CMD_ERROR_VALIDATION_FAILURE), "Validation error raised for invalid timeperiod"); registered_timeperiod = find_timeperiod("24x7"); assert(NULL != registered_timeperiod); g_clear_error(&error); ext_command = command_parse("[1234567890] DO_THING_WITH_TIMEPERIOD;24x7", COMMAND_SYNTAX_NOKV, &error); ok(ext_command != NULL, "Command returned when timeperiod arg is not invalid"); ok(error == NULL, "Validation error not raised for valid timeperiod"); ok(registered_timeperiod == command_argument_get_value(ext_command, "timeperiod"), "The correct timeperiod is returned"); command_destroy(ext_command); /** CONTACT SETUP*/ g_clear_error(&error); ext_command = command_create("FIND_CONTACT", test__do_thing_with_contact_handler, "Does a thing with contact", NULL); command_argument_add(ext_command, "contact", CONTACT, NULL, NULL); command_register(ext_command, -1); created_contact = find_contact("nagiosadmin"); assert(NULL != created_contact); /** CONTACT TEST*/ g_clear_error(&error); ext_command = command_parse("[1234567890] FIND_CONTACT;bango", COMMAND_SYNTAX_NOKV, &error); ok(ext_command == NULL, "No command returned when contact arg is invalid"); ok(g_error_matches(error, NM_COMMAND_ERROR, CMD_ERROR_VALIDATION_FAILURE), "Validation error raised for invalid contact"); /** CONTACT TEST*/ g_clear_error(&error); ext_command = command_parse("[1234567890] FIND_CONTACT;nagiosadmin", COMMAND_SYNTAX_NOKV, &error); ok(ext_command != NULL, "Command returned when contact arg is not invalid"); ok(error == NULL, "Validation error not raised for valid contact"); fetched_contact = command_argument_get_value(ext_command, "contact"); ok(created_contact->name == fetched_contact->name, "The correct contact is returned"); /** CONTACT TEARDOWN*/ command_destroy(ext_command); g_clear_error(&error); ext_command = command_parse("[1234567890] _MY_CUSTOMARILY_CUSTOM_CUSTARD_COMMAND;foo;bar;baz;33", COMMAND_SYNTAX_NOKV, &error); ok(g_error_matches(error, NM_COMMAND_ERROR, CMD_ERROR_CUSTOM_COMMAND), "Custom command reported as such"); ok(ext_command != NULL, "Raw command returned when parsing custom command"); ok(!strcmp("foo;bar;baz;33", command_raw_arguments(ext_command)), "Raw arguments properly set for custom command"); ok(command_entry_time(ext_command) == (time_t)1234567890, "Entry time set for custom command"); command_destroy(ext_command); g_clear_error(&error); } registered_commands_deinit(); }
/* START_HANDLER (simple, GET, "simple/\\(.*\\)", res, 2, matches) { */ void simple_func(stone_server_t *server){ ngx_pool_t *pool; char *query, buf[200] = {'\0'}, *dest; int flag,t,len; app_sql_value query_value; ngx_command_t *cache_command; pool = server->pool; HEADER ( "content-type", "text/html" ); //response_write(res, "hello world<br/>"); //response_write(res, "wonder world!<br>"); /* char *path = getenv("PATH_INFO"); regmatch_t preg = matches[1]; len = preg.rm_eo - preg.rm_so; //memset(dest, 0, 20); strncpy(dest, path+preg.rm_so, len); */ dest = server->req->path[1]; //response_write(res, dest); // query = "id = "; //query = ngx_palloc(pool, 6); //strncpy(query, "id = ", 6); // strncpy(buf, query, strlen(query)); // strncpy(buf+strlen(query), dest, len); LIST_HEAD( wheres ); main_add_variable ( pool, &wheres, "id", dest ); LIST_HEAD( fields ); main_add_variable ( pool, &fields, "category_id", ngx_strdup( pool, "211" ) ); //sprintf(buf, "id = %d", *dest); //cache_command = {pool, 0, cache_read, cache_write, NULL}; //cache_command.run = cache_read; //cache_command.type = 0; //cache_command.policy = &file_cache_cmd; //cache_command.post = cache_write; //cache_command.pool = pool; //cache_command.data = NULL; //response_write(res, buf); cache_command = command_create(pool, COMMAND_CACHE_REDIS); cache_command->resource = server->thread->redis; int rc = app_select(server, "article", "*", &wheres, 1, 0, cache_command); if (rc != 0) ECHO("error data"); //app_update(globals_r.con, "article", &fields, &wheres, &cache_command); //ECHO(buf); //if (cache_command.data) response_write(pool, res, cache_command.data); if (cache_command->data) ECHO(cache_command->data); /* cache_command.policy = &node_mjson_command; char *str = tpl_load( &cache_command, "index.tpl"); if ( !str ) return; stone_node_t *node; node = parse_tpl ( &cache_command, &str ); if ( !node ) return; cache_command.data = node; ngx_command_t *dcommand = command_clone( cache_command.pool, &cache_command ); ngx_buf_t *tplbuf = ngx_create_temp_buf( cache_command.pool, 4096 ); if ( !tplbuf ) return; str = tpl_render( &cache_command, dcommand, tplbuf, server->tpl); */ char *val = _GET( "act" ); //TPL_ASSIGN ( ngx_strdup ( pool, "act" ), val ); char *str = TPL_OUTPUT ( "index.tpl" ); if ( str ) ECHO ( str ); char *temp = _GET ( "act" ); if (temp != NULL ) ECHO ( temp ); }