LCOV - code coverage report
Current view: top level - coredump - coredumpctl.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 25 567 4.4 %
Date: 2019-08-23 13:36:53 Functions: 4 19 21.1 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 9 689 1.3 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : 
       3                 :            : #include <fcntl.h>
       4                 :            : #include <getopt.h>
       5                 :            : #include <locale.h>
       6                 :            : #include <stdio.h>
       7                 :            : #include <string.h>
       8                 :            : #include <unistd.h>
       9                 :            : 
      10                 :            : #include "sd-bus.h"
      11                 :            : #include "sd-journal.h"
      12                 :            : #include "sd-messages.h"
      13                 :            : 
      14                 :            : #include "alloc-util.h"
      15                 :            : #include "bus-error.h"
      16                 :            : #include "bus-util.h"
      17                 :            : #include "compress.h"
      18                 :            : #include "def.h"
      19                 :            : #include "fd-util.h"
      20                 :            : #include "fs-util.h"
      21                 :            : #include "journal-internal.h"
      22                 :            : #include "journal-util.h"
      23                 :            : #include "log.h"
      24                 :            : #include "macro.h"
      25                 :            : #include "main-func.h"
      26                 :            : #include "pager.h"
      27                 :            : #include "parse-util.h"
      28                 :            : #include "path-util.h"
      29                 :            : #include "pretty-print.h"
      30                 :            : #include "process-util.h"
      31                 :            : #include "rlimit-util.h"
      32                 :            : #include "sigbus.h"
      33                 :            : #include "signal-util.h"
      34                 :            : #include "string-util.h"
      35                 :            : #include "strv.h"
      36                 :            : #include "terminal-util.h"
      37                 :            : #include "tmpfile-util.h"
      38                 :            : #include "user-util.h"
      39                 :            : #include "util.h"
      40                 :            : #include "verbs.h"
      41                 :            : 
      42                 :            : #define SHORT_BUS_CALL_TIMEOUT_USEC (3 * USEC_PER_SEC)
      43                 :            : 
      44                 :            : static usec_t arg_since = USEC_INFINITY, arg_until = USEC_INFINITY;
      45                 :            : static const char* arg_field = NULL;
      46                 :            : static const char *arg_debugger = NULL;
      47                 :            : static const char *arg_directory = NULL;
      48                 :            : static PagerFlags arg_pager_flags = 0;
      49                 :            : static int arg_no_legend = false;
      50                 :            : static int arg_one = false;
      51                 :            : static const char* arg_output = NULL;
      52                 :            : static bool arg_reverse = false;
      53                 :            : static bool arg_quiet = false;
      54                 :            : 
      55                 :          0 : static int add_match(sd_journal *j, const char *match) {
      56                 :          0 :         _cleanup_free_ char *p = NULL;
      57                 :            :         const char* prefix, *pattern;
      58                 :            :         pid_t pid;
      59                 :            :         int r;
      60                 :            : 
      61         [ #  # ]:          0 :         if (strchr(match, '='))
      62                 :          0 :                 prefix = "";
      63         [ #  # ]:          0 :         else if (strchr(match, '/')) {
      64                 :          0 :                 r = path_make_absolute_cwd(match, &p);
      65         [ #  # ]:          0 :                 if (r < 0)
      66         [ #  # ]:          0 :                         return log_error_errno(r, "path_make_absolute_cwd(\"%s\"): %m", match);
      67                 :            : 
      68                 :          0 :                 match = p;
      69                 :          0 :                 prefix = "COREDUMP_EXE=";
      70         [ #  # ]:          0 :         } else if (parse_pid(match, &pid) >= 0)
      71                 :          0 :                 prefix = "COREDUMP_PID=";
      72                 :            :         else
      73                 :          0 :                 prefix = "COREDUMP_COMM=";
      74                 :            : 
      75   [ #  #  #  #  :          0 :         pattern = strjoina(prefix, match);
          #  #  #  #  #  
                #  #  # ]
      76         [ #  # ]:          0 :         log_debug("Adding match: %s", pattern);
      77                 :          0 :         r = sd_journal_add_match(j, pattern, 0);
      78         [ #  # ]:          0 :         if (r < 0)
      79         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to add match \"%s\": %m", match);
      80                 :            : 
      81                 :          0 :         return 0;
      82                 :            : }
      83                 :            : 
      84                 :          0 : static int add_matches(sd_journal *j, char **matches) {
      85                 :            :         char **match;
      86                 :            :         int r;
      87                 :            : 
      88                 :          0 :         r = sd_journal_add_match(j, "MESSAGE_ID=" SD_MESSAGE_COREDUMP_STR, 0);
      89         [ #  # ]:          0 :         if (r < 0)
      90         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to add match \"%s\": %m", "MESSAGE_ID=" SD_MESSAGE_COREDUMP_STR);
      91                 :            : 
      92                 :          0 :         r = sd_journal_add_match(j, "MESSAGE_ID=" SD_MESSAGE_BACKTRACE_STR, 0);
      93         [ #  # ]:          0 :         if (r < 0)
      94         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to add match \"%s\": %m", "MESSAGE_ID=" SD_MESSAGE_BACKTRACE_STR);
      95                 :            : 
      96   [ #  #  #  # ]:          0 :         STRV_FOREACH(match, matches) {
      97                 :          0 :                 r = add_match(j, *match);
      98         [ #  # ]:          0 :                 if (r < 0)
      99                 :          0 :                         return r;
     100                 :            :         }
     101                 :            : 
     102                 :          0 :         return 0;
     103                 :            : }
     104                 :            : 
     105                 :          0 : static int acquire_journal(sd_journal **ret, char **matches) {
     106                 :          0 :         _cleanup_(sd_journal_closep) sd_journal *j = NULL;
     107                 :            :         int r;
     108                 :            : 
     109         [ #  # ]:          0 :         assert(ret);
     110                 :            : 
     111         [ #  # ]:          0 :         if (arg_directory) {
     112                 :          0 :                 r = sd_journal_open_directory(&j, arg_directory, 0);
     113         [ #  # ]:          0 :                 if (r < 0)
     114         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to open journals in directory: %s: %m", arg_directory);
     115                 :            :         } else {
     116                 :          0 :                 r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY);
     117         [ #  # ]:          0 :                 if (r < 0)
     118         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to open journal: %m");
     119                 :            :         }
     120                 :            : 
     121                 :          0 :         r = journal_access_check_and_warn(j, arg_quiet, true);
     122         [ #  # ]:          0 :         if (r < 0)
     123                 :          0 :                 return r;
     124                 :            : 
     125                 :          0 :         r = add_matches(j, matches);
     126         [ #  # ]:          0 :         if (r < 0)
     127                 :          0 :                 return r;
     128                 :            : 
     129         [ #  # ]:          0 :         if (DEBUG_LOGGING) {
     130                 :          0 :                 _cleanup_free_ char *filter;
     131                 :            : 
     132                 :          0 :                 filter = journal_make_match_string(j);
     133         [ #  # ]:          0 :                 log_debug("Journal filter: %s", filter);
     134                 :            :         }
     135                 :            : 
     136                 :          0 :         *ret = TAKE_PTR(j);
     137                 :            : 
     138                 :          0 :         return 0;
     139                 :            : }
     140                 :            : 
     141                 :         12 : static int help(void) {
     142                 :         12 :         _cleanup_free_ char *link = NULL;
     143                 :            :         int r;
     144                 :            : 
     145                 :         12 :         r = terminal_urlify_man("coredumpctl", "1", &link);
     146         [ -  + ]:         12 :         if (r < 0)
     147                 :          0 :                 return log_oom();
     148                 :            : 
     149                 :         12 :         printf("%s [OPTIONS...]\n\n"
     150                 :            :                "List or retrieve coredumps from the journal.\n\n"
     151                 :            :                "Flags:\n"
     152                 :            :                "  -h --help              Show this help\n"
     153                 :            :                "     --version           Print version string\n"
     154                 :            :                "     --no-pager          Do not pipe output into a pager\n"
     155                 :            :                "     --no-legend         Do not print the column headers\n"
     156                 :            :                "     --debugger=DEBUGGER Use the given debugger\n"
     157                 :            :                "  -1                     Show information about most recent entry only\n"
     158                 :            :                "  -S --since=DATE        Only print coredumps since the date\n"
     159                 :            :                "  -U --until=DATE        Only print coredumps until the date\n"
     160                 :            :                "  -r --reverse           Show the newest entries first\n"
     161                 :            :                "  -F --field=FIELD       List all values a certain field takes\n"
     162                 :            :                "  -o --output=FILE       Write output to FILE\n"
     163                 :            :                "  -D --directory=DIR     Use journal files from directory\n\n"
     164                 :            :                "  -q --quiet             Do not show info messages and privilege warning\n"
     165                 :            :                "Commands:\n"
     166                 :            :                "  list [MATCHES...]  List available coredumps (default)\n"
     167                 :            :                "  info [MATCHES...]  Show detailed information about one or more coredumps\n"
     168                 :            :                "  dump [MATCHES...]  Print first matching coredump to stdout\n"
     169                 :            :                "  debug [MATCHES...] Start a debugger for the first matching coredump\n"
     170                 :            :                "\nSee the %s for details.\n"
     171                 :            :                , program_invocation_short_name
     172                 :            :                , link
     173                 :            :         );
     174                 :            : 
     175                 :         12 :         return 0;
     176                 :            : }
     177                 :            : 
     178                 :         16 : static int parse_argv(int argc, char *argv[]) {
     179                 :            :         enum {
     180                 :            :                 ARG_VERSION = 0x100,
     181                 :            :                 ARG_NO_PAGER,
     182                 :            :                 ARG_NO_LEGEND,
     183                 :            :                 ARG_DEBUGGER,
     184                 :            :         };
     185                 :            : 
     186                 :            :         int c, r;
     187                 :            : 
     188                 :            :         static const struct option options[] = {
     189                 :            :                 { "help",         no_argument,       NULL, 'h'           },
     190                 :            :                 { "version" ,     no_argument,       NULL, ARG_VERSION   },
     191                 :            :                 { "no-pager",     no_argument,       NULL, ARG_NO_PAGER  },
     192                 :            :                 { "no-legend",    no_argument,       NULL, ARG_NO_LEGEND },
     193                 :            :                 { "debugger",     required_argument, NULL, ARG_DEBUGGER  },
     194                 :            :                 { "output",       required_argument, NULL, 'o'           },
     195                 :            :                 { "field",        required_argument, NULL, 'F'           },
     196                 :            :                 { "directory",    required_argument, NULL, 'D'           },
     197                 :            :                 { "reverse",      no_argument,       NULL, 'r'           },
     198                 :            :                 { "since",        required_argument, NULL, 'S'           },
     199                 :            :                 { "until",        required_argument, NULL, 'U'           },
     200                 :            :                 { "quiet",        no_argument,       NULL, 'q'           },
     201                 :            :                 {}
     202                 :            :         };
     203                 :            : 
     204         [ -  + ]:         16 :         assert(argc >= 0);
     205         [ -  + ]:         16 :         assert(argv);
     206                 :            : 
     207         [ +  - ]:         16 :         while ((c = getopt_long(argc, argv, "ho:F:1D:rS:U:q", options, NULL)) >= 0)
     208   [ +  -  -  -  :         16 :                 switch(c) {
          -  -  -  -  -  
          -  -  -  -  +  
                      - ]
     209                 :         12 :                 case 'h':
     210                 :         12 :                         return help();
     211                 :            : 
     212                 :          0 :                 case ARG_VERSION:
     213                 :          0 :                         return version();
     214                 :            : 
     215                 :          0 :                 case ARG_NO_PAGER:
     216                 :          0 :                         arg_pager_flags |= PAGER_DISABLE;
     217                 :          0 :                         break;
     218                 :            : 
     219                 :          0 :                 case ARG_NO_LEGEND:
     220                 :          0 :                         arg_no_legend = true;
     221                 :          0 :                         break;
     222                 :            : 
     223                 :          0 :                 case ARG_DEBUGGER:
     224                 :          0 :                         arg_debugger = optarg;
     225                 :          0 :                         break;
     226                 :            : 
     227                 :          0 :                 case 'o':
     228         [ #  # ]:          0 :                         if (arg_output)
     229         [ #  # ]:          0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     230                 :            :                                                        "Cannot set output more than once.");
     231                 :            : 
     232                 :          0 :                         arg_output = optarg;
     233                 :          0 :                         break;
     234                 :            : 
     235                 :          0 :                 case 'S':
     236                 :          0 :                         r = parse_timestamp(optarg, &arg_since);
     237         [ #  # ]:          0 :                         if (r < 0)
     238         [ #  # ]:          0 :                                 return log_error_errno(r, "Failed to parse timestamp '%s': %m", optarg);
     239                 :          0 :                         break;
     240                 :            : 
     241                 :          0 :                 case 'U':
     242                 :          0 :                         r = parse_timestamp(optarg, &arg_until);
     243         [ #  # ]:          0 :                         if (r < 0)
     244         [ #  # ]:          0 :                                 return log_error_errno(r, "Failed to parse timestamp '%s': %m", optarg);
     245                 :          0 :                         break;
     246                 :            : 
     247                 :          0 :                 case 'F':
     248         [ #  # ]:          0 :                         if (arg_field)
     249         [ #  # ]:          0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     250                 :            :                                                        "Cannot use --field/-F more than once.");
     251                 :          0 :                         arg_field = optarg;
     252                 :          0 :                         break;
     253                 :            : 
     254                 :          0 :                 case '1':
     255                 :          0 :                         arg_one = true;
     256                 :          0 :                         break;
     257                 :            : 
     258                 :          0 :                 case 'D':
     259                 :          0 :                         arg_directory = optarg;
     260                 :          0 :                         break;
     261                 :            : 
     262                 :          0 :                 case 'r':
     263                 :          0 :                         arg_reverse = true;
     264                 :          0 :                         break;
     265                 :            : 
     266                 :          0 :                 case 'q':
     267                 :          0 :                         arg_quiet = true;
     268                 :          0 :                         break;
     269                 :            : 
     270                 :          4 :                 case '?':
     271                 :          4 :                         return -EINVAL;
     272                 :            : 
     273                 :          0 :                 default:
     274                 :          0 :                         assert_not_reached("Unhandled option");
     275                 :            :                 }
     276                 :            : 
     277   [ #  #  #  # ]:          0 :         if (arg_since != USEC_INFINITY && arg_until != USEC_INFINITY &&
     278         [ #  # ]:          0 :             arg_since > arg_until)
     279         [ #  # ]:          0 :                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     280                 :            :                                        "--since= must be before --until=.");
     281                 :            : 
     282                 :          0 :         return 1;
     283                 :            : }
     284                 :            : 
     285                 :          0 : static int retrieve(const void *data,
     286                 :            :                     size_t len,
     287                 :            :                     const char *name,
     288                 :            :                     char **var) {
     289                 :            : 
     290                 :            :         size_t ident;
     291                 :            :         char *v;
     292                 :            : 
     293                 :          0 :         ident = strlen(name) + 1; /* name + "=" */
     294                 :            : 
     295         [ #  # ]:          0 :         if (len < ident)
     296                 :          0 :                 return 0;
     297                 :            : 
     298         [ #  # ]:          0 :         if (memcmp(data, name, ident - 1) != 0)
     299                 :          0 :                 return 0;
     300                 :            : 
     301         [ #  # ]:          0 :         if (((const char*) data)[ident - 1] != '=')
     302                 :          0 :                 return 0;
     303                 :            : 
     304                 :          0 :         v = strndup((const char*)data + ident, len - ident);
     305         [ #  # ]:          0 :         if (!v)
     306                 :          0 :                 return log_oom();
     307                 :            : 
     308                 :          0 :         free_and_replace(*var, v);
     309                 :          0 :         return 1;
     310                 :            : }
     311                 :            : 
     312                 :          0 : static int print_field(FILE* file, sd_journal *j) {
     313                 :            :         const void *d;
     314                 :            :         size_t l;
     315                 :            : 
     316         [ #  # ]:          0 :         assert(file);
     317         [ #  # ]:          0 :         assert(j);
     318                 :            : 
     319         [ #  # ]:          0 :         assert(arg_field);
     320                 :            : 
     321                 :            :         /* A (user-specified) field may appear more than once for a given entry.
     322                 :            :          * We will print all of the occurrences.
     323                 :            :          * This is different below for fields that systemd-coredump uses,
     324                 :            :          * because they cannot meaningfully appear more than once.
     325                 :            :          */
     326         [ #  # ]:          0 :         SD_JOURNAL_FOREACH_DATA(j, d, l) {
     327         [ #  # ]:          0 :                 _cleanup_free_ char *value = NULL;
     328                 :            :                 int r;
     329                 :            : 
     330                 :          0 :                 r = retrieve(d, l, arg_field, &value);
     331         [ #  # ]:          0 :                 if (r < 0)
     332                 :          0 :                         return r;
     333         [ #  # ]:          0 :                 if (r > 0)
     334                 :          0 :                         fprintf(file, "%s\n", value);
     335                 :            :         }
     336                 :            : 
     337                 :          0 :         return 0;
     338                 :            : }
     339                 :            : 
     340                 :            : #define RETRIEVE(d, l, name, arg)                    \
     341                 :            :         {                                            \
     342                 :            :                 int _r = retrieve(d, l, name, &arg); \
     343                 :            :                 if (_r < 0)                          \
     344                 :            :                         return _r;                   \
     345                 :            :                 if (_r > 0)                          \
     346                 :            :                         continue;                    \
     347                 :            :         }
     348                 :            : 
     349                 :          0 : static int print_list(FILE* file, sd_journal *j, int had_legend) {
     350                 :            :         _cleanup_free_ char
     351                 :          0 :                 *mid = NULL, *pid = NULL, *uid = NULL, *gid = NULL,
     352                 :          0 :                 *sgnl = NULL, *exe = NULL, *comm = NULL, *cmdline = NULL,
     353                 :          0 :                 *filename = NULL, *truncated = NULL, *coredump = NULL;
     354                 :            :         const void *d;
     355                 :            :         size_t l;
     356                 :            :         usec_t t;
     357                 :            :         char buf[FORMAT_TIMESTAMP_MAX];
     358                 :            :         int r;
     359                 :            :         const char *present;
     360                 :            :         bool normal_coredump;
     361                 :            : 
     362         [ #  # ]:          0 :         assert(file);
     363         [ #  # ]:          0 :         assert(j);
     364                 :            : 
     365         [ #  # ]:          0 :         SD_JOURNAL_FOREACH_DATA(j, d, l) {
     366   [ #  #  #  # ]:          0 :                 RETRIEVE(d, l, "MESSAGE_ID", mid);
     367   [ #  #  #  # ]:          0 :                 RETRIEVE(d, l, "COREDUMP_PID", pid);
     368   [ #  #  #  # ]:          0 :                 RETRIEVE(d, l, "COREDUMP_UID", uid);
     369   [ #  #  #  # ]:          0 :                 RETRIEVE(d, l, "COREDUMP_GID", gid);
     370   [ #  #  #  # ]:          0 :                 RETRIEVE(d, l, "COREDUMP_SIGNAL", sgnl);
     371   [ #  #  #  # ]:          0 :                 RETRIEVE(d, l, "COREDUMP_EXE", exe);
     372   [ #  #  #  # ]:          0 :                 RETRIEVE(d, l, "COREDUMP_COMM", comm);
     373   [ #  #  #  # ]:          0 :                 RETRIEVE(d, l, "COREDUMP_CMDLINE", cmdline);
     374   [ #  #  #  # ]:          0 :                 RETRIEVE(d, l, "COREDUMP_FILENAME", filename);
     375   [ #  #  #  # ]:          0 :                 RETRIEVE(d, l, "COREDUMP_TRUNCATED", truncated);
     376   [ #  #  #  # ]:          0 :                 RETRIEVE(d, l, "COREDUMP", coredump);
     377                 :            :         }
     378                 :            : 
     379   [ #  #  #  #  :          0 :         if (!pid && !uid && !gid && !sgnl && !exe && !comm && !cmdline && !filename) {
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     380         [ #  # ]:          0 :                 log_warning("Empty coredump log entry");
     381                 :          0 :                 return -EINVAL;
     382                 :            :         }
     383                 :            : 
     384                 :          0 :         r = sd_journal_get_realtime_usec(j, &t);
     385         [ #  # ]:          0 :         if (r < 0)
     386         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to get realtime timestamp: %m");
     387                 :            : 
     388                 :          0 :         format_timestamp(buf, sizeof(buf), t);
     389                 :            : 
     390   [ #  #  #  # ]:          0 :         if (!had_legend && !arg_no_legend)
     391                 :          0 :                 fprintf(file, "%-*s %*s %*s %*s %*s %-*s %s\n",
     392                 :            :                         FORMAT_TIMESTAMP_WIDTH, "TIME",
     393                 :            :                         6, "PID",
     394                 :            :                         5, "UID",
     395                 :            :                         5, "GID",
     396                 :            :                         3, "SIG",
     397                 :            :                         9, "COREFILE",
     398                 :            :                            "EXE");
     399                 :            : 
     400                 :          0 :         normal_coredump = streq_ptr(mid, SD_MESSAGE_COREDUMP_STR);
     401                 :            : 
     402         [ #  # ]:          0 :         if (filename)
     403         [ #  # ]:          0 :                 if (access(filename, R_OK) == 0)
     404                 :          0 :                         present = "present";
     405         [ #  # ]:          0 :                 else if (errno == ENOENT)
     406                 :          0 :                         present = "missing";
     407                 :            :                 else
     408                 :          0 :                         present = "error";
     409         [ #  # ]:          0 :         else if (coredump)
     410                 :          0 :                 present = "journal";
     411         [ #  # ]:          0 :         else if (normal_coredump)
     412                 :          0 :                 present = "none";
     413                 :            :         else
     414                 :          0 :                 present = "-";
     415                 :            : 
     416   [ #  #  #  #  :          0 :         if (STR_IN_SET(present, "present", "journal") && truncated && parse_boolean(truncated) > 0)
                   #  # ]
     417                 :          0 :                 present = "truncated";
     418                 :            : 
     419         [ #  # ]:          0 :         fprintf(file, "%-*s %*s %*s %*s %*s %-*s %s\n",
     420                 :            :                 FORMAT_TIMESTAMP_WIDTH, buf,
     421                 :            :                 6, strna(pid),
     422                 :            :                 5, strna(uid),
     423                 :            :                 5, strna(gid),
     424                 :          0 :                 3, normal_coredump ? strna(sgnl) : "-",
     425                 :            :                 9, present,
     426   [ #  #  #  # ]:          0 :                 strna(exe ?: (comm ?: cmdline)));
     427                 :            : 
     428                 :          0 :         return 0;
     429                 :            : }
     430                 :            : 
     431                 :          0 : static int print_info(FILE *file, sd_journal *j, bool need_space) {
     432                 :            :         _cleanup_free_ char
     433                 :          0 :                 *mid = NULL, *pid = NULL, *uid = NULL, *gid = NULL,
     434                 :          0 :                 *sgnl = NULL, *exe = NULL, *comm = NULL, *cmdline = NULL,
     435                 :          0 :                 *unit = NULL, *user_unit = NULL, *session = NULL,
     436                 :          0 :                 *boot_id = NULL, *machine_id = NULL, *hostname = NULL,
     437                 :          0 :                 *slice = NULL, *cgroup = NULL, *owner_uid = NULL,
     438                 :          0 :                 *message = NULL, *timestamp = NULL, *filename = NULL,
     439                 :          0 :                 *truncated = NULL, *coredump = NULL;
     440                 :            :         const void *d;
     441                 :            :         size_t l;
     442                 :            :         bool normal_coredump;
     443                 :            :         int r;
     444                 :            : 
     445         [ #  # ]:          0 :         assert(file);
     446         [ #  # ]:          0 :         assert(j);
     447                 :            : 
     448         [ #  # ]:          0 :         SD_JOURNAL_FOREACH_DATA(j, d, l) {
     449   [ #  #  #  # ]:          0 :                 RETRIEVE(d, l, "MESSAGE_ID", mid);
     450   [ #  #  #  # ]:          0 :                 RETRIEVE(d, l, "COREDUMP_PID", pid);
     451   [ #  #  #  # ]:          0 :                 RETRIEVE(d, l, "COREDUMP_UID", uid);
     452   [ #  #  #  # ]:          0 :                 RETRIEVE(d, l, "COREDUMP_GID", gid);
     453   [ #  #  #  # ]:          0 :                 RETRIEVE(d, l, "COREDUMP_SIGNAL", sgnl);
     454   [ #  #  #  # ]:          0 :                 RETRIEVE(d, l, "COREDUMP_EXE", exe);
     455   [ #  #  #  # ]:          0 :                 RETRIEVE(d, l, "COREDUMP_COMM", comm);
     456   [ #  #  #  # ]:          0 :                 RETRIEVE(d, l, "COREDUMP_CMDLINE", cmdline);
     457   [ #  #  #  # ]:          0 :                 RETRIEVE(d, l, "COREDUMP_UNIT", unit);
     458   [ #  #  #  # ]:          0 :                 RETRIEVE(d, l, "COREDUMP_USER_UNIT", user_unit);
     459   [ #  #  #  # ]:          0 :                 RETRIEVE(d, l, "COREDUMP_SESSION", session);
     460   [ #  #  #  # ]:          0 :                 RETRIEVE(d, l, "COREDUMP_OWNER_UID", owner_uid);
     461   [ #  #  #  # ]:          0 :                 RETRIEVE(d, l, "COREDUMP_SLICE", slice);
     462   [ #  #  #  # ]:          0 :                 RETRIEVE(d, l, "COREDUMP_CGROUP", cgroup);
     463   [ #  #  #  # ]:          0 :                 RETRIEVE(d, l, "COREDUMP_TIMESTAMP", timestamp);
     464   [ #  #  #  # ]:          0 :                 RETRIEVE(d, l, "COREDUMP_FILENAME", filename);
     465   [ #  #  #  # ]:          0 :                 RETRIEVE(d, l, "COREDUMP_TRUNCATED", truncated);
     466   [ #  #  #  # ]:          0 :                 RETRIEVE(d, l, "COREDUMP", coredump);
     467   [ #  #  #  # ]:          0 :                 RETRIEVE(d, l, "_BOOT_ID", boot_id);
     468   [ #  #  #  # ]:          0 :                 RETRIEVE(d, l, "_MACHINE_ID", machine_id);
     469   [ #  #  #  # ]:          0 :                 RETRIEVE(d, l, "_HOSTNAME", hostname);
     470   [ #  #  #  # ]:          0 :                 RETRIEVE(d, l, "MESSAGE", message);
     471                 :            :         }
     472                 :            : 
     473         [ #  # ]:          0 :         if (need_space)
     474                 :          0 :                 fputs("\n", file);
     475                 :            : 
     476                 :          0 :         normal_coredump = streq_ptr(mid, SD_MESSAGE_COREDUMP_STR);
     477                 :            : 
     478         [ #  # ]:          0 :         if (comm)
     479                 :          0 :                 fprintf(file,
     480                 :            :                         "           PID: %s%s%s (%s)\n",
     481                 :            :                         ansi_highlight(), strna(pid), ansi_normal(), comm);
     482                 :            :         else
     483                 :          0 :                 fprintf(file,
     484                 :            :                         "           PID: %s%s%s\n",
     485                 :            :                         ansi_highlight(), strna(pid), ansi_normal());
     486                 :            : 
     487         [ #  # ]:          0 :         if (uid) {
     488                 :            :                 uid_t n;
     489                 :            : 
     490         [ #  # ]:          0 :                 if (parse_uid(uid, &n) >= 0) {
     491                 :          0 :                         _cleanup_free_ char *u = NULL;
     492                 :            : 
     493                 :          0 :                         u = uid_to_name(n);
     494                 :          0 :                         fprintf(file,
     495                 :            :                                 "           UID: %s (%s)\n",
     496                 :            :                                 uid, u);
     497                 :            :                 } else {
     498                 :          0 :                         fprintf(file,
     499                 :            :                                 "           UID: %s\n",
     500                 :            :                                 uid);
     501                 :            :                 }
     502                 :            :         }
     503                 :            : 
     504         [ #  # ]:          0 :         if (gid) {
     505                 :            :                 gid_t n;
     506                 :            : 
     507         [ #  # ]:          0 :                 if (parse_gid(gid, &n) >= 0) {
     508                 :          0 :                         _cleanup_free_ char *g = NULL;
     509                 :            : 
     510                 :          0 :                         g = gid_to_name(n);
     511                 :          0 :                         fprintf(file,
     512                 :            :                                 "           GID: %s (%s)\n",
     513                 :            :                                 gid, g);
     514                 :            :                 } else {
     515                 :          0 :                         fprintf(file,
     516                 :            :                                 "           GID: %s\n",
     517                 :            :                                 gid);
     518                 :            :                 }
     519                 :            :         }
     520                 :            : 
     521         [ #  # ]:          0 :         if (sgnl) {
     522                 :            :                 int sig;
     523         [ #  # ]:          0 :                 const char *name = normal_coredump ? "Signal" : "Reason";
     524                 :            : 
     525   [ #  #  #  # ]:          0 :                 if (normal_coredump && safe_atoi(sgnl, &sig) >= 0)
     526                 :          0 :                         fprintf(file, "        %s: %s (%s)\n", name, sgnl, signal_to_string(sig));
     527                 :            :                 else
     528                 :          0 :                         fprintf(file, "        %s: %s\n", name, sgnl);
     529                 :            :         }
     530                 :            : 
     531         [ #  # ]:          0 :         if (timestamp) {
     532                 :            :                 usec_t u;
     533                 :            : 
     534                 :          0 :                 r = safe_atou64(timestamp, &u);
     535         [ #  # ]:          0 :                 if (r >= 0) {
     536                 :            :                         char absolute[FORMAT_TIMESTAMP_MAX], relative[FORMAT_TIMESPAN_MAX];
     537                 :            : 
     538                 :          0 :                         fprintf(file,
     539                 :            :                                 "     Timestamp: %s (%s)\n",
     540                 :            :                                 format_timestamp(absolute, sizeof(absolute), u),
     541                 :            :                                 format_timestamp_relative(relative, sizeof(relative), u));
     542                 :            : 
     543                 :            :                 } else
     544                 :          0 :                         fprintf(file, "     Timestamp: %s\n", timestamp);
     545                 :            :         }
     546                 :            : 
     547         [ #  # ]:          0 :         if (cmdline)
     548                 :          0 :                 fprintf(file, "  Command Line: %s\n", cmdline);
     549         [ #  # ]:          0 :         if (exe)
     550                 :          0 :                 fprintf(file, "    Executable: %s%s%s\n", ansi_highlight(), exe, ansi_normal());
     551         [ #  # ]:          0 :         if (cgroup)
     552                 :          0 :                 fprintf(file, " Control Group: %s\n", cgroup);
     553         [ #  # ]:          0 :         if (unit)
     554                 :          0 :                 fprintf(file, "          Unit: %s\n", unit);
     555         [ #  # ]:          0 :         if (user_unit)
     556                 :          0 :                 fprintf(file, "     User Unit: %s\n", user_unit);
     557         [ #  # ]:          0 :         if (slice)
     558                 :          0 :                 fprintf(file, "         Slice: %s\n", slice);
     559         [ #  # ]:          0 :         if (session)
     560                 :          0 :                 fprintf(file, "       Session: %s\n", session);
     561         [ #  # ]:          0 :         if (owner_uid) {
     562                 :            :                 uid_t n;
     563                 :            : 
     564         [ #  # ]:          0 :                 if (parse_uid(owner_uid, &n) >= 0) {
     565                 :          0 :                         _cleanup_free_ char *u = NULL;
     566                 :            : 
     567                 :          0 :                         u = uid_to_name(n);
     568                 :          0 :                         fprintf(file,
     569                 :            :                                 "     Owner UID: %s (%s)\n",
     570                 :            :                                 owner_uid, u);
     571                 :            :                 } else {
     572                 :          0 :                         fprintf(file,
     573                 :            :                                 "     Owner UID: %s\n",
     574                 :            :                                 owner_uid);
     575                 :            :                 }
     576                 :            :         }
     577         [ #  # ]:          0 :         if (boot_id)
     578                 :          0 :                 fprintf(file, "       Boot ID: %s\n", boot_id);
     579         [ #  # ]:          0 :         if (machine_id)
     580                 :          0 :                 fprintf(file, "    Machine ID: %s\n", machine_id);
     581         [ #  # ]:          0 :         if (hostname)
     582                 :          0 :                 fprintf(file, "      Hostname: %s\n", hostname);
     583                 :            : 
     584         [ #  # ]:          0 :         if (filename) {
     585                 :            :                 bool inacc, trunc;
     586                 :            : 
     587                 :          0 :                 inacc = access(filename, R_OK) < 0;
     588   [ #  #  #  # ]:          0 :                 trunc = truncated && parse_boolean(truncated) > 0;
     589                 :            : 
     590   [ #  #  #  # ]:          0 :                 if (inacc || trunc)
     591   [ #  #  #  #  :          0 :                         fprintf(file, "       Storage: %s%s (%s%s%s)%s\n",
                   #  # ]
     592                 :            :                                 ansi_highlight_red(),
     593                 :            :                                 filename,
     594                 :            :                                 inacc ? "inaccessible" : "",
     595         [ #  # ]:          0 :                                 inacc && trunc ? ", " : "",
     596                 :            :                                 trunc ? "truncated" : "",
     597                 :            :                                 ansi_normal());
     598                 :            :                 else
     599                 :          0 :                         fprintf(file, "       Storage: %s\n", filename);
     600                 :            :         }
     601                 :            : 
     602         [ #  # ]:          0 :         else if (coredump)
     603                 :          0 :                 fprintf(file, "       Storage: journal\n");
     604                 :            :         else
     605                 :          0 :                 fprintf(file, "       Storage: none\n");
     606                 :            : 
     607         [ #  # ]:          0 :         if (message) {
     608                 :          0 :                 _cleanup_free_ char *m = NULL;
     609                 :            : 
     610                 :          0 :                 m = strreplace(message, "\n", "\n                ");
     611                 :            : 
     612         [ #  # ]:          0 :                 fprintf(file, "       Message: %s\n", strstrip(m ?: message));
     613                 :            :         }
     614                 :            : 
     615                 :          0 :         return 0;
     616                 :            : }
     617                 :            : 
     618                 :          0 : static int focus(sd_journal *j) {
     619                 :            :         int r;
     620                 :            : 
     621                 :          0 :         r = sd_journal_seek_tail(j);
     622         [ #  # ]:          0 :         if (r == 0)
     623                 :          0 :                 r = sd_journal_previous(j);
     624         [ #  # ]:          0 :         if (r < 0)
     625         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to search journal: %m");
     626         [ #  # ]:          0 :         if (r == 0)
     627         [ #  # ]:          0 :                 return log_error_errno(SYNTHETIC_ERRNO(ESRCH),
     628                 :            :                                        "No match found.");
     629                 :          0 :         return r;
     630                 :            : }
     631                 :            : 
     632                 :          0 : static int print_entry(sd_journal *j, unsigned n_found, bool verb_is_info) {
     633         [ #  # ]:          0 :         assert(j);
     634                 :            : 
     635         [ #  # ]:          0 :         if (verb_is_info)
     636                 :          0 :                 return print_info(stdout, j, n_found);
     637         [ #  # ]:          0 :         else if (arg_field)
     638                 :          0 :                 return print_field(stdout, j);
     639                 :            :         else
     640                 :          0 :                 return print_list(stdout, j, n_found);
     641                 :            : }
     642                 :            : 
     643                 :          0 : static int dump_list(int argc, char **argv, void *userdata) {
     644                 :          0 :         _cleanup_(sd_journal_closep) sd_journal *j = NULL;
     645                 :          0 :         unsigned n_found = 0;
     646                 :            :         bool verb_is_info;
     647                 :            :         int r;
     648                 :            : 
     649   [ #  #  #  # ]:          0 :         verb_is_info = (argc >= 1 && streq(argv[0], "info"));
     650                 :            : 
     651                 :          0 :         r = acquire_journal(&j, argv + 1);
     652         [ #  # ]:          0 :         if (r < 0)
     653                 :          0 :                 return r;
     654                 :            : 
     655                 :          0 :         (void) pager_open(arg_pager_flags);
     656                 :            : 
     657                 :            :         /* The coredumps are likely to compressed, and for just
     658                 :            :          * listing them we don't need to decompress them, so let's
     659                 :            :          * pick a fairly low data threshold here */
     660                 :          0 :         sd_journal_set_data_threshold(j, 4096);
     661                 :            : 
     662                 :            :         /* "info" without pattern implies "-1" */
     663   [ #  #  #  #  :          0 :         if (arg_one || (verb_is_info && argc == 1)) {
                   #  # ]
     664                 :          0 :                 r = focus(j);
     665         [ #  # ]:          0 :                 if (r < 0)
     666                 :          0 :                         return r;
     667                 :            : 
     668                 :          0 :                 return print_entry(j, 0, verb_is_info);
     669                 :            :         } else {
     670   [ #  #  #  # ]:          0 :                 if (arg_since != USEC_INFINITY && !arg_reverse)
     671                 :          0 :                         r = sd_journal_seek_realtime_usec(j, arg_since);
     672   [ #  #  #  # ]:          0 :                 else if (arg_until != USEC_INFINITY && arg_reverse)
     673                 :          0 :                         r = sd_journal_seek_realtime_usec(j, arg_until);
     674         [ #  # ]:          0 :                 else if (arg_reverse)
     675                 :          0 :                         r = sd_journal_seek_tail(j);
     676                 :            :                 else
     677                 :          0 :                         r = sd_journal_seek_head(j);
     678         [ #  # ]:          0 :                 if (r < 0)
     679         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to seek to date: %m");
     680                 :            : 
     681                 :            :                 for (;;) {
     682         [ #  # ]:          0 :                         if (!arg_reverse)
     683                 :          0 :                                 r = sd_journal_next(j);
     684                 :            :                         else
     685                 :          0 :                                 r = sd_journal_previous(j);
     686                 :            : 
     687         [ #  # ]:          0 :                         if (r < 0)
     688         [ #  # ]:          0 :                                 return log_error_errno(r, "Failed to iterate through journal: %m");
     689                 :            : 
     690         [ #  # ]:          0 :                         if (r == 0)
     691                 :          0 :                                 break;
     692                 :            : 
     693   [ #  #  #  # ]:          0 :                         if (arg_until != USEC_INFINITY && !arg_reverse) {
     694                 :            :                                 usec_t usec;
     695                 :            : 
     696                 :          0 :                                 r = sd_journal_get_realtime_usec(j, &usec);
     697         [ #  # ]:          0 :                                 if (r < 0)
     698         [ #  # ]:          0 :                                         return log_error_errno(r, "Failed to determine timestamp: %m");
     699         [ #  # ]:          0 :                                 if (usec > arg_until)
     700                 :          0 :                                         continue;
     701                 :            :                         }
     702                 :            : 
     703   [ #  #  #  # ]:          0 :                         if (arg_since != USEC_INFINITY && arg_reverse) {
     704                 :            :                                 usec_t usec;
     705                 :            : 
     706                 :          0 :                                 r = sd_journal_get_realtime_usec(j, &usec);
     707         [ #  # ]:          0 :                                 if (r < 0)
     708         [ #  # ]:          0 :                                         return log_error_errno(r, "Failed to determine timestamp: %m");
     709         [ #  # ]:          0 :                                 if (usec < arg_since)
     710                 :          0 :                                         continue;
     711                 :            :                         }
     712                 :            : 
     713                 :          0 :                         r = print_entry(j, n_found++, verb_is_info);
     714         [ #  # ]:          0 :                         if (r < 0)
     715                 :          0 :                                 return r;
     716                 :            :                 }
     717                 :            : 
     718   [ #  #  #  # ]:          0 :                 if (!arg_field && n_found <= 0) {
     719         [ #  # ]:          0 :                         if (!arg_quiet)
     720         [ #  # ]:          0 :                                 log_notice("No coredumps found.");
     721                 :          0 :                         return -ESRCH;
     722                 :            :                 }
     723                 :            :         }
     724                 :            : 
     725                 :          0 :         return 0;
     726                 :            : }
     727                 :            : 
     728                 :          0 : static int save_core(sd_journal *j, FILE *file, char **path, bool *unlink_temp) {
     729                 :            :         const char *data;
     730                 :          0 :         _cleanup_free_ char *filename = NULL;
     731                 :            :         size_t len;
     732                 :            :         int r, fd;
     733                 :          0 :         _cleanup_close_ int fdt = -1;
     734                 :          0 :         char *temp = NULL;
     735                 :            : 
     736   [ #  #  #  # ]:          0 :         assert(!(file && path));         /* At most one can be specified */
     737         [ #  # ]:          0 :         assert(!!path == !!unlink_temp); /* Those must be specified together */
     738                 :            : 
     739                 :            :         /* Look for a coredump on disk first. */
     740                 :          0 :         r = sd_journal_get_data(j, "COREDUMP_FILENAME", (const void**) &data, &len);
     741         [ #  # ]:          0 :         if (r == 0) {
     742                 :          0 :                 r = retrieve(data, len, "COREDUMP_FILENAME", &filename);
     743         [ #  # ]:          0 :                 if (r < 0)
     744                 :          0 :                         return r;
     745         [ #  # ]:          0 :                 assert(r > 0);
     746                 :            : 
     747         [ #  # ]:          0 :                 if (access(filename, R_OK) < 0)
     748         [ #  # ]:          0 :                         return log_error_errno(errno, "File \"%s\" is not readable: %m", filename);
     749                 :            : 
     750   [ #  #  #  #  :          0 :                 if (path && !endswith(filename, ".xz") && !endswith(filename, ".lz4")) {
                   #  # ]
     751                 :          0 :                         *path = TAKE_PTR(filename);
     752                 :            : 
     753                 :          0 :                         return 0;
     754                 :            :                 }
     755                 :            : 
     756                 :            :         } else {
     757         [ #  # ]:          0 :                 if (r != -ENOENT)
     758         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to retrieve COREDUMP_FILENAME field: %m");
     759                 :            :                 /* Check that we can have a COREDUMP field. We still haven't set a high
     760                 :            :                  * data threshold, so we'll get a few kilobytes at most.
     761                 :            :                  */
     762                 :            : 
     763                 :          0 :                 r = sd_journal_get_data(j, "COREDUMP", (const void**) &data, &len);
     764         [ #  # ]:          0 :                 if (r == -ENOENT)
     765         [ #  # ]:          0 :                         return log_error_errno(r, "Coredump entry has no core attached (neither internally in the journal nor externally on disk).");
     766         [ #  # ]:          0 :                 if (r < 0)
     767         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to retrieve COREDUMP field: %m");
     768                 :            :         }
     769                 :            : 
     770         [ #  # ]:          0 :         if (path) {
     771                 :            :                 const char *vt;
     772                 :            : 
     773                 :            :                 /* Create a temporary file to write the uncompressed core to. */
     774                 :            : 
     775                 :          0 :                 r = var_tmp_dir(&vt);
     776         [ #  # ]:          0 :                 if (r < 0)
     777         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to acquire temporary directory path: %m");
     778                 :            : 
     779                 :          0 :                 temp = path_join(vt, "coredump-XXXXXX");
     780         [ #  # ]:          0 :                 if (!temp)
     781                 :          0 :                         return log_oom();
     782                 :            : 
     783                 :          0 :                 fdt = mkostemp_safe(temp);
     784         [ #  # ]:          0 :                 if (fdt < 0)
     785         [ #  # ]:          0 :                         return log_error_errno(fdt, "Failed to create temporary file: %m");
     786         [ #  # ]:          0 :                 log_debug("Created temporary file %s", temp);
     787                 :            : 
     788                 :          0 :                 fd = fdt;
     789                 :            :         } else {
     790                 :            :                 /* If neither path or file are specified, we will write to stdout. Let's now check
     791                 :            :                  * if stdout is connected to a tty. We checked that the file exists, or that the
     792                 :            :                  * core might be stored in the journal. In this second case, if we found the entry,
     793                 :            :                  * in all likelihood we will be able to access the COREDUMP= field.  In either case,
     794                 :            :                  * we stop before doing any "real" work, i.e. before starting decompression or
     795                 :            :                  * reading from the file or creating temporary files.
     796                 :            :                  */
     797         [ #  # ]:          0 :                 if (!file) {
     798         [ #  # ]:          0 :                         if (on_tty())
     799         [ #  # ]:          0 :                                 return log_error_errno(SYNTHETIC_ERRNO(ENOTTY),
     800                 :            :                                                        "Refusing to dump core to tty"
     801                 :            :                                                        " (use shell redirection or specify --output).");
     802                 :          0 :                         file = stdout;
     803                 :            :                 }
     804                 :            : 
     805                 :          0 :                 fd = fileno(file);
     806                 :            :         }
     807                 :            : 
     808         [ #  # ]:          0 :         if (filename) {
     809                 :            : #if HAVE_XZ || HAVE_LZ4
     810         [ #  # ]:          0 :                 _cleanup_close_ int fdf;
     811                 :            : 
     812                 :          0 :                 fdf = open(filename, O_RDONLY | O_CLOEXEC);
     813         [ #  # ]:          0 :                 if (fdf < 0) {
     814         [ #  # ]:          0 :                         r = log_error_errno(errno, "Failed to open %s: %m", filename);
     815                 :          0 :                         goto error;
     816                 :            :                 }
     817                 :            : 
     818                 :          0 :                 r = decompress_stream(filename, fdf, fd, -1);
     819         [ #  # ]:          0 :                 if (r < 0) {
     820         [ #  # ]:          0 :                         log_error_errno(r, "Failed to decompress %s: %m", filename);
     821                 :          0 :                         goto error;
     822                 :            :                 }
     823                 :            : #else
     824                 :            :                 log_error("Cannot decompress file. Compiled without compression support.");
     825                 :            :                 r = -EOPNOTSUPP;
     826                 :            :                 goto error;
     827                 :            : #endif
     828                 :            :         } else {
     829                 :            :                 ssize_t sz;
     830                 :            : 
     831                 :            :                 /* We want full data, nothing truncated. */
     832                 :          0 :                 sd_journal_set_data_threshold(j, 0);
     833                 :            : 
     834                 :          0 :                 r = sd_journal_get_data(j, "COREDUMP", (const void**) &data, &len);
     835         [ #  # ]:          0 :                 if (r < 0)
     836         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to retrieve COREDUMP field: %m");
     837                 :            : 
     838         [ #  # ]:          0 :                 assert(len >= 9);
     839                 :          0 :                 data += 9;
     840                 :          0 :                 len -= 9;
     841                 :            : 
     842                 :          0 :                 sz = write(fd, data, len);
     843         [ #  # ]:          0 :                 if (sz < 0) {
     844         [ #  # ]:          0 :                         r = log_error_errno(errno, "Failed to write output: %m");
     845                 :          0 :                         goto error;
     846                 :            :                 }
     847         [ #  # ]:          0 :                 if (sz != (ssize_t) len) {
     848         [ #  # ]:          0 :                         log_error("Short write to output.");
     849                 :          0 :                         r = -EIO;
     850                 :          0 :                         goto error;
     851                 :            :                 }
     852                 :            :         }
     853                 :            : 
     854         [ #  # ]:          0 :         if (temp) {
     855                 :          0 :                 *path = temp;
     856                 :          0 :                 *unlink_temp = true;
     857                 :            :         }
     858                 :          0 :         return 0;
     859                 :            : 
     860                 :          0 : error:
     861         [ #  # ]:          0 :         if (temp) {
     862                 :          0 :                 (void) unlink(temp);
     863         [ #  # ]:          0 :                 log_debug("Removed temporary file %s", temp);
     864                 :            :         }
     865                 :          0 :         return r;
     866                 :            : }
     867                 :            : 
     868                 :          0 : static int dump_core(int argc, char **argv, void *userdata) {
     869                 :          0 :         _cleanup_(sd_journal_closep) sd_journal *j = NULL;
     870                 :          0 :         _cleanup_fclose_ FILE *f = NULL;
     871                 :            :         int r;
     872                 :            : 
     873         [ #  # ]:          0 :         if (arg_field) {
     874         [ #  # ]:          0 :                 log_error("Option --field/-F only makes sense with list");
     875                 :          0 :                 return -EINVAL;
     876                 :            :         }
     877                 :            : 
     878                 :          0 :         r = acquire_journal(&j, argv + 1);
     879         [ #  # ]:          0 :         if (r < 0)
     880                 :          0 :                 return r;
     881                 :            : 
     882                 :          0 :         r = focus(j);
     883         [ #  # ]:          0 :         if (r < 0)
     884                 :          0 :                 return r;
     885                 :            : 
     886         [ #  # ]:          0 :         if (arg_output) {
     887                 :          0 :                 f = fopen(arg_output, "we");
     888         [ #  # ]:          0 :                 if (!f)
     889         [ #  # ]:          0 :                         return log_error_errno(errno, "Failed to open \"%s\" for writing: %m", arg_output);
     890                 :            :         }
     891                 :            : 
     892         [ #  # ]:          0 :         print_info(f ? stdout : stderr, j, false);
     893                 :            : 
     894                 :          0 :         r = save_core(j, f, NULL, NULL);
     895         [ #  # ]:          0 :         if (r < 0)
     896                 :          0 :                 return r;
     897                 :            : 
     898                 :          0 :         r = sd_journal_previous(j);
     899   [ #  #  #  # ]:          0 :         if (r > 0 && !arg_quiet)
     900         [ #  # ]:          0 :                 log_notice("More than one entry matches, ignoring rest.");
     901                 :            : 
     902                 :          0 :         return 0;
     903                 :            : }
     904                 :            : 
     905                 :          0 : static int run_debug(int argc, char **argv, void *userdata) {
     906                 :          0 :         _cleanup_(sd_journal_closep) sd_journal *j = NULL;
     907                 :          0 :         _cleanup_free_ char *exe = NULL, *path = NULL, *debugger = NULL;
     908                 :          0 :         bool unlink_path = false;
     909                 :            :         const char *data, *fork_name;
     910                 :            :         size_t len;
     911                 :            :         pid_t pid;
     912                 :            :         int r;
     913                 :            : 
     914         [ #  # ]:          0 :         if (!arg_debugger) {
     915                 :            :                 char *env_debugger;
     916                 :            : 
     917                 :          0 :                 env_debugger = getenv("SYSTEMD_DEBUGGER");
     918         [ #  # ]:          0 :                 if (env_debugger)
     919                 :          0 :                         arg_debugger = env_debugger;
     920                 :            :                 else
     921                 :          0 :                         arg_debugger = "gdb";
     922                 :            :         }
     923                 :            : 
     924                 :          0 :         debugger = strdup(arg_debugger);
     925         [ #  # ]:          0 :         if (!debugger)
     926                 :          0 :                 return -ENOMEM;
     927                 :            : 
     928         [ #  # ]:          0 :         if (arg_field) {
     929         [ #  # ]:          0 :                 log_error("Option --field/-F only makes sense with list");
     930                 :          0 :                 return -EINVAL;
     931                 :            :         }
     932                 :            : 
     933                 :          0 :         r = acquire_journal(&j, argv + 1);
     934         [ #  # ]:          0 :         if (r < 0)
     935                 :          0 :                 return r;
     936                 :            : 
     937                 :          0 :         r = focus(j);
     938         [ #  # ]:          0 :         if (r < 0)
     939                 :          0 :                 return r;
     940                 :            : 
     941                 :          0 :         print_info(stdout, j, false);
     942                 :          0 :         fputs("\n", stdout);
     943                 :            : 
     944                 :          0 :         r = sd_journal_get_data(j, "COREDUMP_EXE", (const void**) &data, &len);
     945         [ #  # ]:          0 :         if (r < 0)
     946         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to retrieve COREDUMP_EXE field: %m");
     947                 :            : 
     948         [ #  # ]:          0 :         assert(len > STRLEN("COREDUMP_EXE="));
     949                 :          0 :         data += STRLEN("COREDUMP_EXE=");
     950                 :          0 :         len -= STRLEN("COREDUMP_EXE=");
     951                 :            : 
     952                 :          0 :         exe = strndup(data, len);
     953         [ #  # ]:          0 :         if (!exe)
     954                 :          0 :                 return log_oom();
     955                 :            : 
     956         [ #  # ]:          0 :         if (endswith(exe, " (deleted)")) {
     957         [ #  # ]:          0 :                 log_error("Binary already deleted.");
     958                 :          0 :                 return -ENOENT;
     959                 :            :         }
     960                 :            : 
     961         [ #  # ]:          0 :         if (!path_is_absolute(exe)) {
     962         [ #  # ]:          0 :                 log_error("Binary is not an absolute path.");
     963                 :          0 :                 return -ENOENT;
     964                 :            :         }
     965                 :            : 
     966                 :          0 :         r = save_core(j, NULL, &path, &unlink_path);
     967         [ #  # ]:          0 :         if (r < 0)
     968                 :          0 :                 return r;
     969                 :            : 
     970                 :            :         /* Don't interfere with gdb and its handling of SIGINT. */
     971                 :          0 :         (void) ignore_signals(SIGINT, -1);
     972                 :            : 
     973   [ #  #  #  #  :          0 :         fork_name = strjoina("(", debugger, ")");
          #  #  #  #  #  
                #  #  # ]
     974                 :            : 
     975                 :          0 :         r = safe_fork(fork_name, FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pid);
     976         [ #  # ]:          0 :         if (r < 0)
     977                 :          0 :                 goto finish;
     978         [ #  # ]:          0 :         if (r == 0) {
     979                 :          0 :                 execlp(debugger, debugger, exe, "-c", path, NULL);
     980                 :          0 :                 log_open();
     981         [ #  # ]:          0 :                 log_error_errno(errno, "Failed to invoke %s: %m", debugger);
     982                 :          0 :                 _exit(EXIT_FAILURE);
     983                 :            :         }
     984                 :            : 
     985                 :          0 :         r = wait_for_terminate_and_check(debugger, pid, WAIT_LOG_ABNORMAL);
     986                 :            : 
     987                 :          0 : finish:
     988                 :          0 :         (void) default_signals(SIGINT, -1);
     989                 :            : 
     990         [ #  # ]:          0 :         if (unlink_path) {
     991         [ #  # ]:          0 :                 log_debug("Removed temporary file %s", path);
     992                 :          0 :                 (void) unlink(path);
     993                 :            :         }
     994                 :            : 
     995                 :          0 :         return r;
     996                 :            : }
     997                 :            : 
     998                 :          0 : static int check_units_active(void) {
     999                 :          0 :         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
    1000                 :          0 :         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
    1001                 :          0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
    1002                 :          0 :         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
    1003                 :          0 :         int c = 0, r;
    1004                 :            :         const char *id, *state, *substate;
    1005                 :            : 
    1006         [ #  # ]:          0 :         if (arg_quiet)
    1007                 :          0 :                 return false;
    1008                 :            : 
    1009                 :          0 :         r = sd_bus_default_system(&bus);
    1010         [ #  # ]:          0 :         if (r < 0)
    1011         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to acquire bus: %m");
    1012                 :            : 
    1013                 :          0 :         r = sd_bus_message_new_method_call(
    1014                 :            :                         bus,
    1015                 :            :                         &m,
    1016                 :            :                         "org.freedesktop.systemd1",
    1017                 :            :                         "/org/freedesktop/systemd1",
    1018                 :            :                         "org.freedesktop.systemd1.Manager",
    1019                 :            :                         "ListUnitsByPatterns");
    1020         [ #  # ]:          0 :         if (r < 0)
    1021         [ #  # ]:          0 :                 return bus_log_create_error(r);
    1022                 :            : 
    1023                 :          0 :         r = sd_bus_message_append_strv(m, NULL);
    1024         [ #  # ]:          0 :         if (r < 0)
    1025         [ #  # ]:          0 :                 return bus_log_create_error(r);
    1026                 :            : 
    1027                 :          0 :         r = sd_bus_message_append_strv(m, STRV_MAKE("systemd-coredump@*.service"));
    1028         [ #  # ]:          0 :         if (r < 0)
    1029         [ #  # ]:          0 :                 return bus_log_create_error(r);
    1030                 :            : 
    1031                 :          0 :         r = sd_bus_call(bus, m, SHORT_BUS_CALL_TIMEOUT_USEC, &error, &reply);
    1032         [ #  # ]:          0 :         if (r < 0)
    1033         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to check if any systemd-coredump@.service units are running: %s",
    1034                 :            :                                        bus_error_message(&error, r));
    1035                 :            : 
    1036                 :          0 :         r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssssouso)");
    1037         [ #  # ]:          0 :         if (r < 0)
    1038         [ #  # ]:          0 :                 return bus_log_parse_error(r);
    1039                 :            : 
    1040         [ #  # ]:          0 :         while ((r = sd_bus_message_read(
    1041                 :            :                                 reply, "(ssssssouso)",
    1042                 :            :                                 &id,  NULL,  NULL,  &state,  &substate,
    1043                 :            :                                 NULL,  NULL,  NULL,  NULL,  NULL)) > 0) {
    1044                 :          0 :                 bool found = !STR_IN_SET(state, "inactive", "dead", "failed");
    1045   [ #  #  #  # ]:          0 :                 log_debug("Unit %s is %s/%s, %scounting it.", id, state, substate, found ? "" : "not ");
    1046                 :          0 :                 c += found;
    1047                 :            :         }
    1048         [ #  # ]:          0 :         if (r < 0)
    1049         [ #  # ]:          0 :                 return bus_log_parse_error(r);
    1050                 :            : 
    1051                 :          0 :         r = sd_bus_message_exit_container(reply);
    1052         [ #  # ]:          0 :         if (r < 0)
    1053         [ #  # ]:          0 :                 return bus_log_parse_error(r);
    1054                 :            : 
    1055                 :          0 :         return c;
    1056                 :            : }
    1057                 :            : 
    1058                 :          0 : static int coredumpctl_main(int argc, char *argv[]) {
    1059                 :            : 
    1060                 :            :         static const Verb verbs[] = {
    1061                 :            :                 { "list",  VERB_ANY, VERB_ANY, VERB_DEFAULT, dump_list },
    1062                 :            :                 { "info",  VERB_ANY, VERB_ANY, 0,            dump_list },
    1063                 :            :                 { "dump",  VERB_ANY, VERB_ANY, 0,            dump_core },
    1064                 :            :                 { "debug", VERB_ANY, VERB_ANY, 0,            run_debug },
    1065                 :            :                 { "gdb",   VERB_ANY, VERB_ANY, 0,            run_debug },
    1066                 :            :                 {}
    1067                 :            :         };
    1068                 :            : 
    1069                 :          0 :         return dispatch_verb(argc, argv, verbs, NULL);
    1070                 :            : }
    1071                 :            : 
    1072                 :         16 : static int run(int argc, char *argv[]) {
    1073                 :            :         int r, units_active;
    1074                 :            : 
    1075                 :         16 :         setlocale(LC_ALL, "");
    1076                 :         16 :         log_show_color(true);
    1077                 :         16 :         log_parse_environment();
    1078                 :         16 :         log_open();
    1079                 :            : 
    1080                 :            :         /* The journal merging logic potentially needs a lot of fds. */
    1081                 :         16 :         (void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE);
    1082                 :            : 
    1083                 :         16 :         r = parse_argv(argc, argv);
    1084         [ +  - ]:         16 :         if (r <= 0)
    1085                 :         16 :                 return r;
    1086                 :            : 
    1087                 :          0 :         sigbus_install();
    1088                 :            : 
    1089                 :          0 :         units_active = check_units_active(); /* error is treated the same as 0 */
    1090                 :            : 
    1091                 :          0 :         r = coredumpctl_main(argc, argv);
    1092                 :            : 
    1093         [ #  # ]:          0 :         if (units_active > 0)
    1094         [ #  # ]:          0 :                 printf("%s-- Notice: %d systemd-coredump@.service %s, output may be incomplete.%s\n",
    1095                 :            :                        ansi_highlight_red(),
    1096                 :            :                        units_active, units_active == 1 ? "unit is running" : "units are running",
    1097                 :            :                        ansi_normal());
    1098                 :          0 :         return r;
    1099                 :            : }
    1100                 :            : 
    1101         [ +  + ]:         16 : DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE(run);

Generated by: LCOV version 1.14