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 | |
18 | LogOpts log_opts; |
19 | |
20 | static 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 | */ |
28 | void |
29 | report_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 */ |
43 | void |
44 | end_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 | */ |
69 | void |
70 | prep_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 | |
87 | static void |
88 | pg_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 | |
147 | void |
148 | pg_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 | |
158 | void |
159 | pg_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 | |
171 | void |
172 | check_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 | */ |
187 | char * |
188 | quote_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 | */ |
211 | int |
212 | get_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 | */ |
240 | unsigned int |
241 | str2uint(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 | */ |
253 | void |
254 | pg_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 | |