Exemple #1
0
void PgReader::initialize()
{
    // First thing we do, is set up a connection
    if (!m_session)
        m_session = pg_connect(m_connection);

}
Exemple #2
0
/*
 * Function: PG_SETTING
 *
 * Provides access to run-time parameters of the server such as those returned
 * by `SHOW` commands.
 *
 * Parameter [0-4]:     	<host,port,db,user,passwd>
 *
 * Parameter [setting]:  	run-time configuration parameter name
 *
 * Returns: determined by parameter vartype
 */
 int    PG_SETTING(AGENT_REQUEST *request, AGENT_RESULT *result)
 {
    int         ret = SYSINFO_RET_FAIL;             // Request result code
    const char  *__function_name = "PG_SETTING"; 	// Function name for log file
    
    PGconn      *conn = NULL;
    PGresult    *res = NULL;

    char        *setting = NULL;
    char        *value = NULL;
    char        *type = NULL;
    char        query[MAX_STRING_LEN];
    
    zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
    
    // Build the query
    setting = get_rparam(request, PARAM_FIRST);
    if(NULL == setting || '\0' == *setting) {
        zabbix_log(LOG_LEVEL_ERR, "No setting name specified in %s()", __function_name);
        goto out;
    }

    zbx_snprintf(query, sizeof(query), PGSQL_GET_SETTING, setting);    
    
    // Connect to PostreSQL
    if(NULL == (conn = pg_connect(request)))
        goto out;

    // Execute the query
    res = PQexec(conn, query);
    if(PQresultStatus(res) != PGRES_TUPLES_OK) {
        zabbix_log(LOG_LEVEL_ERR, "Failed to execute PostgreSQL query in %s() with: %s", __function_name, PQresultErrorMessage(res));
        goto out;
    }
    
    if(0 == PQntuples(res)) {
        zabbix_log(LOG_LEVEL_DEBUG, "No results returned for query \"%s\" in %s()", query, __function_name);
        goto out;
    }
    
    // Set result
    value = strdup(PQgetvalue(res, 0, 0));
    type = strdup(PQgetvalue(res, 0, 1));

    if(0 == strncmp("integer", type, 7))
    	SET_UI64_RESULT(result, strtoull(value, NULL, 10));
   	else if(0 == strncmp("real", type, 4))
   		SET_DBL_RESULT(result, strtold(value, NULL));
   	else
   		SET_STR_RESULT(result, value);

    ret = SYSINFO_RET_OK;
    
out:
    PQclear(res);
    PQfinish(conn);
    
    zabbix_log(LOG_LEVEL_DEBUG, "End of %s(%s)", __function_name, request->key);
    return ret;
}
/*
 * Custom key pg.table.discovery
 *
 * Returns all known Tables in a PostgreSQL database
 *
 * Parameter [0-4]:     <host,port,db,user,passwd>
 * *
 * Returns:
 * {
 *        "data":[
 *                {
 *                        "{#DATABASE}":"MyDatabase",
 *                        "{#SCHEMA}":"public",
 *                        "{#TABLESPACE}":"pg_default",
 *                        "{#TABLE}":"MyTable",
 *                        "{#TYPE}":"MyTable",
 *                        "{#OWNER}":"postgres",
 *                        "{#PERSISTENCE":"permenant|temporary",
 *                        "{#ISSUBCLASS}":"0"}]}
 */
int    PG_TABLE_DISCOVERY(AGENT_REQUEST *request, AGENT_RESULT *result)
{
    int         ret = SYSINFO_RET_FAIL;                     // Request result code
    const char  *__function_name = "PG_TABLE_DISCOVERY";    // Function name for log file
    struct      zbx_json j;                                 // JSON response for discovery rule
    
    PGconn      *conn = NULL;
    PGresult    *res = NULL;
    
    char        query[MAX_STRING_LEN] = PGSQL_DISCOVER_TABLES;
    int         i = 0, count = 0;
    
    zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
    
    // Connect to PostreSQL
    if(NULL == (conn = pg_connect(request)))
        goto out;
    
    // Execute a query
    res = PQexec(conn, query);
    if(PQresultStatus(res) != PGRES_TUPLES_OK) {
        zabbix_log(LOG_LEVEL_ERR, "Failed to execute PostgreSQL query in %s() with: %s", __function_name, PQresultErrorMessage(res));
        goto out;
    }
    
    if(0 == (count = PQntuples(res))) {
        zabbix_log(LOG_LEVEL_DEBUG, "No results returned for query \"%s\" in %s()", query, __function_name);
    }
             
    // Create JSON array of discovered objects
    zbx_json_init(&j, ZBX_JSON_STAT_BUF_LEN);
    zbx_json_addarray(&j, ZBX_PROTO_TAG_DATA);
    
    for(i = 0; i < count; i++) {
        zbx_json_addobject(&j, NULL);        
        zbx_json_addstring(&j, "{#OID}", PQgetvalue(res, i, 0), ZBX_JSON_TYPE_STRING);
        zbx_json_addstring(&j, "{#DATABASE}", PQgetvalue(res, i, 1), ZBX_JSON_TYPE_STRING);
        zbx_json_addstring(&j, "{#SCHEMA}", PQgetvalue(res, i, 2), ZBX_JSON_TYPE_STRING);
        zbx_json_addstring(&j, "{#TABLESPACE}", PQgetvalue(res, i, 3), ZBX_JSON_TYPE_STRING);
        zbx_json_addstring(&j, "{#TABLE}", PQgetvalue(res, i, 4), ZBX_JSON_TYPE_STRING);
        zbx_json_addstring(&j, "{#TYPE}", PQgetvalue(res, i, 5), ZBX_JSON_TYPE_STRING);
        zbx_json_addstring(&j, "{#OWNER}", PQgetvalue(res, i, 6), ZBX_JSON_TYPE_STRING);
        zbx_json_addstring(&j, "{#PERSISTENCE}", PQgetvalue(res, i, 7), ZBX_JSON_TYPE_STRING);
        zbx_json_addstring(&j, "{#ISSUBCLASS}", PQgetvalue(res, i, 8), ZBX_JSON_TYPE_STRING);
        zbx_json_close(&j);         
    }
    
    // Finalize JSON response
    zbx_json_close(&j);
    SET_STR_RESULT(result, strdup(j.buffer));
    zbx_json_free(&j);
    ret = SYSINFO_RET_OK;
        
out:
    PQclear(res);
    PQfinish(conn);
    
    zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
    return ret;
}
/*
 * Custom keys pg.index.* (for each field in pg_stat_all_indexes)
 *
 * Returns the requested statistic for the specified index
 *
 * Parameters:
 *   0:  connection string
 *   1:  connection database
 *   2:  filter by index name (default: sum of all indexes)
 *
 * Returns: u
 */
int    PG_STAT_ALL_INDEXES(AGENT_REQUEST *request, AGENT_RESULT *result)
{
    int         ret = SYSINFO_RET_FAIL;                     // Request result code
    const char  *__function_name = "PG_STAT_ALL_INDEXES";   // Function name for log file
    
    char        *index = NULL;
    
    PGconn      *conn = NULL;
    PGresult    *res = NULL;
    
    char        *field;
    char        query[MAX_STRING_LEN];
    char        *buffer = NULL;
    
    zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
    
    // Get stat field from requested key name "pb.table.<field>"
    field = &request->key[9];
    
    // Build query
    index = get_rparam(request, PARAM_FIRST);
    if(NULL == index || '\0' == *index)
        zbx_snprintf(query, sizeof(query), "SELECT SUM(%s) FROM pg_stat_all_indexes", field);
    else
        zbx_snprintf(query, sizeof(query),  "SELECT %s FROM pg_stat_all_indexes WHERE indexrelname = '%s'", field, index);

    // Connect to PostreSQL
    if(NULL == (conn = pg_connect(request)))
        goto out;
    
    // Execute a query
    res = pg_exec(conn, query);
    if(PQresultStatus(res) != PGRES_TUPLES_OK) {
        zabbix_log(LOG_LEVEL_ERR, "Failed to execute PostgreSQL query in %s() with: %s", __function_name, PQresultErrorMessage(res));
        goto out;
    }
    
    if(0 == PQntuples(res)) {
        zabbix_log(LOG_LEVEL_ERR, "No results returned for query \"%s\" in %s()", query, __function_name);
        goto out;
    }
    
    // Set result
    buffer = strdup(PQgetvalue(res, 0, 0));
    SET_UI64_RESULT(result, atoi(buffer));
    ret = SYSINFO_RET_OK;
        
out:
    PQclear(res);
    PQfinish(conn);
    
    zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
    return ret;
}
/*
 * Function: pg_get_int
 *
 * Executes a PostgreSQL Query using connection details from a Zabbix agent
 * request structure and updates the agent result structure with the integer
 * value of the first column of the first row returned.
 *
 * Parameter [request]: Zabbix agent request structure.
 *          Passed to pg_connect to fetch as valid PostgreSQL
 *          server connection
 *
 * Parameter [result]:  Zabbix agent result structure
 *
 * Paramater [query]:   PostgreSQL query to execute. Query should return a
 *          single scalar integer value
 *
 * Returns: SYSINFO_RET_OK or SYSINFO_RET_FAIL on error
 */
 int    pg_get_int(AGENT_REQUEST *request, AGENT_RESULT *result, const char *query)
 {
    int         ret = SYSINFO_RET_FAIL;             // Request result code
    const char  *__function_name = "pg_get_int";    // Function name for log file
    
    PGconn      *conn = NULL;
    PGresult    *res = NULL;
    char        *buffer = NULL;
    
    zabbix_log(LOG_LEVEL_DEBUG, "In %s(%s)", __function_name, request->key);
    
    // Connect to PostreSQL
    if(NULL == (conn = pg_connect(request)))
        goto out;
    
    // Execute a query
    res = pg_exec(conn, query);
    if(PQresultStatus(res) != PGRES_TUPLES_OK) {
        zabbix_log(LOG_LEVEL_ERR, "Failed to execute PostgreSQL query in %s(%s) with: %s", __function_name, request->key, PQresultErrorMessage(res));
        goto out;
    }
    
    if(0 == PQntuples(res)) {
        zabbix_log(LOG_LEVEL_DEBUG, "No results returned for query \"%s\" in %s(%s)", query, __function_name, request->key);
        goto out;
    }
    
    // Set result
    buffer = strdup(PQgetvalue(res, 0, 0));
    
    // Convert E Notation
    if(1 < strlen(buffer) && '.' == buffer[1]) {
        double dbl = strtod(buffer, NULL);
        SET_UI64_RESULT(result, (unsigned long long) dbl);
    }
    
    else {
        SET_UI64_RESULT(result, strtoull(buffer, NULL, 10));
    }
    
    ret = SYSINFO_RET_OK;
    
out:
    PQclear(res);
    PQfinish(conn);
    
    zabbix_log(LOG_LEVEL_DEBUG, "End of %s(%s)", __function_name, request->key);
    return ret;
}
Exemple #6
0
/* Ein Datum in die Datenbank schreiben */
static void pg_insert(char *query){
  PGresult *res;
  if(pg_connect()){
    res = PQexec(connection, query);
    if(!res || PQresultStatus(res) != PGRES_COMMAND_OK){
      DEBUGOUT2("Fehler beim INSERT: %s\n", query);
      #ifndef NO_LOGING
      snprintf(get_error_buffer(), ERR_BUFFERSIZE, "Fehler beim INSERT: %s", query);
      log_error(get_error_buffer());
      #endif
    } else {
      DEBUGOUT2("Query: '%s' ausgefuehrt\n", query);
    }
    PQclear(res);
  }
}
/*
 * Function: pg_get_string
 *
 * Executes a PostgreSQL Query using connection details from a Zabbix agent
 * request structure and updates the agent result structure with the string
 * value of the first column of the first row returned.
 *
 * Parameter [request]: Zabbix agent request structure.
 *          Passed to pg_connect to fetch as valid PostgreSQL
 *          server connection
 *
 * Parameter [result]:  Zabbix agent result structure
 *
 * Paramater [query]:   PostgreSQL query to execute. Query should return a
 *          single scalar string value
 *
 * Returns: SYSINFO_RET_OK or SYSINFO_RET_FAIL on error
 */
 int    pg_get_string(AGENT_REQUEST *request, AGENT_RESULT *result, const char *query)
 {
    int         ret = SYSINFO_RET_FAIL;             // Request result code
    const char  *__function_name = "pg_get_string"; // Function name for log file
    
    PGconn      *conn = NULL;
    PGresult    *res = NULL;
    char        *buffer = NULL;
    
    zabbix_log(LOG_LEVEL_DEBUG, "In %s(%s)", __function_name, request->key);
    
    // Connect to PostreSQL
    if(NULL == (conn = pg_connect(request)))
        goto out;
    
    // Execute a query
    res = pg_exec(conn, query);
    if(PQresultStatus(res) != PGRES_TUPLES_OK) {
        zabbix_log(LOG_LEVEL_ERR, "Failed to execute PostgreSQL query in %s(%s) with: %s", __function_name, request->key, PQresultErrorMessage(res));
        goto out;
    }
    
    if(0 == PQntuples(res)) {
        zabbix_log(LOG_LEVEL_DEBUG, "No results returned for query \"%s\" in %s(%s)", query, __function_name, request->key);
        goto out;
    }
    
    // Set result
    buffer = strdup(PQgetvalue(res, 0, 0));
    SET_STR_RESULT(result, buffer);    
    ret = SYSINFO_RET_OK;
    
out:
    PQclear(res);
    PQfinish(conn);
    
    zabbix_log(LOG_LEVEL_DEBUG, "End of %s(%s)", __function_name, request->key);
    return ret;
}
long int pg_version(AGENT_REQUEST *request) {
    PGconn      *conn = NULL;
    PGresult    *res = NULL;
    long int    version = 0;

    // connect to PostgreSQL
    conn = pg_connect(request);
    if (NULL == conn)
        return 0;

    // get server version
    res = pg_exec(conn, "SELECT setting FROM pg_settings WHERE name='server_version_num'", NULL);
    if(0 == PQntuples(res)) {
        zabbix_log(LOG_LEVEL_ERR, "Failed to get PostgreSQL server version");
        return 0;
    }

    // convert to integer
    version = atol(PQgetvalue(res, 0, 0));

    zabbix_log(LOG_LEVEL_DEBUG, "PostgreSQL server version: %lu", version);
    return version;
}
/*
 * Function: pg_get_discovery
 *
 * Executes a PostgreSQL Query using connection details from a Zabbix agent
 * request structure and updates the agent result structure with the JSON
 * discovery data for each returned row.
 *
 * Parameter [request]: Zabbix agent request structure.
 *          Passed to pg_connect to fetch as valid PostgreSQL
 *          server connection
 *
 * Parameter [result]:  Zabbix agent result structure
 *
 * Paramater [query]:   PostgreSQL query to execute. Query should column names
            that match the desired discovery fields.
 *
 * Returns: SYSINFO_RET_OK or SYSINFO_RET_FAIL on error
 */
 int    pg_get_discovery(AGENT_REQUEST *request, AGENT_RESULT *result, const char *query)
 {
    int         ret = SYSINFO_RET_FAIL;                 // Request result code
    const char  *__function_name = "pg_get_discovery";  // Function name for log file
    
    PGconn      *conn = NULL;
    PGresult    *res = NULL;
    struct      zbx_json j;                             // JSON response for discovery rule
    int         i = 0, x = 0, columns = 0, rows = 0;
    char        *colname = NULL, *c = NULL;
    char        buffer[MAX_STRING_LEN];
    
    zabbix_log(LOG_LEVEL_DEBUG, "In %s(%s)", __function_name, request->key);
    
    // Connect to PostreSQL
    if(NULL == (conn = pg_connect(request)))
        goto out;
    
    // Execute a query
    res = pg_exec(conn, query);
    if(PQresultStatus(res) != PGRES_TUPLES_OK) {
        zabbix_log(LOG_LEVEL_ERR, "Failed to execute PostgreSQL query in %s(%s) with: %s", __function_name, request->key, PQresultErrorMessage(res));
        goto out;
    }

    rows = PQntuples(res);
    columns = PQnfields(res);
    
    // Create JSON array of discovered objects
    zbx_json_init(&j, ZBX_JSON_STAT_BUF_LEN);
    zbx_json_addarray(&j, ZBX_PROTO_TAG_DATA);
    
    // create discovery instance for each row
    for(i = 0; i < rows; i++) {
        zbx_json_addobject(&j, NULL);
        
        // add each fields as a discovery field
        for(x = 0; x < columns; x++) {
            // set discovery key name to uppercase column name
            zbx_snprintf(buffer, sizeof(buffer), "{#%s}", PQfname(res, x));
            for(c = &buffer[0]; *c; c++)
                *c = toupper(*c);

            zbx_json_addstring(&j, buffer, PQgetvalue(res, i, x), ZBX_JSON_TYPE_STRING);
        }

        zbx_json_close(&j);         
    }
    
    // Finalize JSON response
    zbx_json_close(&j);
    SET_STR_RESULT(result, strdup(j.buffer));
    zbx_json_free(&j);

    ret = SYSINFO_RET_OK;
    
out:
    PQclear(res);
    PQfinish(conn);

    zabbix_log(LOG_LEVEL_DEBUG, "End of %s(%s)", __function_name, request->key);
    return ret;
}
/*
 * Function: pg_get_result
 *
 * Executes a PostgreSQL Query using connection details from a Zabbix agent
 * request structure and updates the agent result structure with the value of
 * the first column of the first row returned.
 *
 * type may be 
 *
 * Query parameters may be provided as a NULL terminated sequence of *char
 * values in the ... parameter.
 *
 * Parameter [request]: Zabbix agent request structure.
 *          Passed to pg_connect to fetch as valid PostgreSQL
 *          server connection
 *
 * Parameter [result]:  Zabbix agent result structure
 *
 * Parameter [type]:    Result type to set. May be one of AR_STRING, AR_UINT64
 *          or AR_DOUBLE.
 *
 * Paramater [query]:   PostgreSQL query to execute. Query should return a
 *          single scalar string value. Parameters defined using PostgreSQL's
 *          '$n' notation will be replaced with the corresponding variadic
 *          argument provided in ...
 *
 * Returns: SYSINFO_RET_OK or SYSINFO_RET_FAIL on error
 */
int    pg_get_result(AGENT_REQUEST *request, AGENT_RESULT *result, int type, const char *query, PGparams params)
{
    int         ret = SYSINFO_RET_FAIL;             // Request result code
    const char  *__function_name = "pg_get_result"; // Function name for log file
    
    PGconn      *conn = NULL;
    PGresult    *res = NULL;
    char        *value = NULL;
    
    zabbix_log(LOG_LEVEL_DEBUG, "In %s(%s)", __function_name, request->key);
    
    // Connect to PostreSQL
    if(NULL == (conn = pg_connect(request)))
        goto out;
    
    // Execute a query
    res = pg_exec(conn, query, params);

    if(PQresultStatus(res) != PGRES_TUPLES_OK) {
        zabbix_log(LOG_LEVEL_ERR, "Failed to execute PostgreSQL query in %s(%s) with: %s", __function_name, request->key, PQresultErrorMessage(res));
        goto out;
    }
    
    if(0 == PQntuples(res)) {
        zabbix_log(LOG_LEVEL_DEBUG, "No results returned for query \"%s\" in %s(%s)", query, __function_name, request->key);
        goto out;
    }
    
    // get scalar value (freed later by PQclear)
    value = PQgetvalue(res, 0, 0);

    // Set result
    switch(type) {
        case AR_STRING:
            // string result (zabbix will clean the strdup'd buffer)
            SET_STR_RESULT(result, strdup(value));
            break;

        case AR_UINT64:
            // integer result
            // Convert E Notation
            if(1 < strlen(value) && '.' == value[1]) {
                double dbl = strtod(value, NULL);
                SET_UI64_RESULT(result, (unsigned long long) dbl);
            } else {
                SET_UI64_RESULT(result, strtoull(value, NULL, 10));
            }
            break;

        case AR_DOUBLE:
            // double result
            SET_DBL_RESULT(result, strtold(value, NULL));
            break;

        default:
            // unknown result type
            zabbix_log(LOG_LEVEL_ERR, "Unsupported result type: 0x%0X in %s", type, __function_name);
            goto out;
    }

    ret = SYSINFO_RET_OK;
    
out:
    PQclear(res);
    PQfinish(conn);
    
    zabbix_log(LOG_LEVEL_DEBUG, "End of %s(%s)", __function_name, request->key);
    return ret;
}
Exemple #11
0
int main(int argc, char **argv)
{
    int lev = LOG_NOTICE;
    int opt, fg = 0, err = 0, nopass = 0, nport;
    char *cfgfile = NULL;
    char *logfile = NULL;
    const char *shuser = getenv("USER");
    const char *dbdsn = NULL;
    char *dbuser = NULL;
    char *dbpasswd = NULL;
    char *port = NULL;
    char *prefix = NULL;
    char prompt[64];
    char hostname[_POSIX_HOST_NAME_MAX];
    char serveruri[_POSIX_HOST_NAME_MAX * 2];
    wordexp_t expresult;
    config_t config;
    tf_node *orgroot = NULL;
    tf_node *infroot = NULL;
    tf_node *servinst = NULL;
    tf_host *host = NULL;
    tf_access_map *accmap = NULL;
    tf_property *instprop = NULL;
    tf_host **hostarr = NULL;
    tf_error dberr;
    int result = 0;

    hostname[0] = '\0';

    while (err == 0 && (opt = getopt(argc, argv, "c:d:fh:l:p:P:t:u:w")) != -1) {

        switch (opt) {

        case 'c':
            cfgfile = strdup(optarg);
            break;

        case 'd':
            lev = atoi(optarg);
            break;

        case 'f':
            fg = 1;
            break;

        case 'h':
            strncpy(hostname, optarg, _POSIX_HOST_NAME_MAX);
            break;

        case 'l':
            logfile = strdup(optarg);
            break;

        case 'p':
            dbpasswd = strdup(optarg);
            break;

        case 'P':
            prefix = strdup(optarg);
            break;

        case 't':
            port = strdup(optarg);
            break;

        case 'u':
            dbuser = strdup(optarg);
            break;

        case 'w':
            nopass = 1;
            break;

        default:
            err = 1;
        }
    }

    argc -= optind;
    argv += optind;

    if (argc != 0 || err || !cfgfile) {
        printf("USAGE: tfadmin setup [options] -c <file>\n");
        printf("\n");
        printf("Common Options:\n");
        printf("  -c <file>             configuration file (required)\n");
        printf("  -d <level>            log level (default: 5)\n");
        printf("  -f                    write log messages to standard out\n");
        printf("  -l <file>             log file (default: ~/tfadmin.log)\n");
        printf("\n");
        printf("Team Services Options:\n");
        printf("  -h <host>             hostname where HAProxy is installed (default: localhost)\n");
        printf("  -t <port>             TCP port HAProxy listens on (default: 8080)\n");
        printf("  -P <prefix>           URL prefix with leading forward slash (default: /tfs)\n");
        printf("\n");
        printf("Database Options:\n");
        printf("  -u <username>         database user to connect as (default: shell user)\n");
        printf("  -p <password>         password for the database user (will prompt if omitted)\n");
        printf("  -w                    never prompt for password\n");
        printf("\n");

        result = 1;
        goto cleanup;
    }

    if (!logfile) {
        wordexp("~/tfadmin.log", &expresult, 0);
        logfile = strdup(expresult.we_wordv[0]);
        wordfree(&expresult);
    }

    config_init(&config);
    if (config_read_file(&config, cfgfile) != CONFIG_TRUE) {
        fprintf(stderr, "tfadmin: failed to read config file!\n");
        result = 1;
        goto cleanup;
    }

    config_lookup_string(&config, "configdsn", &dbdsn);

    nport = (port) ? atoi(port) : 0;
    if (port && (nport == 0 || nport != (nport & 0xffff))) {
        fprintf(stderr, "listening port must be a valid TCP port number (was %d)\n", nport);
        result = 1;
        goto cleanup_config;
    } else if (!port)
        port = strdup("8080"); /* default */

    if (prefix && (strcmp(prefix, "") == 0 || prefix[0] != '/')) {
        fprintf(stderr, "prefix must be a valid URI (was %s)\n", prefix);
        result = 1;
        goto cleanup_config;
    } else if (!prefix)
        prefix = strdup("/tfs"); /* default */

    if (!dbuser && shuser)
        dbuser = strdup(shuser);
    else if (!dbuser) {
        fprintf(stderr, "tfadmin: no database user specified!\n");
        result = 1;
        goto cleanup_config;
    }

    if (!nopass && !dbpasswd) {
        snprintf(prompt, 64, "Password for user %s: ", dbuser);
        dbpasswd = getpass(prompt);
    } else if (!dbpasswd)
        dbpasswd = strdup("");

    if (!log_open(logfile, lev, fg)) {
        fprintf(stderr, "tfadmin: failed to open log file!\n");
        result = 1;
        goto cleanup_config;
    }

    if (pg_pool_init(1) != 1) {
        log_fatal("failed to initialise PG context pool");
        fprintf(stderr, "tfadmin: failed to initialise (see %s for details)\n", logfile);
        result = 1;
        goto cleanup_log;
    }

    if (!pg_connect(dbdsn, dbuser, dbpasswd, 1, NULL)) {
        log_fatal("failed to connect to PG");
        fprintf(stderr, "tfadmin: failed to connect to the database (see %s for details)\n", logfile);
        result = 1;
        goto cleanup_db;
    }

    pgctx *ctx = pg_context_acquire(NULL);
    if (!ctx) {
        log_fatal("failed to obtain PG context!");
        fprintf(stderr, "tfadmin: failed to connect to the database (see %s for details)\n", logfile);
        result = 1;
        goto cleanup_db;
    }

    if (tf_fetch_hosts(ctx, &hostarr) == TF_ERROR_SUCCESS) {
        hostarr = tf_free_host_array(hostarr);
        pg_context_release(ctx);
        printf("Team Foundation deployment is already initialised\n");
        goto cleanup_db;
    }

    pg_context_release(ctx);
    ctx = pg_acquire_trans(NULL);

    if (!ctx) {
        log_fatal("failed to obtain PG context!");
        fprintf(stderr, "tfadmin: failed to connect to the database (see %s for details)\n", logfile);
        result = 1;
        goto cleanup_db;
    }

    if (tf_init_configdb(ctx) != TF_ERROR_SUCCESS)
        goto error;

    printf("Building initial catalog\n");

    orgroot = tf_new_node(
        NULL, 
        TF_CATALOG_TYPE_ORGANIZATIONAL_ROOT, 
        "Organizational Root", 
        "The root of the catalog tree that describes the organizational makeup of the TFS deployment.");
    sprintf(orgroot->child, TF_CATALOG_ORGANIZATION_ROOT);
    
    if ((dberr = tf_add_node(ctx, orgroot)) != TF_ERROR_SUCCESS)
        goto error;

    infroot = tf_new_node(
        NULL, 
        TF_CATALOG_TYPE_INFRASTRUCTURE_ROOT, 
        "Infrastructure Root", 
        "The root of the catalog tree that describes the physical makeup of the TFS deployment.");
    sprintf(infroot->child, TF_CATALOG_INFRASTRUCTURE_ROOT);
    
    if ((dberr = tf_add_node(ctx, infroot)) != TF_ERROR_SUCCESS)
        goto error;

    servinst = tf_new_node(
        orgroot, 
        TF_CATALOG_TYPE_SERVER_INSTANCE, 
        "Team Foundation Server Instance", 
        NULL);
    dberr = tf_add_node(ctx, servinst);

    if (dberr != TF_ERROR_SUCCESS)
        goto error;

    printf("Registering services\n");

    if (!hostname[0])
        gethostname(hostname, _POSIX_HOST_NAME_MAX);

    snprintf(serveruri, _POSIX_HOST_NAME_MAX * 2, "http://%s:%s/%s", hostname, port, prefix);
    accmap = tf_new_access_map(TF_ACCESSMAP_PUBLIC_MONIKER, TF_ACCESSMAP_PUBLIC_DISPLNAME, serveruri);
    dberr = tf_add_access_map(ctx, accmap);

    if (dberr != TF_ERROR_SUCCESS)
        goto error;

    dberr = tf_set_default_access_map(ctx, accmap);
    accmap = tf_free_access_map(accmap);

    if (dberr != TF_ERROR_SUCCESS)
        goto error;

    tf_service *service = tf_new_service(
        TF_SERVICE_LOCATION_ID, 
        TF_SERVICE_LOCATION_TYPE, 
        TF_SERVICE_LOCATION_NAME, 
        TF_CATALOG_TOOL_FRAMEWORK);
    tf_set_service_url(service, TF_LOCATION_SERVICE_ENDPOINT, TF_SERVICE_RELTO_CONTEXT);
    dberr = tf_add_service(ctx, service);

    if (dberr != TF_ERROR_SUCCESS)
        goto error;

    tf_service_ref *ref = tf_new_service_ref(&servinst->resource, service, "Location");
    service = tf_free_service(service);
    dberr = tf_add_service_ref(ctx, ref);
    ref = tf_free_service_ref(ref);

    if (dberr != TF_ERROR_SUCCESS)
        goto error;

    service = tf_new_service(
        TF_SERVICE_CATALOG_ID, 
        TF_SERVICE_CATALOG_TYPE, 
        TF_SERVICE_CATALOG_NAME, 
        TF_CATALOG_TOOL_FRAMEWORK);
    tf_set_service_url(service, TF_CATALOG_SERVICE_ENDPOINT, TF_SERVICE_RELTO_CONTEXT);
    dberr = tf_add_service(ctx, service);

    if (dberr != TF_ERROR_SUCCESS)
        goto error;

    ref = tf_new_service_ref(&servinst->resource, service, "Catalog");
    service = tf_free_service(service);
    dberr = tf_add_service_ref(ctx, ref);
    ref = tf_free_service_ref(ref);

    if (dberr != TF_ERROR_SUCCESS)
        goto error;

    printf("Registering Team Foundation service host\n");
    host = tf_new_host(TF_TEAM_FOUNDATION_SERVICE_NAME, dbdsn);
    dberr = tf_add_host(ctx, host);

    if (dberr != TF_ERROR_SUCCESS)
        goto error;

    instprop = tf_new_property(
        TF_PROPERTY_INSTANCE_ID_ID,
        servinst->resource.propertyid,
        host->id);
    dberr = tf_add_property(ctx, instprop);

    if (dberr != TF_ERROR_SUCCESS)
        goto error;

    printf("Team Foundation deployment is initialised\n");
    pg_release_commit(ctx);
    goto cleanup_db;

error:
    pg_release_rollback(ctx);
    result = 1;
    fprintf(stderr, "tfadmin: the operation failed (see %s for details)\n", logfile);

cleanup_db:
    orgroot = tf_free_node(orgroot);
    infroot = tf_free_node(infroot);
    servinst = tf_free_node(servinst);
    host = tf_free_host(host);

    pg_disconnect();

cleanup_log:
    log_close();

cleanup_config:
    config_destroy(&config);

cleanup:
    if (cfgfile)
        free(cfgfile);

    if (logfile)
        free(logfile);

    if (dbuser)
        free(dbuser);

    if (dbpasswd)
        free(dbpasswd);

    if (port)
        free(port);

    if (prefix)
        free(prefix);

    return result;
}