chiark / gitweb /
remove unused includes
[elogind.git] / src / bus-proxyd / stdio-bridge.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 Lennart Poettering
7   Copyright 2013 Daniel Mack
8   Copyright 2014 Kay Sievers
9
10   systemd is free software; you can redistribute it and/or modify it
11   under the terms of the GNU Lesser General Public License as published by
12   the Free Software Foundation; either version 2.1 of the License, or
13   (at your option) any later version.
14
15   systemd is distributed in the hope that it will be useful, but
16   WITHOUT ANY WARRANTY; without even the implied warranty of
17   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18   Lesser General Public License for more details.
19
20   You should have received a copy of the GNU Lesser General Public License
21   along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 ***/
23
24 #include <unistd.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <stddef.h>
28 #include <getopt.h>
29
30 #include "log.h"
31 #include "util.h"
32 #include "sd-daemon.h"
33 #include "sd-bus.h"
34 #include "bus-internal.h"
35 #include "bus-util.h"
36 #include "build.h"
37 #include "strv.h"
38 #include "def.h"
39 #include "proxy.h"
40
41 static char *arg_address = NULL;
42 static char *arg_command_line_buffer = NULL;
43
44 static int help(void) {
45
46         printf("%s [OPTIONS...]\n\n"
47                "Connect STDIO to a given bus address.\n\n"
48                "  -h --help               Show this help\n"
49                "     --version            Show package version\n"
50                "     --machine=MACHINE    Connect to specified machine\n"
51                "     --address=ADDRESS    Connect to the bus specified by ADDRESS\n"
52                "                          (default: " DEFAULT_SYSTEM_BUS_ADDRESS ")\n",
53                program_invocation_short_name);
54
55         return 0;
56 }
57
58 static int parse_argv(int argc, char *argv[]) {
59
60         enum {
61                 ARG_VERSION = 0x100,
62                 ARG_ADDRESS,
63                 ARG_MACHINE,
64         };
65
66         static const struct option options[] = {
67                 { "help",            no_argument,       NULL, 'h'                 },
68                 { "version",         no_argument,       NULL, ARG_VERSION         },
69                 { "address",         required_argument, NULL, ARG_ADDRESS         },
70                 { "machine",         required_argument, NULL, ARG_MACHINE         },
71                 {},
72         };
73
74         int c;
75
76         assert(argc >= 0);
77         assert(argv);
78
79         while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
80
81                 switch (c) {
82
83                 case 'h':
84                         help();
85                         return 0;
86
87                 case ARG_VERSION:
88                         puts(PACKAGE_STRING);
89                         puts(SYSTEMD_FEATURES);
90                         return 0;
91
92                 case ARG_ADDRESS: {
93                         char *a;
94
95                         a = strdup(optarg);
96                         if (!a)
97                                 return log_oom();
98
99                         free(arg_address);
100                         arg_address = a;
101                         break;
102                 }
103
104                 case ARG_MACHINE: {
105                         _cleanup_free_ char *e = NULL;
106                         char *a;
107
108                         e = bus_address_escape(optarg);
109                         if (!e)
110                                 return log_oom();
111
112 #ifdef ENABLE_KDBUS
113                         a = strjoin("x-machine-kernel:machine=", e, ";x-machine-unix:machine=", e, NULL);
114 #else
115                         a = strjoin("x-machine-unix:machine=", e, NULL);
116 #endif
117                         if (!a)
118                                 return log_oom();
119
120                         free(arg_address);
121                         arg_address = a;
122
123                         break;
124                 }
125
126                 case '?':
127                         return -EINVAL;
128
129                 default:
130                         assert_not_reached("Unhandled option");
131                 }
132
133         /* If the first command line argument is only "x" characters
134          * we'll write who we are talking to into it, so that "ps" is
135          * explanatory */
136         arg_command_line_buffer = argv[optind];
137         if (argc > optind + 1 || (arg_command_line_buffer && !in_charset(arg_command_line_buffer, "x"))) {
138                 log_error("Too many arguments");
139                 return -EINVAL;
140         }
141
142         if (!arg_address) {
143                 arg_address = strdup(DEFAULT_SYSTEM_BUS_ADDRESS);
144                 if (!arg_address)
145                         return log_oom();
146         }
147
148         return 1;
149 }
150
151 static int rename_service(sd_bus *a, sd_bus *b) {
152         _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
153         _cleanup_free_ char *p = NULL, *name = NULL;
154         const char *comm;
155         char **cmdline;
156         uid_t uid;
157         pid_t pid;
158         int r;
159
160         assert(a);
161         assert(b);
162
163         r = sd_bus_get_owner_creds(b, SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID|SD_BUS_CREDS_CMDLINE|SD_BUS_CREDS_COMM|SD_BUS_CREDS_AUGMENT, &creds);
164         if (r < 0)
165                 return r;
166
167         r = sd_bus_creds_get_euid(creds, &uid);
168         if (r < 0)
169                 return r;
170
171         r = sd_bus_creds_get_pid(creds, &pid);
172         if (r < 0)
173                 return r;
174
175         r = sd_bus_creds_get_cmdline(creds, &cmdline);
176         if (r < 0)
177                 return r;
178
179         r = sd_bus_creds_get_comm(creds, &comm);
180         if (r < 0)
181                 return r;
182
183         name = uid_to_name(uid);
184         if (!name)
185                 return -ENOMEM;
186
187         p = strv_join(cmdline, " ");
188         if (!p)
189                 return -ENOMEM;
190
191         /* The status string gets the full command line ... */
192         sd_notifyf(false,
193                    "STATUS=Processing requests from client PID "PID_FMT" (%s); UID "UID_FMT" (%s)",
194                    pid, p,
195                    uid, name);
196
197         /* ... and the argv line only the short comm */
198         if (arg_command_line_buffer) {
199                 size_t m, w;
200
201                 m = strlen(arg_command_line_buffer);
202                 w = snprintf(arg_command_line_buffer, m,
203                              "[PID "PID_FMT"/%s; UID "UID_FMT"/%s]",
204                              pid, comm,
205                              uid, name);
206
207                 if (m > w)
208                         memzero(arg_command_line_buffer + w, m - w);
209         }
210
211         log_debug("Running on behalf of PID "PID_FMT" (%s), UID "UID_FMT" (%s), %s",
212                   pid, p,
213                   uid, name,
214                   a->unique_name);
215
216         return 0;
217 }
218
219 int main(int argc, char *argv[]) {
220         _cleanup_(proxy_freep) Proxy *p = NULL;
221         int r;
222
223         log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
224         log_parse_environment();
225         log_open();
226
227         r = parse_argv(argc, argv);
228         if (r <= 0)
229                 goto finish;
230
231         r = proxy_new(&p, STDIN_FILENO, STDOUT_FILENO, arg_address);
232         if (r < 0)
233                 goto finish;
234
235         r = rename_service(p->destination_bus, p->local_bus);
236         if (r < 0)
237                 log_debug_errno(r, "Failed to rename process: %m");
238
239         r = proxy_run(p);
240
241 finish:
242         sd_notify(false,
243                   "STOPPING=1\n"
244                   "STATUS=Shutting down.");
245
246         free(arg_address);
247
248         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
249 }