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-2022, 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 void
43 {
44  /*
45  * For output to a tty, erase prior contents of progress line. When either
46  * tty or verbose, indent so that report_status() output will align
47  * nicely.
48  */
49  if (log_opts.isatty)
50  pg_log(PG_REPORT, "\r%-*s", MESSAGE_WIDTH, "");
51  else if (log_opts.verbose)
52  pg_log(PG_REPORT, "%-*s", MESSAGE_WIDTH, "");
53 }
54 
55 
56 /*
57  * prep_status
58  *
59  * Displays a message that describes an operation we are about to begin.
60  * We pad the message out to MESSAGE_WIDTH characters so that all of the "ok" and
61  * "failed" indicators line up nicely.
62  *
63  * A typical sequence would look like this:
64  * prep_status("about to flarb the next %d files", fileCount );
65  *
66  * if(( message = flarbFiles(fileCount)) == NULL)
67  * report_status(PG_REPORT, "ok" );
68  * else
69  * pg_log(PG_FATAL, "failed - %s\n", message );
70  */
71 void
72 prep_status(const char *fmt,...)
73 {
74  va_list args;
75  char message[MAX_STRING];
76 
77  va_start(args, fmt);
78  vsnprintf(message, sizeof(message), fmt, args);
79  va_end(args);
80 
81  /* trim strings */
82  pg_log(PG_REPORT, "%-*s", MESSAGE_WIDTH, message);
83 }
84 
85 /*
86  * prep_status_progress
87  *
88  * Like prep_status(), but for potentially longer running operations.
89  * Details about what item is currently being processed can be displayed
90  * with pg_log(PG_STATUS, ...). A typical sequence would look like this:
91  *
92  * prep_status_progress("copying files");
93  * for (...)
94  * pg_log(PG_STATUS, "%s", filename);
95  * end_progress_output();
96  * report_status(PG_REPORT, "ok");
97  */
98 void
99 prep_status_progress(const char *fmt,...)
100 {
101  va_list args;
102  char message[MAX_STRING];
103 
104  va_start(args, fmt);
105  vsnprintf(message, sizeof(message), fmt, args);
106  va_end(args);
107 
108  /*
109  * If outputting to a tty or in verbose, append newline. pg_log_v() will
110  * put the individual progress items onto the next line.
111  */
113  pg_log(PG_REPORT, "%-*s\n", MESSAGE_WIDTH, message);
114  else
115  pg_log(PG_REPORT, "%-*s", MESSAGE_WIDTH, message);
116 }
117 
118 static void
119 pg_log_v(eLogType type, const char *fmt, va_list ap)
120 {
121  char message[QUERY_ALLOC];
122 
123  vsnprintf(message, sizeof(message), _(fmt), ap);
124 
125  /* PG_VERBOSE and PG_STATUS are only output in verbose mode */
126  /* fopen() on log_opts.internal might have failed, so check it */
127  if (((type != PG_VERBOSE && type != PG_STATUS) || log_opts.verbose) &&
128  log_opts.internal != NULL)
129  {
130  if (type == PG_STATUS)
131  /* status messages need two leading spaces and a newline */
132  fprintf(log_opts.internal, " %s\n", message);
133  else
134  fprintf(log_opts.internal, "%s", message);
136  }
137 
138  switch (type)
139  {
140  case PG_VERBOSE:
141  if (log_opts.verbose)
142  printf("%s", message);
143  break;
144 
145  case PG_STATUS:
146 
147  /*
148  * For output to a display, do leading truncation. Append \r so
149  * that the next message is output at the start of the line.
150  *
151  * If going to non-interactive output, only display progress if
152  * verbose is enabled. Otherwise the output gets unreasonably
153  * large by default.
154  */
155  if (log_opts.isatty)
156  /* -2 because we use a 2-space indent */
157  printf(" %s%-*.*s\r",
158  /* prefix with "..." if we do leading truncation */
159  strlen(message) <= MESSAGE_WIDTH - 2 ? "" : "...",
160  MESSAGE_WIDTH - 2, MESSAGE_WIDTH - 2,
161  /* optional leading truncation */
162  strlen(message) <= MESSAGE_WIDTH - 2 ? message :
163  message + strlen(message) - MESSAGE_WIDTH + 3 + 2);
164  else if (log_opts.verbose)
165  printf(" %s\n", message);
166  break;
167 
168  case PG_REPORT:
169  case PG_WARNING:
170  printf("%s", message);
171  break;
172 
173  case PG_FATAL:
174  printf("\n%s", message);
175  printf(_("Failure, exiting\n"));
176  exit(1);
177  break;
178 
179  default:
180  break;
181  }
182  fflush(stdout);
183 }
184 
185 
186 void
187 pg_log(eLogType type, const char *fmt,...)
188 {
189  va_list args;
190 
191  va_start(args, fmt);
192  pg_log_v(type, fmt, args);
193  va_end(args);
194 }
195 
196 
197 void
198 pg_fatal(const char *fmt,...)
199 {
200  va_list args;
201 
202  va_start(args, fmt);
204  va_end(args);
205  printf(_("Failure, exiting\n"));
206  exit(1);
207 }
208 
209 
210 void
211 check_ok(void)
212 {
213  /* all seems well */
214  report_status(PG_REPORT, "ok");
215  fflush(stdout);
216 }
217 
218 
219 /*
220  * quote_identifier()
221  * Properly double-quote a SQL identifier.
222  *
223  * The result should be pg_free'd, but most callers don't bother because
224  * memory leakage is not a big deal in this program.
225  */
226 char *
227 quote_identifier(const char *s)
228 {
229  char *result = pg_malloc(strlen(s) * 2 + 3);
230  char *r = result;
231 
232  *r++ = '"';
233  while (*s)
234  {
235  if (*s == '"')
236  *r++ = *s;
237  *r++ = *s;
238  s++;
239  }
240  *r++ = '"';
241  *r++ = '\0';
242 
243  return result;
244 }
245 
246 
247 /*
248  * get_user_info()
249  */
250 int
251 get_user_info(char **user_name_p)
252 {
253  int user_id;
254  const char *user_name;
255  char *errstr;
256 
257 #ifndef WIN32
258  user_id = geteuid();
259 #else
260  user_id = 1;
261 #endif
262 
263  user_name = get_user_name(&errstr);
264  if (!user_name)
265  pg_fatal("%s\n", errstr);
266 
267  /* make a copy */
268  *user_name_p = pg_strdup(user_name);
269 
270  return user_id;
271 }
272 
273 
274 /*
275  * str2uint()
276  *
277  * convert string to oid
278  */
279 unsigned int
280 str2uint(const char *str)
281 {
282  return strtoul(str, NULL, 10);
283 }
#define pg_attribute_printf(f, a)
Definition: c.h:164
#define _(x)
Definition: elog.c:89
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
static void const char fflush(stdout)
va_end(args)
exit(1)
static void const char * fmt
va_start(args, fmt)
#define MESSAGE_WIDTH
Definition: pg_upgrade.h:24
#define QUERY_ALLOC
Definition: pg_upgrade.h:22
eLogType
Definition: pg_upgrade.h:234
@ PG_FATAL
Definition: pg_upgrade.h:239
@ PG_STATUS
Definition: pg_upgrade.h:236
@ PG_WARNING
Definition: pg_upgrade.h:238
@ PG_VERBOSE
Definition: pg_upgrade.h:235
@ PG_REPORT
Definition: pg_upgrade.h:237
#define MAX_STRING
Definition: pg_upgrade.h:21
#define vsnprintf
Definition: port.h:224
#define fprintf
Definition: port.h:229
#define printf(...)
Definition: port.h:231
FILE * internal
Definition: pg_upgrade.h:275
bool isatty
Definition: pg_upgrade.h:282
bool verbose
Definition: pg_upgrade.h:276
const char * get_user_name(char **errstr)
Definition: username.c:31
void pg_fatal(const char *fmt,...)
Definition: util.c:198
unsigned int str2uint(const char *str)
Definition: util.c:280
void pg_log(eLogType type, const char *fmt,...)
Definition: util.c:187
void prep_status_progress(const char *fmt,...)
Definition: util.c:99
int get_user_info(char **user_name_p)
Definition: util.c:251
static void void report_status(eLogType type, const char *fmt,...)
Definition: util.c:28
LogOpts log_opts
Definition: util.c:17
char * quote_identifier(const char *s)
Definition: util.c:227
void check_ok(void)
Definition: util.c:211
void prep_status(const char *fmt,...)
Definition: util.c:72
static void pg_log_v(eLogType type, const char *fmt, va_list ap) pg_attribute_printf(2
Definition: util.c:119
void end_progress_output(void)
Definition: util.c:42