LCOV - code coverage report
Current view: top level - src/bin/pg_upgrade - util.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 91 113 80.5 %
Date: 2024-11-21 09:14:53 Functions: 12 12 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  *  util.c
       3             :  *
       4             :  *  utility functions
       5             :  *
       6             :  *  Copyright (c) 2010-2024, 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         312 : report_status(eLogType type, const char *fmt,...)
      33             : {
      34             :     va_list     args;
      35             : 
      36         312 :     va_start(args, fmt);
      37         312 :     pg_log_v(type, fmt, args);
      38         310 :     va_end(args);
      39         310 : }
      40             : 
      41             : 
      42             : void
      43          22 : 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          22 :     if (log_opts.isatty)
      51             :     {
      52           0 :         printf("\r");
      53           0 :         pg_log(PG_REPORT_NONL, "%-*s", MESSAGE_WIDTH, "");
      54             :     }
      55          22 :     else if (log_opts.verbose)
      56           0 :         pg_log(PG_REPORT_NONL, "%-*s", MESSAGE_WIDTH, "");
      57          22 : }
      58             : 
      59             : /*
      60             :  * Remove any logs generated internally.  To be used once when exiting.
      61             :  */
      62             : void
      63           8 : cleanup_output_dirs(void)
      64             : {
      65           8 :     fclose(log_opts.internal);
      66             : 
      67             :     /* Remove dump and log files? */
      68           8 :     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           8 :     if (!rmtree(log_opts.basedir, true))
      76           0 :         rmtree(log_opts.basedir, true);
      77             : 
      78             :     /* Remove pg_upgrade_output.d only if empty */
      79           8 :     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           6 :         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           6 :             if (!rmtree(log_opts.rootdir, true))
      94           0 :                 rmtree(log_opts.rootdir, true);
      95           6 :             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         298 : prep_status(const char *fmt,...)
     130             : {
     131             :     va_list     args;
     132             :     char        message[MAX_STRING];
     133             : 
     134         298 :     va_start(args, fmt);
     135         298 :     vsnprintf(message, sizeof(message), fmt, args);
     136         298 :     va_end(args);
     137             : 
     138             :     /* trim strings */
     139         298 :     pg_log(PG_REPORT_NONL, "%-*s", MESSAGE_WIDTH, message);
     140         298 : }
     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          22 : prep_status_progress(const char *fmt,...)
     157             : {
     158             :     va_list     args;
     159             :     char        message[MAX_STRING];
     160             : 
     161          22 :     va_start(args, fmt);
     162          22 :     vsnprintf(message, sizeof(message), fmt, args);
     163          22 :     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          22 :     if (log_opts.isatty || log_opts.verbose)
     170           0 :         pg_log(PG_REPORT, "%-*s", MESSAGE_WIDTH, message);
     171             :     else
     172          22 :         pg_log(PG_REPORT_NONL, "%-*s", MESSAGE_WIDTH, message);
     173          22 : }
     174             : 
     175             : static void
     176        9410 : 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        9410 :     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        9410 :     if (((type != PG_VERBOSE && type != PG_STATUS) || log_opts.verbose) &&
     189         698 :         log_opts.internal != NULL)
     190             :     {
     191         698 :         if (type == PG_STATUS)
     192             :             /* status messages get two leading spaces, see below */
     193           0 :             fprintf(log_opts.internal, "  %s\n", message);
     194         698 :         else if (type == PG_REPORT_NONL)
     195         320 :             fprintf(log_opts.internal, "%s", message);
     196             :         else
     197         378 :             fprintf(log_opts.internal, "%s\n", message);
     198         698 :         fflush(log_opts.internal);
     199             :     }
     200             : 
     201        9410 :     switch (type)
     202             :     {
     203        5364 :         case PG_VERBOSE:
     204        5364 :             if (log_opts.verbose)
     205           0 :                 printf("%s\n", message);
     206        5364 :             break;
     207             : 
     208        3348 :         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        3348 :             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        3348 :             else if (log_opts.verbose)
     232           0 :                 printf("  %s\n", message);
     233        3348 :             break;
     234             : 
     235         320 :         case PG_REPORT_NONL:
     236             :             /* This option is for use by prep_status and friends */
     237         320 :             printf("%s", message);
     238         320 :             break;
     239             : 
     240         366 :         case PG_REPORT:
     241             :         case PG_WARNING:
     242         366 :             printf("%s\n", message);
     243         366 :             break;
     244             : 
     245          12 :         case PG_FATAL:
     246             :             /* Extra newline in case we're interrupting status output */
     247          12 :             printf("\n%s\n", message);
     248          12 :             printf(_("Failure, exiting\n"));
     249          12 :             exit(1);
     250             :             break;
     251             : 
     252             :             /* No default:, we want a warning for omitted cases */
     253             :     }
     254        9398 :     fflush(stdout);
     255        9398 : }
     256             : 
     257             : 
     258             : void
     259        9088 : pg_log(eLogType type, const char *fmt,...)
     260             : {
     261             :     va_list     args;
     262             : 
     263        9088 :     va_start(args, fmt);
     264        9088 :     pg_log_v(type, fmt, args);
     265        9088 :     va_end(args);
     266        9088 : }
     267             : 
     268             : 
     269             : void
     270          10 : pg_fatal(const char *fmt,...)
     271             : {
     272             :     va_list     args;
     273             : 
     274          10 :     va_start(args, fmt);
     275          10 :     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         310 : check_ok(void)
     285             : {
     286             :     /* all seems well */
     287         310 :     report_status(PG_REPORT, "ok");
     288         310 : }
     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          12 : quote_identifier(const char *s)
     300             : {
     301          12 :     char       *result = pg_malloc(strlen(s) * 2 + 3);
     302          12 :     char       *r = result;
     303             : 
     304          12 :     *r++ = '"';
     305         120 :     while (*s)
     306             :     {
     307         108 :         if (*s == '"')
     308           0 :             *r++ = *s;
     309         108 :         *r++ = *s;
     310         108 :         s++;
     311             :     }
     312          12 :     *r++ = '"';
     313          12 :     *r++ = '\0';
     314             : 
     315          12 :     return result;
     316             : }
     317             : 
     318             : 
     319             : /*
     320             :  * get_user_info()
     321             :  */
     322             : int
     323          26 : 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          26 :     user_id = geteuid();
     331             : #else
     332             :     user_id = 1;
     333             : #endif
     334             : 
     335          26 :     user_name = get_user_name(&errstr);
     336          26 :     if (!user_name)
     337           0 :         pg_fatal("%s", errstr);
     338             : 
     339             :     /* make a copy */
     340          26 :     *user_name_p = pg_strdup(user_name);
     341             : 
     342          26 :     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 1.14