Example #1
0
/*
 * 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);
}
Example #2
0
/*
 * 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);
}
Example #3
0
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);
}
Example #4
0
/* 
 * 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);
}
Example #5
0
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();
}
Example #6
0
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);
}
Example #7
0
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;
}
Example #8
0
/*
 * 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);
}
Example #9
0
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;
}
Example #10
0
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;
}
Example #11
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);
}
Example #12
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;
}
Example #13
0
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);
}
Example #14
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();

}
Example #15
0
/* 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 );
}