LCOV - code coverage report
Current view: top level - src/bin/pg_upgrade - util.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 80.5 % 113 91
Test Date: 2026-07-03 19:57:34 Functions: 100.0 % 12 12
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 57.7 % 52 30

             Branch data     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                 :         454 : report_status(eLogType type, const char *fmt, ...)
      33                 :             : {
      34                 :             :     va_list     args;
      35                 :             : 
      36                 :         454 :     va_start(args, fmt);
      37                 :         454 :     pg_log_v(type, fmt, args);
      38                 :         453 :     va_end(args);
      39                 :         453 : }
      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                 :         427 : prep_status(const char *fmt, ...)
     130                 :             : {
     131                 :             :     va_list     args;
     132                 :             :     char        message[MAX_STRING];
     133                 :             : 
     134                 :         427 :     va_start(args, fmt);
     135                 :         427 :     vsnprintf(message, sizeof(message), fmt, args);
     136                 :         427 :     va_end(args);
     137                 :             : 
     138                 :             :     /* trim strings */
     139                 :         427 :     pg_log(PG_REPORT_NONL, "%-*s", MESSAGE_WIDTH, message);
     140                 :         427 : }
     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                 :        7611 : 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                 :        7611 :     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   [ +  +  +  +  :        7611 :     if (((type != PG_VERBOSE && type != PG_STATUS) || log_opts.verbose) &&
                   -  + ]
     189         [ +  - ]:         997 :         log_opts.internal != NULL)
     190                 :             :     {
     191         [ -  + ]:         997 :         if (type == PG_STATUS)
     192                 :             :             /* status messages get two leading spaces, see below */
     193                 :           0 :             fprintf(log_opts.internal, "  %s\n", message);
     194         [ +  + ]:         997 :         else if (type == PG_REPORT_NONL)
     195                 :         460 :             fprintf(log_opts.internal, "%s", message);
     196                 :             :         else
     197                 :         537 :             fprintf(log_opts.internal, "%s\n", message);
     198                 :         997 :         fflush(log_opts.internal);
     199                 :             :     }
     200                 :             : 
     201   [ +  +  +  +  :        7611 :     switch (type)
                   +  - ]
     202                 :             :     {
     203                 :        4493 :         case PG_VERBOSE:
     204         [ -  + ]:        4493 :             if (log_opts.verbose)
     205                 :           0 :                 printf("%s\n", message);
     206                 :        4493 :             break;
     207                 :             : 
     208                 :        2121 :         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         [ -  + ]:        2121 :             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         [ -  + ]:        2121 :             else if (log_opts.verbose)
     232                 :           0 :                 printf("  %s\n", message);
     233                 :        2121 :             break;
     234                 :             : 
     235                 :         460 :         case PG_REPORT_NONL:
     236                 :             :             /* This option is for use by prep_status and friends */
     237                 :         460 :             printf("%s", message);
     238                 :         460 :             break;
     239                 :             : 
     240                 :         528 :         case PG_REPORT:
     241                 :             :         case PG_WARNING:
     242                 :         528 :             printf("%s\n", message);
     243                 :         528 :             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                 :        7602 :     fflush(stdout);
     255                 :        7602 : }
     256                 :             : 
     257                 :             : 
     258                 :             : void
     259                 :        7149 : pg_log(eLogType type, const char *fmt, ...)
     260                 :             : {
     261                 :             :     va_list     args;
     262                 :             : 
     263                 :        7149 :     va_start(args, fmt);
     264                 :        7149 :     pg_log_v(type, fmt, args);
     265                 :        7149 :     va_end(args);
     266                 :        7149 : }
     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                 :         453 : check_ok(void)
     285                 :             : {
     286                 :             :     /* all seems well */
     287                 :         453 :     report_status(PG_REPORT, "ok");
     288                 :         453 : }
     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                 :         684 : str2uint(const char *str)
     353                 :             : {
     354                 :         684 :     return strtoul(str, NULL, 10);
     355                 :             : }
        

Generated by: LCOV version 2.0-1