LCOV - code coverage report
Current view: top level - src/bin/pg_upgrade - util.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 80.5 % 113 91
Test Date: 2026-03-16 22:14:56 Functions: 100.0 % 12 12
Legend: Lines:     hit not hit

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

Generated by: LCOV version 2.0-1