chiark / gitweb /
ba2fb4789f0b17395de12e52ff80e26983af787f
[elogind.git] / src / escape / escape.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2014 Michael Biebl
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 <stdlib.h>
24 #include <getopt.h>
25
26 #include "log.h"
27 #include "unit-name.h"
28 #include "build.h"
29 #include "strv.h"
30
31 static enum {
32         ACTION_ESCAPE,
33         ACTION_UNESCAPE,
34         ACTION_MANGLE
35 } arg_action = ACTION_ESCAPE;
36 static const char *arg_suffix = NULL;
37 static const char *arg_template = NULL;
38 static bool arg_path = false;
39
40 static int help(void) {
41
42         printf("%s [OPTIONS...] [NAME...]\n\n"
43                "Show system and user paths.\n\n"
44                "  -h --help               Show this help\n"
45                "     --version            Show package version\n"
46                "     --suffix=SUFFIX      Unit suffix to append to escaped strings\n"
47                "     --template=TEMPLATE  Insert strings as instance into template\n"
48                "  -u --unescape           Unescape strings\n"
49                "  -m --mangle             Mangle strings\n"
50                "  -p --path               When escaping/unescaping assume the string is a path\n",
51                program_invocation_short_name);
52
53         return 0;
54 }
55
56 static int parse_argv(int argc, char *argv[]) {
57
58         enum {
59                 ARG_VERSION = 0x100,
60                 ARG_SUFFIX,
61                 ARG_TEMPLATE
62         };
63
64         static const struct option options[] = {
65                 { "help",      no_argument,       NULL, 'h'           },
66                 { "version",   no_argument,       NULL, ARG_VERSION   },
67                 { "suffix",    required_argument, NULL, ARG_SUFFIX    },
68                 { "template",  required_argument, NULL, ARG_TEMPLATE  },
69                 { "unescape",  no_argument,       NULL, 'u'           },
70                 { "mangle",    no_argument,       NULL, 'm'           },
71                 { "path",      no_argument,       NULL, 'p'           },
72                 {}
73         };
74
75         int c;
76
77         assert(argc >= 0);
78         assert(argv);
79
80         while ((c = getopt_long(argc, argv, "hump", options, NULL)) >= 0) {
81
82                 switch (c) {
83
84                 case 'h':
85                         return help();
86
87                 case ARG_VERSION:
88                         puts(PACKAGE_STRING);
89                         puts(SYSTEMD_FEATURES);
90                         return 0;
91
92                 case ARG_SUFFIX:
93
94                         if (unit_type_from_string(optarg) < 0) {
95                                 log_error("Invalid unit suffix type %s.", optarg);
96                                 return -EINVAL;
97                         }
98
99                         arg_suffix = optarg;
100                         break;
101
102                 case ARG_TEMPLATE:
103
104                         if (!unit_name_is_valid(optarg, true) || !unit_name_is_template(optarg)) {
105                                 log_error("Template name %s is not valid.", optarg);
106                                 return -EINVAL;
107                         }
108
109                         arg_template = optarg;
110                         break;
111
112                 case 'u':
113                         arg_action = ACTION_UNESCAPE;
114                         break;
115
116                 case 'm':
117                         arg_action = ACTION_MANGLE;
118                         break;
119
120                 case 'p':
121                         arg_path = true;
122                         break;
123
124                 case '?':
125                         return -EINVAL;
126
127                 default:
128                         assert_not_reached("Unhandled option");
129                 }
130         }
131
132         if (optind >= argc) {
133                 log_error("Not enough arguments.");
134                 return -EINVAL;
135         }
136
137         if (arg_template && arg_suffix) {
138                 log_error("--suffix= and --template= may not be combined.");
139                 return -EINVAL;
140         }
141
142         if ((arg_template || arg_suffix) && arg_action != ACTION_ESCAPE) {
143                 log_error("--suffix= and --template= are not compatible with --unescape or --mangle.");
144                 return -EINVAL;
145         }
146
147         if (arg_path && !IN_SET(arg_action, ACTION_ESCAPE, ACTION_UNESCAPE)) {
148                 log_error("--path may not be combined with --mangle.");
149                 return -EINVAL;
150         }
151
152         return 1;
153 }
154
155 int main(int argc, char *argv[]) {
156         char **i;
157         int r;
158
159         log_parse_environment();
160         log_open();
161
162         r = parse_argv(argc, argv);
163         if (r <= 0)
164                 goto finish;
165
166         STRV_FOREACH(i, argv + optind) {
167                 _cleanup_free_ char *e = NULL;
168
169                 switch (arg_action) {
170
171                 case ACTION_ESCAPE:
172                         if (arg_path)
173                                 e = unit_name_path_escape(*i);
174                         else
175                                 e = unit_name_escape(*i);
176
177                         if (!e) {
178                                 r = log_oom();
179                                 goto finish;
180                         }
181
182                         if (arg_template) {
183                                 char *x;
184
185                                 x = unit_name_replace_instance(arg_template, e);
186                                 if (!x) {
187                                         r = log_oom();
188                                         goto finish;
189                                 }
190
191                                 free(e);
192                                 e = x;
193                         } else if (arg_suffix) {
194                                 char *x;
195
196                                 x = strjoin(e, ".", arg_suffix, NULL);
197                                 if (!x) {
198                                         r = log_oom();
199                                         goto finish;
200                                 }
201
202                                 free(e);
203                                 e = x;
204                         }
205
206                         break;
207
208                 case ACTION_UNESCAPE:
209                         if (arg_path)
210                                 e = unit_name_path_unescape(*i);
211                         else
212                                 e = unit_name_unescape(*i);
213
214                         if (!e) {
215                                 r = log_oom();
216                                 goto finish;
217                         }
218                         break;
219
220                 case ACTION_MANGLE:
221                         e = unit_name_mangle(*i, MANGLE_NOGLOB);
222                         if (!e) {
223                                 r = log_oom();
224                                 goto finish;
225                         }
226                         break;
227                 }
228
229                 if (i != argv+optind)
230                         fputc(' ', stdout);
231
232                 fputs(e, stdout);
233         }
234
235         fputc('\n', stdout);
236
237 finish:
238         return r <= 0 ? EXIT_FAILURE : EXIT_SUCCESS;
239 }