]>
Commit | Line | Data |
---|---|---|
6dbe3af9 KZ |
1 | /* |
2 | * Copyright (c) 1983, 1993 | |
3 | * The Regents of the University of California. All rights reserved. | |
4 | * | |
5 | * Redistribution and use in source and binary forms, with or without | |
6 | * modification, are permitted provided that the following conditions | |
7 | * are met: | |
8 | * 1. Redistributions of source code must retain the above copyright | |
9 | * notice, this list of conditions and the following disclaimer. | |
10 | * 2. Redistributions in binary form must reproduce the above copyright | |
11 | * notice, this list of conditions and the following disclaimer in the | |
12 | * documentation and/or other materials provided with the distribution. | |
13 | * 3. All advertising materials mentioning features or use of this software | |
14 | * must display the following acknowledgement: | |
15 | * This product includes software developed by the University of | |
16 | * California, Berkeley and its contributors. | |
17 | * 4. Neither the name of the University nor the names of its contributors | |
18 | * may be used to endorse or promote products derived from this software | |
19 | * without specific prior written permission. | |
20 | * | |
21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
31 | * SUCH DAMAGE. | |
7eda085c | 32 | * |
b50945d4 | 33 | * 1999-02-22 Arkadiusz MiĆkiewicz <misiek@pld.ORG.PL> |
7eda085c KZ |
34 | * - added Native Language Support |
35 | * Sun Mar 21 1999 - Arnaldo Carvalho de Melo <acme@conectiva.com.br> | |
36 | * - fixed strerr(errno) in gettext calls | |
6dbe3af9 KZ |
37 | */ |
38 | ||
6dbe3af9 | 39 | #include <errno.h> |
047e2888 | 40 | #include <limits.h> |
6dbe3af9 KZ |
41 | #include <unistd.h> |
42 | #include <stdlib.h> | |
7eda085c | 43 | #include <time.h> |
6dbe3af9 KZ |
44 | #include <stdio.h> |
45 | #include <ctype.h> | |
46 | #include <string.h> | |
7eda085c KZ |
47 | #include <sys/types.h> |
48 | #include <sys/socket.h> | |
66ee8158 | 49 | #include <sys/un.h> |
912d6b98 WJE |
50 | #include <arpa/inet.h> |
51 | #include <netdb.h> | |
b363e86d SK |
52 | #include <getopt.h> |
53 | ||
633493be | 54 | #include "all-io.h" |
b363e86d | 55 | #include "c.h" |
c05a80ca | 56 | #include "closestream.h" |
7eda085c | 57 | #include "nls.h" |
b363e86d | 58 | #include "strutils.h" |
4b670c01 | 59 | #include "xalloc.h" |
6dbe3af9 KZ |
60 | |
61 | #define SYSLOG_NAMES | |
62 | #include <syslog.h> | |
63 | ||
ebff016a | 64 | #ifdef HAVE_LIBSYSTEMD |
4b670c01 SK |
65 | # include <systemd/sd-journal.h> |
66 | #endif | |
67 | ||
68265d07 SK |
68 | enum { |
69 | TYPE_UDP = (1 << 1), | |
70 | TYPE_TCP = (1 << 2), | |
71 | ALL_TYPES = TYPE_UDP | TYPE_TCP | |
72 | }; | |
73 | ||
98920f80 | 74 | enum { |
4b670c01 SK |
75 | OPT_PRIO_PREFIX = CHAR_MAX + 1, |
76 | OPT_JOURNALD | |
98920f80 DJ |
77 | }; |
78 | ||
79 | ||
80 | static char* get_prio_prefix(char *msg, int *prio) | |
81 | { | |
82 | int p; | |
83 | char *end = NULL; | |
84 | int facility = *prio & LOG_FACMASK; | |
85 | ||
86 | errno = 0; | |
87 | p = strtoul(msg + 1, &end, 10); | |
88 | ||
89 | if (errno || !end || end == msg + 1 || end[0] != '>') | |
90 | return msg; | |
91 | ||
92 | if (p & LOG_FACMASK) | |
93 | facility = p & LOG_FACMASK; | |
94 | ||
95 | *prio = facility | (p & LOG_PRIMASK); | |
96 | return end + 1; | |
97 | } | |
98 | ||
82054b1d DR |
99 | static int decode(char *name, CODE *codetab) |
100 | { | |
101 | register CODE *c; | |
102 | ||
4d7d1af6 SK |
103 | if (name == NULL || *name == '\0') |
104 | return -1; | |
105 | if (isdigit(*name)) { | |
106 | int num; | |
107 | char *end = NULL; | |
108 | ||
109 | num = strtol(name, &end, 10); | |
110 | if (errno || name == end || (end && *end)) | |
111 | return -1; | |
112 | for (c = codetab; c->c_name; c++) | |
113 | if (num == c->c_val) | |
114 | return num; | |
115 | return -1; | |
116 | } | |
82054b1d DR |
117 | for (c = codetab; c->c_name; c++) |
118 | if (!strcasecmp(name, c->c_name)) | |
119 | return (c->c_val); | |
120 | ||
121 | return -1; | |
122 | } | |
123 | ||
124 | static int pencode(char *s) | |
125 | { | |
126 | char *save; | |
127 | int fac, lev; | |
128 | ||
129 | for (save = s; *s && *s != '.'; ++s); | |
130 | if (*s) { | |
131 | *s = '\0'; | |
132 | fac = decode(save, facilitynames); | |
133 | if (fac < 0) | |
09af3db4 | 134 | errx(EXIT_FAILURE, _("unknown facility name: %s"), save); |
82054b1d DR |
135 | *s++ = '.'; |
136 | } | |
137 | else { | |
138 | fac = LOG_USER; | |
139 | s = save; | |
140 | } | |
141 | lev = decode(s, prioritynames); | |
142 | if (lev < 0) | |
09af3db4 | 143 | errx(EXIT_FAILURE, _("unknown priority name: %s"), save); |
82054b1d DR |
144 | return ((lev & LOG_PRIMASK) | (fac & LOG_FACMASK)); |
145 | } | |
146 | ||
195c3603 | 147 | static int unix_socket(const char *path, const int socket_type) |
fe6999da | 148 | { |
68265d07 | 149 | int fd, i; |
fe6999da | 150 | static struct sockaddr_un s_addr; /* AF_UNIX address of local logger */ |
7eda085c | 151 | |
68265d07 SK |
152 | if (strlen(path) >= sizeof(s_addr.sun_path)) |
153 | errx(EXIT_FAILURE, _("openlog %s: pathname too long"), path); | |
7eda085c | 154 | |
fe6999da | 155 | s_addr.sun_family = AF_UNIX; |
68265d07 SK |
156 | strcpy(s_addr.sun_path, path); |
157 | ||
158 | for (i = 2; i; i--) { | |
159 | int st = -1; | |
49999d6a | 160 | |
68265d07 SK |
161 | if (i == 2 && socket_type & TYPE_UDP) |
162 | st = SOCK_DGRAM; | |
163 | if (i == 1 && socket_type & TYPE_TCP) | |
164 | st = SOCK_STREAM; | |
165 | if (st == -1 || (fd = socket(AF_UNIX, st, 0)) == -1) | |
166 | continue; | |
fe6999da SK |
167 | if (connect(fd, (struct sockaddr *)&s_addr, sizeof(s_addr)) == -1) { |
168 | close(fd); | |
68265d07 | 169 | continue; |
fe6999da | 170 | } |
68265d07 | 171 | break; |
fe6999da | 172 | } |
7eda085c | 173 | |
68265d07 SK |
174 | if (i == 0) |
175 | err(EXIT_FAILURE, _("socket %s"), path); | |
176 | ||
fe6999da | 177 | return fd; |
7eda085c KZ |
178 | } |
179 | ||
195c3603 KZ |
180 | static int inet_socket(const char *servername, const char *port, |
181 | const int socket_type) | |
68265d07 SK |
182 | { |
183 | int fd, errcode, i; | |
24f4db69 | 184 | struct addrinfo hints, *res; |
68265d07 SK |
185 | const char *p = port; |
186 | ||
187 | for (i = 2; i; i--) { | |
188 | memset(&hints, 0, sizeof(hints)); | |
189 | if (i == 2 && socket_type & TYPE_UDP) { | |
190 | hints.ai_socktype = SOCK_DGRAM; | |
191 | if (port == NULL) | |
192 | p = "syslog"; | |
193 | } | |
194 | if (i == 1 && socket_type & TYPE_TCP) { | |
195 | hints.ai_socktype = SOCK_STREAM; | |
196 | if (port == NULL) | |
197 | p = "syslog-conn"; | |
198 | } | |
199 | if (hints.ai_socktype == 0) | |
200 | continue; | |
201 | hints.ai_family = AF_UNSPEC; | |
202 | errcode = getaddrinfo(servername, p, &hints, &res); | |
203 | if (errcode != 0) | |
4ce393f4 | 204 | errx(EXIT_FAILURE, _("failed to resolve name %s port %s: %s"), |
68265d07 SK |
205 | servername, p, gai_strerror(errcode)); |
206 | if ((fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1) { | |
207 | freeaddrinfo(res); | |
208 | continue; | |
209 | } | |
210 | if (connect(fd, res->ai_addr, res->ai_addrlen) == -1) { | |
211 | freeaddrinfo(res); | |
212 | close(fd); | |
213 | continue; | |
214 | } | |
24f4db69 | 215 | |
68265d07 SK |
216 | freeaddrinfo(res); |
217 | break; | |
218 | } | |
912d6b98 | 219 | |
68265d07 | 220 | if (i == 0) |
4ce393f4 | 221 | errx(EXIT_FAILURE, _("failed to connect to %s port %s"), servername, p); |
49999d6a | 222 | |
912d6b98 WJE |
223 | return fd; |
224 | } | |
68265d07 | 225 | |
ebff016a | 226 | #ifdef HAVE_LIBSYSTEMD |
4b670c01 SK |
227 | static int journald_entry(FILE *fp) |
228 | { | |
229 | struct iovec *iovec; | |
230 | char *buf = NULL; | |
231 | ssize_t sz; | |
232 | int n, lines, vectors = 8, ret; | |
233 | size_t dummy = 0; | |
234 | ||
235 | iovec = xmalloc(vectors * sizeof(struct iovec)); | |
236 | for (lines = 0; /* nothing */ ; lines++) { | |
237 | buf = NULL; | |
238 | sz = getline(&buf, &dummy, fp); | |
239 | if (sz == -1) | |
240 | break; | |
241 | if (0 < sz && buf[sz - 1] == '\n') { | |
242 | sz--; | |
243 | buf[sz] = '\0'; | |
244 | } | |
245 | if (lines == vectors) { | |
246 | vectors *= 2; | |
047e2888 SK |
247 | if (IOV_MAX < vectors) |
248 | errx(EXIT_FAILURE, _("maximum input lines (%d) exceeded"), IOV_MAX); | |
4b670c01 SK |
249 | iovec = xrealloc(iovec, vectors * sizeof(struct iovec)); |
250 | } | |
251 | iovec[lines].iov_base = buf; | |
252 | iovec[lines].iov_len = sz; | |
253 | } | |
254 | ret = sd_journal_sendv(iovec, lines); | |
255 | for (n = 0; n < lines; n++) | |
256 | free(iovec[n].iov_base); | |
257 | free(iovec); | |
258 | return ret; | |
259 | } | |
260 | #endif | |
261 | ||
195c3603 KZ |
262 | static void mysyslog(int fd, int logflags, int pri, char *tag, char *msg) |
263 | { | |
7eda085c KZ |
264 | char buf[1000], pid[30], *cp, *tp; |
265 | time_t now; | |
266 | ||
267 | if (fd > -1) { | |
7eda085c | 268 | if (logflags & LOG_PID) |
dd0d1654 | 269 | snprintf (pid, sizeof(pid), "[%d]", getpid()); |
7eda085c KZ |
270 | else |
271 | pid[0] = 0; | |
272 | if (tag) | |
273 | cp = tag; | |
274 | else { | |
275 | cp = getlogin(); | |
276 | if (!cp) | |
277 | cp = "<someone>"; | |
278 | } | |
89dda678 | 279 | time(&now); |
7eda085c KZ |
280 | tp = ctime(&now)+4; |
281 | ||
dd0d1654 | 282 | snprintf(buf, sizeof(buf), "<%d>%.15s %.200s%s: %.400s", |
7eda085c KZ |
283 | pri, tp, cp, pid, msg); |
284 | ||
633493be SK |
285 | if (write_all(fd, buf, strlen(buf)+1) < 0) |
286 | warn(_("write failed")); | |
7eda085c KZ |
287 | } |
288 | } | |
289 | ||
b363e86d SK |
290 | static void __attribute__ ((__noreturn__)) usage(FILE *out) |
291 | { | |
925aa9e8 | 292 | fputs(USAGE_HEADER, out); |
4ce393f4 | 293 | fprintf(out, _(" %s [options] [<message>]\n"), program_invocation_short_name); |
2da49186 | 294 | |
925aa9e8 | 295 | fputs(USAGE_OPTIONS, out); |
68265d07 | 296 | fputs(_(" -T, --tcp use TCP only\n"), out); |
925aa9e8 KZ |
297 | fputs(_(" -d, --udp use UDP only\n"), out); |
298 | fputs(_(" -i, --id log the process ID too\n"), out); | |
299 | fputs(_(" -f, --file <file> log the contents of this file\n"), out); | |
300 | fputs(_(" -n, --server <name> write to this remote syslog server\n"), out); | |
301 | fputs(_(" -P, --port <number> use this UDP port\n"), out); | |
302 | fputs(_(" -p, --priority <prio> mark given message with this priority\n"), out); | |
98920f80 | 303 | fputs(_(" --prio-prefix look for a prefix on every line read from stdin\n"), out); |
925aa9e8 KZ |
304 | fputs(_(" -s, --stderr output message to standard error as well\n"), out); |
305 | fputs(_(" -t, --tag <tag> mark every line with this tag\n"), out); | |
306 | fputs(_(" -u, --socket <socket> write to this Unix socket\n"), out); | |
ebff016a | 307 | #ifdef HAVE_LIBSYSTEMD |
4b670c01 SK |
308 | fputs(_(" --journald[=<file>] write journald entry\n"), out); |
309 | #endif | |
925aa9e8 KZ |
310 | |
311 | fputs(USAGE_SEPARATOR, out); | |
312 | fputs(USAGE_HELP, out); | |
313 | fputs(USAGE_VERSION, out); | |
314 | fprintf(out, USAGE_MAN_TAIL("logger(1)")); | |
b363e86d SK |
315 | |
316 | exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS); | |
317 | } | |
318 | ||
6dbe3af9 KZ |
319 | /* |
320 | * logger -- read and log utility | |
321 | * | |
322 | * Reads from an input and arranges to write the result on the system | |
323 | * log. | |
324 | */ | |
195c3603 KZ |
325 | int main(int argc, char **argv) |
326 | { | |
98920f80 | 327 | int ch, logflags, pri, prio_prefix; |
6dbe3af9 | 328 | char *tag, buf[1024]; |
7eda085c | 329 | char *usock = NULL; |
68265d07 SK |
330 | char *server = NULL; |
331 | char *port = NULL; | |
332 | int LogSock = -1, socket_type = ALL_TYPES; | |
ebff016a | 333 | #ifdef HAVE_LIBSYSTEMD |
4b670c01 SK |
334 | FILE *jfd = NULL; |
335 | #endif | |
b363e86d SK |
336 | static const struct option longopts[] = { |
337 | { "id", no_argument, 0, 'i' }, | |
338 | { "stderr", no_argument, 0, 's' }, | |
339 | { "file", required_argument, 0, 'f' }, | |
340 | { "priority", required_argument, 0, 'p' }, | |
341 | { "tag", required_argument, 0, 't' }, | |
342 | { "socket", required_argument, 0, 'u' }, | |
343 | { "udp", no_argument, 0, 'd' }, | |
68265d07 | 344 | { "tcp", no_argument, 0, 'T' }, |
b363e86d SK |
345 | { "server", required_argument, 0, 'n' }, |
346 | { "port", required_argument, 0, 'P' }, | |
347 | { "version", no_argument, 0, 'V' }, | |
348 | { "help", no_argument, 0, 'h' }, | |
98920f80 | 349 | { "prio-prefix", no_argument, 0, OPT_PRIO_PREFIX }, |
ebff016a | 350 | #ifdef HAVE_LIBSYSTEMD |
4b670c01 SK |
351 | { "journald", optional_argument, 0, OPT_JOURNALD }, |
352 | #endif | |
b363e86d SK |
353 | { NULL, 0, 0, 0 } |
354 | }; | |
7eda085c KZ |
355 | |
356 | setlocale(LC_ALL, ""); | |
357 | bindtextdomain(PACKAGE, LOCALEDIR); | |
358 | textdomain(PACKAGE); | |
c05a80ca | 359 | atexit(close_stdout); |
6dbe3af9 KZ |
360 | |
361 | tag = NULL; | |
362 | pri = LOG_NOTICE; | |
363 | logflags = 0; | |
98920f80 | 364 | prio_prefix = 0; |
68265d07 | 365 | while ((ch = getopt_long(argc, argv, "f:ip:st:u:dTn:P:Vh", |
49999d6a | 366 | longopts, NULL)) != -1) { |
98920f80 | 367 | switch (ch) { |
6dbe3af9 | 368 | case 'f': /* file to log */ |
49999d6a SK |
369 | if (freopen(optarg, "r", stdin) == NULL) |
370 | err(EXIT_FAILURE, _("file %s"), | |
371 | optarg); | |
6dbe3af9 KZ |
372 | break; |
373 | case 'i': /* log process id also */ | |
374 | logflags |= LOG_PID; | |
375 | break; | |
376 | case 'p': /* priority */ | |
377 | pri = pencode(optarg); | |
378 | break; | |
379 | case 's': /* log to standard error */ | |
380 | logflags |= LOG_PERROR; | |
381 | break; | |
382 | case 't': /* tag */ | |
383 | tag = optarg; | |
384 | break; | |
7eda085c KZ |
385 | case 'u': /* unix socket */ |
386 | usock = optarg; | |
387 | break; | |
66ee8158 | 388 | case 'd': |
68265d07 SK |
389 | socket_type = TYPE_UDP; |
390 | break; | |
391 | case 'T': | |
392 | socket_type = TYPE_TCP; | |
66ee8158 | 393 | break; |
68265d07 SK |
394 | case 'n': |
395 | server = optarg; | |
912d6b98 | 396 | break; |
68265d07 SK |
397 | case 'P': |
398 | port = optarg; | |
912d6b98 | 399 | break; |
b363e86d | 400 | case 'V': |
e421313d | 401 | printf(UTIL_LINUX_VERSION); |
b363e86d SK |
402 | exit(EXIT_SUCCESS); |
403 | case 'h': | |
404 | usage(stdout); | |
98920f80 DJ |
405 | case OPT_PRIO_PREFIX: |
406 | prio_prefix = 1; | |
407 | break; | |
ebff016a | 408 | #ifdef HAVE_LIBSYSTEMD |
4b670c01 SK |
409 | case OPT_JOURNALD: |
410 | if (optarg) { | |
411 | jfd = fopen(optarg, "r"); | |
412 | if (!jfd) | |
413 | err(EXIT_FAILURE, _("cannot open %s"), | |
414 | optarg); | |
415 | } else | |
416 | jfd = stdin; | |
417 | break; | |
418 | #endif | |
6dbe3af9 KZ |
419 | case '?': |
420 | default: | |
b363e86d | 421 | usage(stderr); |
6dbe3af9 | 422 | } |
49999d6a | 423 | } |
6dbe3af9 KZ |
424 | argc -= optind; |
425 | argv += optind; | |
426 | ||
427 | /* setup for logging */ | |
ebff016a | 428 | #ifdef HAVE_LIBSYSTEMD |
4b670c01 SK |
429 | if (jfd) { |
430 | int ret = journald_entry(jfd); | |
431 | if (stdin != jfd) | |
432 | fclose(jfd); | |
047e2888 SK |
433 | if (ret) |
434 | errx(EXIT_FAILURE, "journald entry could not be wrote"); | |
435 | return EXIT_SUCCESS; | |
4b670c01 SK |
436 | } |
437 | #endif | |
2885c533 | 438 | if (server) |
68265d07 | 439 | LogSock = inet_socket(server, port, socket_type); |
2885c533 | 440 | else if (usock) |
68265d07 | 441 | LogSock = unix_socket(usock, socket_type); |
2885c533 KZ |
442 | else |
443 | openlog(tag ? tag : getlogin(), logflags, 0); | |
7eda085c | 444 | |
6dbe3af9 KZ |
445 | /* log input line if appropriate */ |
446 | if (argc > 0) { | |
447 | register char *p, *endp; | |
dd49983a | 448 | size_t len; |
6dbe3af9 KZ |
449 | |
450 | for (p = buf, endp = buf + sizeof(buf) - 2; *argv;) { | |
451 | len = strlen(*argv); | |
452 | if (p + len > endp && p > buf) { | |
68265d07 | 453 | if (!usock && !server) |
6dbe3af9 | 454 | syslog(pri, "%s", buf); |
7eda085c KZ |
455 | else |
456 | mysyslog(LogSock, logflags, pri, tag, buf); | |
6dbe3af9 KZ |
457 | p = buf; |
458 | } | |
7eda085c | 459 | if (len > sizeof(buf) - 1) { |
68265d07 | 460 | if (!usock && !server) |
6dbe3af9 | 461 | syslog(pri, "%s", *argv++); |
7eda085c KZ |
462 | else |
463 | mysyslog(LogSock, logflags, pri, tag, *argv++); | |
464 | } else { | |
6dbe3af9 KZ |
465 | if (p != buf) |
466 | *p++ = ' '; | |
c0f19ccf | 467 | memmove(p, *argv++, len); |
6dbe3af9 KZ |
468 | *(p += len) = '\0'; |
469 | } | |
470 | } | |
7eda085c | 471 | if (p != buf) { |
68265d07 | 472 | if (!usock && !server) |
6dbe3af9 | 473 | syslog(pri, "%s", buf); |
7eda085c KZ |
474 | else |
475 | mysyslog(LogSock, logflags, pri, tag, buf); | |
476 | } | |
49999d6a | 477 | } else { |
98920f80 DJ |
478 | char *msg; |
479 | int default_priority = pri; | |
7eda085c | 480 | while (fgets(buf, sizeof(buf), stdin) != NULL) { |
eb63b9b8 KZ |
481 | /* glibc is buggy and adds an additional newline, |
482 | so we have to remove it here until glibc is fixed */ | |
483 | int len = strlen(buf); | |
484 | ||
485 | if (len > 0 && buf[len - 1] == '\n') | |
486 | buf[len - 1] = '\0'; | |
487 | ||
98920f80 DJ |
488 | msg = buf; |
489 | pri = default_priority; | |
490 | if (prio_prefix && msg[0] == '<') | |
491 | msg = get_prio_prefix(msg, &pri); | |
492 | ||
68265d07 | 493 | if (!usock && !server) |
98920f80 | 494 | syslog(pri, "%s", msg); |
7eda085c | 495 | else |
98920f80 | 496 | mysyslog(LogSock, logflags, pri, tag, msg); |
7eda085c | 497 | } |
49999d6a | 498 | } |
68265d07 | 499 | if (!usock && !server) |
7eda085c KZ |
500 | closelog(); |
501 | else | |
502 | close(LogSock); | |
49999d6a SK |
503 | |
504 | return EXIT_SUCCESS; | |
6dbe3af9 | 505 | } |