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