chiark / gitweb /
systemctl: show hint about --full when lines don't fit
[elogind.git] / src / journal / cat.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2012 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <stdio.h>
23 #include <getopt.h>
24 #include <assert.h>
25 #include <unistd.h>
26 #include <stdlib.h>
27 #include <errno.h>
28 #include <fcntl.h>
29
30 #include <systemd/sd-journal.h>
31
32 #include "util.h"
33 #include "build.h"
34
35 static char *arg_identifier = NULL;
36 static int arg_priority = LOG_INFO;
37 static bool arg_level_prefix = true;
38
39 static int help(void) {
40
41         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
42                "Execute process with stdout/stderr connected to the journal.\n\n"
43                "  -h --help               Show this help\n"
44                "     --version            Show package version\n"
45                "  -t --identifier=STRING  Set syslog identifier\n"
46                "  -p --priority=PRIORITY  Set priority value (0..7)\n"
47                "     --level-prefix=BOOL  Control whether level prefix shall be parsed\n",
48                program_invocation_short_name);
49
50         return 0;
51 }
52
53 static int parse_argv(int argc, char *argv[]) {
54
55         enum {
56                 ARG_VERSION = 0x100,
57                 ARG_LEVEL_PREFIX
58         };
59
60         static const struct option options[] = {
61                 { "help",         no_argument,       NULL, 'h'              },
62                 { "version",      no_argument,       NULL, ARG_VERSION      },
63                 { "identifier",   required_argument, NULL, 't'              },
64                 { "priority",     required_argument, NULL, 'p'              },
65                 { "level-prefix", required_argument, NULL, ARG_LEVEL_PREFIX },
66                 { NULL,           0,                 NULL, 0                }
67         };
68
69         int c;
70
71         assert(argc >= 0);
72         assert(argv);
73
74         while ((c = getopt_long(argc, argv, "+ht:p:", options, NULL)) >= 0) {
75
76                 switch (c) {
77
78                 case 'h':
79                         help();
80                         return 0;
81
82                 case ARG_VERSION:
83                         puts(PACKAGE_STRING);
84                         puts(SYSTEMD_FEATURES);
85                         return 0;
86
87                 case 't':
88                         free(arg_identifier);
89                         if (isempty(optarg))
90                                 arg_identifier = NULL;
91                         else {
92                                 arg_identifier = strdup(optarg);
93                                 if (!arg_identifier)
94                                         return log_oom();
95                         }
96                         break;
97
98                 case 'p':
99                         arg_priority = log_level_from_string(optarg);
100                         if (arg_priority < 0) {
101                                 log_error("Failed to parse priority value.");
102                                 return arg_priority;
103                         }
104                         break;
105
106                 case ARG_LEVEL_PREFIX: {
107                         int k;
108
109                         k = parse_boolean(optarg);
110                         if (k < 0) {
111                                 log_error("Failed to parse level prefix value.");
112                                 return k;
113                         }
114                         arg_level_prefix = k;
115                         break;
116                 }
117
118                 default:
119                         log_error("Unknown option code %c", c);
120                         return -EINVAL;
121                 }
122         }
123
124         return 1;
125 }
126
127 int main(int argc, char *argv[]) {
128         int r, fd = -1, saved_stderr = -1;
129
130         log_parse_environment();
131         log_open();
132
133         r = parse_argv(argc, argv);
134         if (r <= 0)
135                 goto finish;
136
137         fd = sd_journal_stream_fd(arg_identifier, arg_priority, arg_level_prefix);
138         if (fd < 0) {
139                 log_error("Failed to create stream fd: %s", strerror(-fd));
140                 r = fd;
141                 goto finish;
142         }
143
144         saved_stderr = fcntl(STDERR_FILENO, F_DUPFD_CLOEXEC, 3);
145
146         if (dup3(fd, STDOUT_FILENO, 0) < 0 ||
147             dup3(fd, STDERR_FILENO, 0) < 0) {
148                 log_error("Failed to duplicate fd: %m");
149                 r = -errno;
150                 goto finish;
151         }
152
153         if (fd >= 3)
154                 close_nointr_nofail(fd);
155
156         fd = -1;
157
158         if (argc <= optind)
159                 execl("/bin/cat", "/bin/cat", NULL);
160         else
161                 execvp(argv[optind], argv + optind);
162
163         r = -errno;
164
165         /* Let's try to restore a working stderr, so we can print the error message */
166         if (saved_stderr >= 0)
167                 dup3(saved_stderr, STDERR_FILENO, 0);
168
169         log_error("Failed to execute process: %s", strerror(-r));
170
171 finish:
172         if (fd >= 0)
173                 close_nointr_nofail(fd);
174
175         if (saved_stderr >= 0)
176                 close_nointr_nofail(saved_stderr);
177
178         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
179 }