1/*
2 * util.c
3 *
4 * utility functions
5 *
6 * Copyright (c) 2010-2019, PostgreSQL Global Development Group
7 * src/bin/pg_upgrade/util.c
8 */
9
10#include "postgres_fe.h"
11
12#include "common/username.h"
13#include "pg_upgrade.h"
14
15#include <signal.h>
16
17
18LogOpts log_opts;
19
20static void pg_log_v(eLogType type, const char *fmt, va_list ap) pg_attribute_printf(2, 0);
21
22
23/*
24 * report_status()
25 *
26 * Displays the result of an operation (ok, failed, error message,...)
27 */
28void
29report_status(eLogType type, const char *fmt,...)
30{
31 va_list args;
32 char message[MAX_STRING];
33
34 va_start(args, fmt);
35 vsnprintf(message, sizeof(message), fmt, args);
36 va_end(args);
37
38 pg_log(type, "%s\n", message);
39}
40
41
42/* force blank output for progress display */
43void
44end_progress_output(void)
45{
46 /*
47 * In case nothing printed; pass a space so gcc doesn't complain about
48 * empty format string.
49 */
50 prep_status(" ");
51}
52
53
54/*
55 * prep_status
56 *
57 * Displays a message that describes an operation we are about to begin.
58 * We pad the message out to MESSAGE_WIDTH characters so that all of the "ok" and
59 * "failed" indicators line up nicely.
60 *
61 * A typical sequence would look like this:
62 * prep_status("about to flarb the next %d files", fileCount );
63 *
64 * if(( message = flarbFiles(fileCount)) == NULL)
65 * report_status(PG_REPORT, "ok" );
66 * else
67 * pg_log(PG_FATAL, "failed - %s\n", message );
68 */
69void
70prep_status(const char *fmt,...)
71{
72 va_list args;
73 char message[MAX_STRING];
74
75 va_start(args, fmt);
76 vsnprintf(message, sizeof(message), fmt, args);
77 va_end(args);
78
79 if (strlen(message) > 0 && message[strlen(message) - 1] == '\n')
80 pg_log(PG_REPORT, "%s", message);
81 else
82 /* trim strings that don't end in a newline */
83 pg_log(PG_REPORT, "%-*s", MESSAGE_WIDTH, message);
84}
85
86
87static void
88pg_log_v(eLogType type, const char *fmt, va_list ap)
89{
90 char message[QUERY_ALLOC];
91
92 vsnprintf(message, sizeof(message), _(fmt), ap);
93
94 /* PG_VERBOSE and PG_STATUS are only output in verbose mode */
95 /* fopen() on log_opts.internal might have failed, so check it */
96 if (((type != PG_VERBOSE && type != PG_STATUS) || log_opts.verbose) &&
97 log_opts.internal != NULL)
98 {
99 if (type == PG_STATUS)
100 /* status messages need two leading spaces and a newline */
101 fprintf(log_opts.internal, " %s\n", message);
102 else
103 fprintf(log_opts.internal, "%s", message);
104 fflush(log_opts.internal);
105 }
106
107 switch (type)
108 {
109 case PG_VERBOSE:
110 if (log_opts.verbose)
111 printf("%s", message);
112 break;
113
114 case PG_STATUS:
115 /* for output to a display, do leading truncation and append \r */
116 if (isatty(fileno(stdout)))
117 /* -2 because we use a 2-space indent */
118 printf(" %s%-*.*s\r",
119 /* prefix with "..." if we do leading truncation */
120 strlen(message) <= MESSAGE_WIDTH - 2 ? "" : "...",
121 MESSAGE_WIDTH - 2, MESSAGE_WIDTH - 2,
122 /* optional leading truncation */
123 strlen(message) <= MESSAGE_WIDTH - 2 ? message :
124 message + strlen(message) - MESSAGE_WIDTH + 3 + 2);
125 else
126 printf(" %s\n", message);
127 break;
128
129 case PG_REPORT:
130 case PG_WARNING:
131 printf("%s", message);
132 break;
133
134 case PG_FATAL:
135 printf("\n%s", message);
136 printf(_("Failure, exiting\n"));
137 exit(1);
138 break;
139
140 default:
141 break;
142 }
143 fflush(stdout);
144}
145
146
147void
148pg_log(eLogType type, const char *fmt,...)
149{
150 va_list args;
151
152 va_start(args, fmt);
153 pg_log_v(type, fmt, args);
154 va_end(args);
155}
156
157
158void
159pg_fatal(const char *fmt,...)
160{
161 va_list args;
162
163 va_start(args, fmt);
164 pg_log_v(PG_FATAL, fmt, args);
165 va_end(args);
166 printf(_("Failure, exiting\n"));
167 exit(1);
168}
169
170
171void
172check_ok(void)
173{
174 /* all seems well */
175 report_status(PG_REPORT, "ok");
176 fflush(stdout);
177}
178
179
180/*
181 * quote_identifier()
182 * Properly double-quote a SQL identifier.
183 *
184 * The result should be pg_free'd, but most callers don't bother because
185 * memory leakage is not a big deal in this program.
186 */
187char *
188quote_identifier(const char *s)
189{
190 char *result = pg_malloc(strlen(s) * 2 + 3);
191 char *r = result;
192
193 *r++ = '"';
194 while (*s)
195 {
196 if (*s == '"')
197 *r++ = *s;
198 *r++ = *s;
199 s++;
200 }
201 *r++ = '"';
202 *r++ = '\0';
203
204 return result;
205}
206
207
208/*
209 * get_user_info()
210 */
211int
212get_user_info(char **user_name_p)
213{
214 int user_id;
215 const char *user_name;
216 char *errstr;
217
218#ifndef WIN32
219 user_id = geteuid();
220#else
221 user_id = 1;
222#endif
223
224 user_name = get_user_name(&errstr);
225 if (!user_name)
226 pg_fatal("%s\n", errstr);
227
228 /* make a copy */
229 *user_name_p = pg_strdup(user_name);
230
231 return user_id;
232}
233
234
235/*
236 * str2uint()
237 *
238 * convert string to oid
239 */
240unsigned int
241str2uint(const char *str)
242{
243 return strtoul(str, NULL, 10);
244}
245
246
247/*
248 * pg_putenv()
249 *
250 * This is like putenv(), but takes two arguments.
251 * It also does unsetenv() if val is NULL.
252 */
253void
254pg_putenv(const char *var, const char *val)
255{
256 if (val)
257 {
258#ifndef WIN32
259 char *envstr;
260
261 envstr = psprintf("%s=%s", var, val);
262 putenv(envstr);
263
264 /*
265 * Do not free envstr because it becomes part of the environment on
266 * some operating systems. See port/unsetenv.c::unsetenv.
267 */
268#else
269 SetEnvironmentVariableA(var, val);
270#endif
271 }
272 else
273 {
274#ifndef WIN32
275 unsetenv(var);
276#else
277 SetEnvironmentVariableA(var, "");
278#endif
279 }
280}
281