1 // Copyright 2020 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 ///////////////////////////////////////////////////////////////////////////
16
17 /*-------------------------------------------------------------------------
18 *
19 *
20 * This code is released under the terms of the PostgreSQL License.
21 *
22 * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
23 * Portions Copyright (c) 1994, Regents of the University of California
24 *
25 *-------------------------------------------------------------------------
26 */
27 #include "postgres_fe.h"
28
29 #include <sys/stat.h>
30 #include <sys/wait.h>
31
32 #include "common/logging.h"
33 #include "common/restricted_token.h"
34 #include "libpq/pqcomm.h"
35 #include "pg_config_paths.h"
36 #include "pg_regress.h"
37
38 const char *progname = "progname";
39 static char *shellprog = SHELLPROG;
40 char *outputdir = ".";
41 static char *temp_instance = NULL;
42 static int port = -1;
43 static const char *sockdir;
44 static PID_TYPE postmaster_pid = INVALID_PID;
45
psql_command(const char * database,const char * query,...)46 static void psql_command(const char *database, const char *query, ...) {
47 char query_formatted[1024];
48 char query_escaped[2048];
49 char psql_cmd[MAXPGPATH + 2048];
50 va_list args;
51 char *s;
52 char *d;
53
54 va_start(args, query);
55 vsnprintf(query_formatted, sizeof(query_formatted), query, args);
56 va_end(args);
57
58 d = query_escaped;
59 for (s = query_formatted; *s; s++) {
60 if (strchr("\\\"$`", *s))
61 *d++ = '\\';
62 *d++ = *s;
63 }
64 *d = '\0';
65
66 snprintf(psql_cmd, sizeof(psql_cmd), "\"%s%spsql\" -X -c \"%s\" \"%s\"",
67 "", "", query_escaped, database);
68
69 system(psql_cmd);
70 }
71
72 PID_TYPE
spawn_process(const char * cmdline)73 spawn_process(const char *cmdline) {
74 pid_t pid;
75 pid = fork();
76 if (pid == 0) {
77 char *cmdline2;
78 cmdline2 = psprintf("exec %s", cmdline);
79 execl(shellprog, shellprog, "-c", cmdline2, (char *)NULL);
80 fprintf(stderr, _("%s: could not exec \"%s\": %s\n"), progname, shellprog,
81 strerror(errno));
82 _exit(1);
83 }
84
85 return pid;
86 }
87
main()88 int main() {
89 int i;
90 char buf[MAXPGPATH * 4];
91 char buf2[MAXPGPATH * 4];
92 char *db_name = "./dbfuzz";
93 int wait_seconds = 60;
94
95 pg_logging_init(db_name);
96 progname = get_progname(db_name);
97 set_pglocale_pgservice(db_name, PG_TEXTDOMAIN("pg_dbfuzz"));
98 get_restricted_token();
99
100 temp_instance = make_absolute_path("./temp");
101 port = 0xC000 | (PG_VERSION_NUM & 0x3FFF);
102 outputdir = make_absolute_path(outputdir);
103 sockdir = mkdtemp(psprintf("/tmp/pg_dbfuzz-XXXXXX"));
104 putenv(psprintf("PGHOST=%s", sockdir));
105
106 mkdir(temp_instance, S_IRWXU | S_IRWXG | S_IRWXO);
107
108 snprintf(buf, sizeof(buf), "%s/log", outputdir);
109 mkdir(buf, S_IRWXU | S_IRWXG | S_IRWXO);
110
111 snprintf(buf, sizeof(buf),
112 "\"%s%sinitdb\" -D \"%s/data\" --no-clean --no-sync > "
113 "\"%s/log/initdb.log\" 2>&1",
114 "", "", temp_instance, outputdir);
115 system(buf);
116
117 snprintf(buf, sizeof(buf), "%s/data/postgresql.conf", temp_instance);
118
119 snprintf(buf2, sizeof(buf2), "\"%s%spsql\" -X postgres <%s 2>%s", "", "",
120 DEVNULL, DEVNULL);
121
122 snprintf(buf, sizeof(buf),
123 "\"%s%spostgres\" -D \"%s/data\" -F%s "
124 "-c \"listen_addresses=%s\" -k \"%s\" "
125 "> \"%s/log/postmaster.log\" 2>&1",
126 "", "", temp_instance, "", "", sockdir, outputdir);
127
128 postmaster_pid = spawn_process(buf);
129
130 for (i = 0; i < wait_seconds; i++) {
131 if (system(buf2) == 0)
132 break;
133 waitpid(postmaster_pid, NULL, WNOHANG);
134 pg_usleep(1000000L);
135 }
136
137 psql_command("postgres", "CREATE DATABASE \"%s\" TEMPLATE=template0%s",
138 "dbfuzz", "");
139
140 snprintf(buf, sizeof(buf), "\"%s%spg_ctl\" stop -D \"%s/data\" -s", "",
141 "", temp_instance);
142 system(buf);
143
144 rmdir(sockdir);
145 return 0;
146 }
147