LCOV - differential code coverage report
Current view: top level - src/bin/pg_upgrade - util.c (source / functions) Coverage Total Hit UNC LBC UIC UBC GBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 76.5 % 115 88 9 7 10 1 7 54 14 13 14 58 5 10
Current Date: 2023-04-08 15:15:32 Functions: 91.7 % 12 11 1 11 1 10 1
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : /*
       2                 :  *  util.c
       3                 :  *
       4                 :  *  utility functions
       5                 :  *
       6                 :  *  Copyright (c) 2010-2023, 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 GIC          45 : report_status(eLogType type, const char *fmt,...)
      33                 : {
      34                 :     va_list     args;
      35 ECB             : 
      36 GIC          45 :     va_start(args, fmt);
      37 GNC          45 :     pg_log_v(type, fmt, args);
      38 GIC          44 :     va_end(args);
      39 CBC          44 : }
      40 ECB             : 
      41                 : 
      42                 : void
      43 GIC           3 : end_progress_output(void)
      44 ECB             : {
      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 GIC           3 :     if (log_opts.isatty)
      51 ECB             :     {
      52 UIC           0 :         printf("\r");
      53 UNC           0 :         pg_log(PG_REPORT_NONL, "%-*s", MESSAGE_WIDTH, "");
      54 EUB             :     }
      55 GIC           3 :     else if (log_opts.verbose)
      56 UNC           0 :         pg_log(PG_REPORT_NONL, "%-*s", MESSAGE_WIDTH, "");
      57 GBC           3 : }
      58 ECB             : 
      59                 : /*
      60                 :  * Remove any logs generated internally.  To be used once when exiting.
      61                 :  */
      62                 : void
      63 GIC           2 : cleanup_output_dirs(void)
      64 ECB             : {
      65 GIC           2 :     fclose(log_opts.internal);
      66 ECB             : 
      67                 :     /* Remove dump and log files? */
      68 GIC           2 :     if (log_opts.retain)
      69 LBC           0 :         return;
      70 EUB             : 
      71                 :     /*
      72                 :      * Try twice.  The second time might wait for files to finish being
      73                 :      * unlinked, on Windows.
      74                 :      */
      75 GNC           2 :     if (!rmtree(log_opts.basedir, true))
      76 UNC           0 :         rmtree(log_opts.basedir, true);
      77                 : 
      78                 :     /* Remove pg_upgrade_output.d only if empty */
      79 GIC           2 :     switch (pg_check_dir(log_opts.rootdir))
      80                 :     {
      81 LBC           0 :         case 0:                 /* non-existent */
      82 EUB             :         case 3:                 /* exists and contains a mount point */
      83 UIC           0 :             Assert(false);
      84                 :             break;
      85 ECB             : 
      86 GIC           2 :         case 1:                 /* exists and empty */
      87 EUB             :         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 GNC           2 :             if (!rmtree(log_opts.rootdir, true))
      94 UNC           0 :                 rmtree(log_opts.rootdir, true);
      95 GBC           2 :             break;
      96                 : 
      97 UIC           0 :         case 4:                 /* exists */
      98 ECB             : 
      99                 :             /*
     100                 :              * Keep the root directory as this includes some past log
     101                 :              * activity.
     102                 :              */
     103 UIC           0 :             break;
     104                 : 
     105 LBC           0 :         default:
     106 EUB             :             /* different failure, just report it */
     107 UNC           0 :             pg_log(PG_WARNING, "could not access directory \"%s\": %m",
     108                 :                    log_opts.rootdir);
     109 UBC           0 :             break;
     110                 :     }
     111                 : }
     112                 : 
     113                 : /*
     114                 :  * prep_status
     115 EUB             :  *
     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 GIC          41 : prep_status(const char *fmt,...)
     130                 : {
     131                 :     va_list     args;
     132                 :     char        message[MAX_STRING];
     133                 : 
     134              41 :     va_start(args, fmt);
     135              41 :     vsnprintf(message, sizeof(message), fmt, args);
     136              41 :     va_end(args);
     137                 : 
     138                 :     /* trim strings */
     139 GNC          41 :     pg_log(PG_REPORT_NONL, "%-*s", MESSAGE_WIDTH, message);
     140 GIC          41 : }
     141 ECB             : 
     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 GIC           3 : prep_status_progress(const char *fmt,...)
     157                 : {
     158                 :     va_list     args;
     159                 :     char        message[MAX_STRING];
     160                 : 
     161               3 :     va_start(args, fmt);
     162               3 :     vsnprintf(message, sizeof(message), fmt, args);
     163               3 :     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 ECB             :      */
     169 GIC           3 :     if (log_opts.isatty || log_opts.verbose)
     170 UIC           0 :         pg_log(PG_REPORT, "%-*s", MESSAGE_WIDTH, message);
     171                 :     else
     172 GNC           3 :         pg_log(PG_REPORT_NONL, "%-*s", MESSAGE_WIDTH, message);
     173 CBC           3 : }
     174 ECB             : 
     175                 : static void
     176 GIC        3609 : 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 GNC        3609 :     Assert(fmt);
     182            3609 :     Assert(fmt[0] == '\0' || fmt[strlen(fmt) - 1] != '\n');
     183                 : 
     184 GIC        3609 :     vsnprintf(message, sizeof(message), _(fmt), ap);
     185 ECB             : 
     186 EUB             :     /* PG_VERBOSE and PG_STATUS are only output in verbose mode */
     187                 :     /* fopen() on log_opts.internal might have failed, so check it */
     188 CBC        3609 :     if (((type != PG_VERBOSE && type != PG_STATUS) || log_opts.verbose) &&
     189              97 :         log_opts.internal != NULL)
     190                 :     {
     191 GIC          97 :         if (type == PG_STATUS)
     192                 :             /* status messages get two leading spaces, see below */
     193 UIC           0 :             fprintf(log_opts.internal, "  %s\n", message);
     194 GNC          97 :         else if (type == PG_REPORT_NONL)
     195 GIC          44 :             fprintf(log_opts.internal, "%s", message);
     196                 :         else
     197 GNC          53 :             fprintf(log_opts.internal, "%s\n", message);
     198 GIC          97 :         fflush(log_opts.internal);
     199 ECB             :     }
     200                 : 
     201 GIC        3609 :     switch (type)
     202 ECB             :     {
     203 GIC        1939 :         case PG_VERBOSE:
     204            1939 :             if (log_opts.verbose)
     205 UNC           0 :                 printf("%s\n", message);
     206 CBC        1939 :             break;
     207 ECB             : 
     208 GIC        1573 :         case PG_STATUS:
     209 ECB             : 
     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 GIC        1573 :             if (log_opts.isatty)
     221                 :             {
     222 UNC           0 :                 bool        itfits = (strlen(message) <= MESSAGE_WIDTH - 2);
     223                 : 
     224 ECB             :                 /* prefix with "..." if we do leading truncation */
     225 UNC           0 :                 printf("  %s%-*.*s\r",
     226                 :                        itfits ? "" : "...",
     227 EUB             :                        MESSAGE_WIDTH - 2, MESSAGE_WIDTH - 2,
     228                 :                        itfits ? message :
     229 ECB             :                        message + strlen(message) - MESSAGE_WIDTH + 3 + 2);
     230                 :             }
     231 GIC        1573 :             else if (log_opts.verbose)
     232 UIC           0 :                 printf("  %s\n", message);
     233 GIC        1573 :             break;
     234                 : 
     235 GNC          44 :         case PG_REPORT_NONL:
     236                 :             /* This option is for use by prep_status and friends */
     237 GIC          44 :             printf("%s", message);
     238              44 :             break;
     239                 : 
     240 GNC          52 :         case PG_REPORT:
     241                 :         case PG_WARNING:
     242              52 :             printf("%s\n", message);
     243              52 :             break;
     244                 : 
     245 GIC           1 :         case PG_FATAL:
     246                 :             /* Extra newline in case we're interrupting status output */
     247 GNC           1 :             printf("\n%s\n", message);
     248 CBC           1 :             printf(_("Failure, exiting\n"));
     249 GIC           1 :             exit(1);
     250 EUB             :             break;
     251                 : 
     252                 :             /* No default:, we want a warning for omitted cases */
     253                 :     }
     254 GIC        3608 :     fflush(stdout);
     255            3608 : }
     256                 : 
     257                 : 
     258 ECB             : void
     259 GBC        3564 : pg_log(eLogType type, const char *fmt,...)
     260 ECB             : {
     261                 :     va_list     args;
     262                 : 
     263 GIC        3564 :     va_start(args, fmt);
     264 CBC        3564 :     pg_log_v(type, fmt, args);
     265            3564 :     va_end(args);
     266 GIC        3564 : }
     267 ECB             : 
     268                 : 
     269                 : void
     270 LBC           0 : pg_fatal(const char *fmt,...)
     271                 : {
     272 ECB             :     va_list     args;
     273                 : 
     274 LBC           0 :     va_start(args, fmt);
     275               0 :     pg_log_v(PG_FATAL, fmt, args);
     276               0 :     va_end(args);
     277                 :     /* NOTREACHED */
     278 UIC           0 :     printf(_("Failure, exiting\n"));
     279               0 :     exit(1);
     280                 : }
     281                 : 
     282 ECB             : 
     283                 : void
     284 GIC          44 : check_ok(void)
     285                 : {
     286                 :     /* all seems well */
     287 CBC          44 :     report_status(PG_REPORT, "ok");
     288 GIC          44 : }
     289                 : 
     290 ECB             : 
     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 EUB             :  */
     298                 : char *
     299 GIC           2 : quote_identifier(const char *s)
     300                 : {
     301 GBC           2 :     char       *result = pg_malloc(strlen(s) * 2 + 3);
     302               2 :     char       *r = result;
     303 EUB             : 
     304 GIC           2 :     *r++ = '"';
     305 GBC          20 :     while (*s)
     306 EUB             :     {
     307 GIC          18 :         if (*s == '"')
     308 UIC           0 :             *r++ = *s;
     309 GIC          18 :         *r++ = *s;
     310              18 :         s++;
     311 ECB             :     }
     312 GIC           2 :     *r++ = '"';
     313               2 :     *r++ = '\0';
     314 ECB             : 
     315 CBC           2 :     return result;
     316                 : }
     317                 : 
     318                 : 
     319                 : /*
     320                 :  * get_user_info()
     321                 :  */
     322                 : int
     323 GIC           6 : get_user_info(char **user_name_p)
     324                 : {
     325                 :     int         user_id;
     326 ECB             :     const char *user_name;
     327                 :     char       *errstr;
     328                 : 
     329                 : #ifndef WIN32
     330 GIC           6 :     user_id = geteuid();
     331 ECB             : #else
     332                 :     user_id = 1;
     333                 : #endif
     334                 : 
     335 GBC           6 :     user_name = get_user_name(&errstr);
     336 CBC           6 :     if (!user_name)
     337 UNC           0 :         pg_fatal("%s", errstr);
     338                 : 
     339 ECB             :     /* make a copy */
     340 CBC           6 :     *user_name_p = pg_strdup(user_name);
     341                 : 
     342               6 :     return user_id;
     343                 : }
     344                 : 
     345                 : 
     346                 : /*
     347                 :  *  str2uint()
     348                 :  *
     349                 :  *  convert string to oid
     350 ECB             :  */
     351                 : unsigned int
     352 GIC          80 : str2uint(const char *str)
     353                 : {
     354              80 :     return strtoul(str, NULL, 10);
     355                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a