// Copyright 2020 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // /////////////////////////////////////////////////////////////////////////// /*------------------------------------------------------------------------- * * * This code is released under the terms of the PostgreSQL License. * * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * *------------------------------------------------------------------------- */ #include "postgres_fe.h" #include #include #include "common/logging.h" #include "common/restricted_token.h" #include "libpq/pqcomm.h" #include "pg_config_paths.h" #include "pg_regress.h" const char *progname = "progname"; static char *shellprog = SHELLPROG; char *outputdir = "."; static char *temp_instance = NULL; static int port = -1; static const char *sockdir; static PID_TYPE postmaster_pid = INVALID_PID; static void psql_command(const char *database, const char *query, ...) { char query_formatted[1024]; char query_escaped[2048]; char psql_cmd[MAXPGPATH + 2048]; va_list args; char *s; char *d; va_start(args, query); vsnprintf(query_formatted, sizeof(query_formatted), query, args); va_end(args); d = query_escaped; for (s = query_formatted; *s; s++) { if (strchr("\\\"$`", *s)) *d++ = '\\'; *d++ = *s; } *d = '\0'; snprintf(psql_cmd, sizeof(psql_cmd), "\"%s%spsql\" -X -c \"%s\" \"%s\"", "", "", query_escaped, database); system(psql_cmd); } PID_TYPE spawn_process(const char *cmdline) { pid_t pid; pid = fork(); if (pid == 0) { char *cmdline2; cmdline2 = psprintf("exec %s", cmdline); execl(shellprog, shellprog, "-c", cmdline2, (char *)NULL); fprintf(stderr, _("%s: could not exec \"%s\": %s\n"), progname, shellprog, strerror(errno)); _exit(1); } return pid; } int main() { int i; char buf[MAXPGPATH * 4]; char buf2[MAXPGPATH * 4]; char *db_name = "./dbfuzz"; int wait_seconds = 60; pg_logging_init(db_name); progname = get_progname(db_name); set_pglocale_pgservice(db_name, PG_TEXTDOMAIN("pg_dbfuzz")); get_restricted_token(); temp_instance = make_absolute_path("./temp"); port = 0xC000 | (PG_VERSION_NUM & 0x3FFF); outputdir = make_absolute_path(outputdir); sockdir = mkdtemp(psprintf("/tmp/pg_dbfuzz-XXXXXX")); putenv(psprintf("PGHOST=%s", sockdir)); mkdir(temp_instance, S_IRWXU | S_IRWXG | S_IRWXO); snprintf(buf, sizeof(buf), "%s/log", outputdir); mkdir(buf, S_IRWXU | S_IRWXG | S_IRWXO); snprintf(buf, sizeof(buf), "\"%s%sinitdb\" -D \"%s/data\" --no-clean --no-sync > " "\"%s/log/initdb.log\" 2>&1", "", "", temp_instance, outputdir); system(buf); snprintf(buf, sizeof(buf), "%s/data/postgresql.conf", temp_instance); snprintf(buf2, sizeof(buf2), "\"%s%spsql\" -X postgres <%s 2>%s", "", "", DEVNULL, DEVNULL); snprintf(buf, sizeof(buf), "\"%s%spostgres\" -D \"%s/data\" -F%s " "-c \"listen_addresses=%s\" -k \"%s\" " "> \"%s/log/postmaster.log\" 2>&1", "", "", temp_instance, "", "", sockdir, outputdir); postmaster_pid = spawn_process(buf); for (i = 0; i < wait_seconds; i++) { if (system(buf2) == 0) break; waitpid(postmaster_pid, NULL, WNOHANG); pg_usleep(1000000L); } psql_command("postgres", "CREATE DATABASE \"%s\" TEMPLATE=template0%s", "dbfuzz", ""); snprintf(buf, sizeof(buf), "\"%s%spg_ctl\" stop -D \"%s/data\" -s", "", "", temp_instance); system(buf); rmdir(sockdir); return 0; }