LCOV - code coverage report
Current view: top level - src/bin/pg_upgrade - util.c (source / functions) Hit Total Coverage
Test: PostgreSQL 16devel Lines: 86 111 77.5 %
Date: 2022-12-05 11:11:09 Functions: 11 12 91.7 %
Legend: Lines: hit not hit

          Line data    Source code
       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             : 
      17             : LogOpts     log_opts;
      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             :  *  This is no longer functionally different from pg_log(), but we keep
      28             :  *  it around to maintain a notational distinction between operation
      29             :  *  results and other messages.
      30             :  */
      31             : void
      32          88 : report_status(eLogType type, const char *fmt,...)
      33             : {
      34             :     va_list     args;
      35             : 
      36          88 :     va_start(args, fmt);
      37          88 :     pg_log_v(type, fmt, args);
      38          86 :     va_end(args);
      39          86 : }
      40             : 
      41             : 
      42             : void
      43           6 : end_progress_output(void)
      44             : {
      45             :     /*
      46             :      * For output to a tty, erase prior contents of progress line. When either
      47             :      * tty or verbose, indent so that report_status() output will align
      48             :      * nicely.
      49             :      */
      50           6 :     if (log_opts.isatty)
      51             :     {
      52           0 :         printf("\r");
      53           0 :         pg_log(PG_REPORT_NONL, "%-*s", MESSAGE_WIDTH, "");
      54             :     }
      55           6 :     else if (log_opts.verbose)
      56           0 :         pg_log(PG_REPORT_NONL, "%-*s", MESSAGE_WIDTH, "");
      57           6 : }
      58             : 
      59             : /*
      60             :  * Remove any logs generated internally.  To be used once when exiting.
      61             :  */
      62             : void
      63           4 : cleanup_output_dirs(void)
      64             : {
      65           4 :     fclose(log_opts.internal);
      66             : 
      67             :     /* Remove dump and log files? */
      68           4 :     if (log_opts.retain)
      69           0 :         return;
      70             : 
      71           4 :     (void) rmtree(log_opts.basedir, true);
      72             : 
      73             :     /* Remove pg_upgrade_output.d only if empty */
      74           4 :     switch (pg_check_dir(log_opts.rootdir))
      75             :     {
      76           0 :         case 0:                 /* non-existent */
      77             :         case 3:                 /* exists and contains a mount point */
      78             :             Assert(false);
      79           0 :             break;
      80             : 
      81           4 :         case 1:                 /* exists and empty */
      82             :         case 2:                 /* exists and contains only dot files */
      83           4 :             (void) rmtree(log_opts.rootdir, true);
      84           4 :             break;
      85             : 
      86           0 :         case 4:                 /* exists */
      87             : 
      88             :             /*
      89             :              * Keep the root directory as this includes some past log
      90             :              * activity.
      91             :              */
      92           0 :             break;
      93             : 
      94           0 :         default:
      95             :             /* different failure, just report it */
      96           0 :             pg_log(PG_WARNING, "could not access directory \"%s\": %m",
      97             :                    log_opts.rootdir);
      98           0 :             break;
      99             :     }
     100             : }
     101             : 
     102             : /*
     103             :  * prep_status
     104             :  *
     105             :  *  Displays a message that describes an operation we are about to begin.
     106             :  *  We pad the message out to MESSAGE_WIDTH characters so that all of the
     107             :  *  "ok" and "failed" indicators line up nicely.  (Overlength messages
     108             :  *  will be truncated, so don't get too verbose.)
     109             :  *
     110             :  *  A typical sequence would look like this:
     111             :  *      prep_status("about to flarb the next %d files", fileCount);
     112             :  *      if ((message = flarbFiles(fileCount)) == NULL)
     113             :  *        report_status(PG_REPORT, "ok");
     114             :  *      else
     115             :  *        pg_log(PG_FATAL, "failed: %s", message);
     116             :  */
     117             : void
     118          80 : prep_status(const char *fmt,...)
     119             : {
     120             :     va_list     args;
     121             :     char        message[MAX_STRING];
     122             : 
     123          80 :     va_start(args, fmt);
     124          80 :     vsnprintf(message, sizeof(message), fmt, args);
     125          80 :     va_end(args);
     126             : 
     127             :     /* trim strings */
     128          80 :     pg_log(PG_REPORT_NONL, "%-*s", MESSAGE_WIDTH, message);
     129          80 : }
     130             : 
     131             : /*
     132             :  * prep_status_progress
     133             :  *
     134             :  *   Like prep_status(), but for potentially longer running operations.
     135             :  *   Details about what item is currently being processed can be displayed
     136             :  *   with pg_log(PG_STATUS, ...). A typical sequence would look like this:
     137             :  *
     138             :  *   prep_status_progress("copying files");
     139             :  *   for (...)
     140             :  *     pg_log(PG_STATUS, "%s", filename);
     141             :  *   end_progress_output();
     142             :  *   report_status(PG_REPORT, "ok");
     143             :  */
     144             : void
     145           6 : prep_status_progress(const char *fmt,...)
     146             : {
     147             :     va_list     args;
     148             :     char        message[MAX_STRING];
     149             : 
     150           6 :     va_start(args, fmt);
     151           6 :     vsnprintf(message, sizeof(message), fmt, args);
     152           6 :     va_end(args);
     153             : 
     154             :     /*
     155             :      * If outputting to a tty or in verbose, append newline. pg_log_v() will
     156             :      * put the individual progress items onto the next line.
     157             :      */
     158           6 :     if (log_opts.isatty || log_opts.verbose)
     159           0 :         pg_log(PG_REPORT, "%-*s", MESSAGE_WIDTH, message);
     160             :     else
     161           6 :         pg_log(PG_REPORT_NONL, "%-*s", MESSAGE_WIDTH, message);
     162           6 : }
     163             : 
     164             : static void
     165        7166 : pg_log_v(eLogType type, const char *fmt, va_list ap)
     166             : {
     167             :     char        message[QUERY_ALLOC];
     168             : 
     169             :     /* No incoming message should end in newline; we add that here. */
     170             :     Assert(fmt);
     171             :     Assert(fmt[0] == '\0' || fmt[strlen(fmt) - 1] != '\n');
     172             : 
     173        7166 :     vsnprintf(message, sizeof(message), _(fmt), ap);
     174             : 
     175             :     /* PG_VERBOSE and PG_STATUS are only output in verbose mode */
     176             :     /* fopen() on log_opts.internal might have failed, so check it */
     177        7166 :     if (((type != PG_VERBOSE && type != PG_STATUS) || log_opts.verbose) &&
     178         190 :         log_opts.internal != NULL)
     179             :     {
     180         190 :         if (type == PG_STATUS)
     181             :             /* status messages get two leading spaces, see below */
     182           0 :             fprintf(log_opts.internal, "  %s\n", message);
     183         190 :         else if (type == PG_REPORT_NONL)
     184          86 :             fprintf(log_opts.internal, "%s", message);
     185             :         else
     186         104 :             fprintf(log_opts.internal, "%s\n", message);
     187         190 :         fflush(log_opts.internal);
     188             :     }
     189             : 
     190        7166 :     switch (type)
     191             :     {
     192        3842 :         case PG_VERBOSE:
     193        3842 :             if (log_opts.verbose)
     194           0 :                 printf("%s\n", message);
     195        3842 :             break;
     196             : 
     197        3134 :         case PG_STATUS:
     198             : 
     199             :             /*
     200             :              * For output to a terminal, we add two leading spaces and no
     201             :              * newline; instead append \r so that the next message is output
     202             :              * on the same line.  Truncate on the left to fit into
     203             :              * MESSAGE_WIDTH (counting the spaces as part of that).
     204             :              *
     205             :              * If going to non-interactive output, only display progress if
     206             :              * verbose is enabled. Otherwise the output gets unreasonably
     207             :              * large by default.
     208             :              */
     209        3134 :             if (log_opts.isatty)
     210             :             {
     211           0 :                 bool        itfits = (strlen(message) <= MESSAGE_WIDTH - 2);
     212             : 
     213             :                 /* prefix with "..." if we do leading truncation */
     214           0 :                 printf("  %s%-*.*s\r",
     215             :                        itfits ? "" : "...",
     216             :                        MESSAGE_WIDTH - 2, MESSAGE_WIDTH - 2,
     217             :                        itfits ? message :
     218             :                        message + strlen(message) - MESSAGE_WIDTH + 3 + 2);
     219             :             }
     220        3134 :             else if (log_opts.verbose)
     221           0 :                 printf("  %s\n", message);
     222        3134 :             break;
     223             : 
     224          86 :         case PG_REPORT_NONL:
     225             :             /* This option is for use by prep_status and friends */
     226          86 :             printf("%s", message);
     227          86 :             break;
     228             : 
     229         102 :         case PG_REPORT:
     230             :         case PG_WARNING:
     231         102 :             printf("%s\n", message);
     232         102 :             break;
     233             : 
     234           2 :         case PG_FATAL:
     235             :             /* Extra newline in case we're interrupting status output */
     236           2 :             printf("\n%s\n", message);
     237           2 :             printf(_("Failure, exiting\n"));
     238           2 :             exit(1);
     239             :             break;
     240             : 
     241             :             /* No default:, we want a warning for omitted cases */
     242             :     }
     243        7164 :     fflush(stdout);
     244        7164 : }
     245             : 
     246             : 
     247             : void
     248        7078 : pg_log(eLogType type, const char *fmt,...)
     249             : {
     250             :     va_list     args;
     251             : 
     252        7078 :     va_start(args, fmt);
     253        7078 :     pg_log_v(type, fmt, args);
     254        7078 :     va_end(args);
     255        7078 : }
     256             : 
     257             : 
     258             : void
     259           0 : pg_fatal(const char *fmt,...)
     260             : {
     261             :     va_list     args;
     262             : 
     263           0 :     va_start(args, fmt);
     264           0 :     pg_log_v(PG_FATAL, fmt, args);
     265           0 :     va_end(args);
     266             :     /* NOTREACHED */
     267           0 :     printf(_("Failure, exiting\n"));
     268           0 :     exit(1);
     269             : }
     270             : 
     271             : 
     272             : void
     273          86 : check_ok(void)
     274             : {
     275             :     /* all seems well */
     276          86 :     report_status(PG_REPORT, "ok");
     277          86 : }
     278             : 
     279             : 
     280             : /*
     281             :  * quote_identifier()
     282             :  *      Properly double-quote a SQL identifier.
     283             :  *
     284             :  * The result should be pg_free'd, but most callers don't bother because
     285             :  * memory leakage is not a big deal in this program.
     286             :  */
     287             : char *
     288           4 : quote_identifier(const char *s)
     289             : {
     290           4 :     char       *result = pg_malloc(strlen(s) * 2 + 3);
     291           4 :     char       *r = result;
     292             : 
     293           4 :     *r++ = '"';
     294          40 :     while (*s)
     295             :     {
     296          36 :         if (*s == '"')
     297           0 :             *r++ = *s;
     298          36 :         *r++ = *s;
     299          36 :         s++;
     300             :     }
     301           4 :     *r++ = '"';
     302           4 :     *r++ = '\0';
     303             : 
     304           4 :     return result;
     305             : }
     306             : 
     307             : 
     308             : /*
     309             :  * get_user_info()
     310             :  */
     311             : int
     312          12 : get_user_info(char **user_name_p)
     313             : {
     314             :     int         user_id;
     315             :     const char *user_name;
     316             :     char       *errstr;
     317             : 
     318             : #ifndef WIN32
     319          12 :     user_id = geteuid();
     320             : #else
     321             :     user_id = 1;
     322             : #endif
     323             : 
     324          12 :     user_name = get_user_name(&errstr);
     325          12 :     if (!user_name)
     326           0 :         pg_fatal("%s", errstr);
     327             : 
     328             :     /* make a copy */
     329          12 :     *user_name_p = pg_strdup(user_name);
     330             : 
     331          12 :     return user_id;
     332             : }
     333             : 
     334             : 
     335             : /*
     336             :  *  str2uint()
     337             :  *
     338             :  *  convert string to oid
     339             :  */
     340             : unsigned int
     341         160 : str2uint(const char *str)
     342             : {
     343         160 :     return strtoul(str, NULL, 10);
     344             : }

Generated by: LCOV version 1.14