|  |  | varnish-cache/bin/varnishadm/varnishadm.c | 
|---|
| 0 |  | /*- | 
| 1 |  |  * Copyright (c) 2006 Verdens Gang AS | 
| 2 |  |  * Copyright (c) 2006-2015 Varnish Software AS | 
| 3 |  |  * All rights reserved. | 
| 4 |  |  * | 
| 5 |  |  * Author: Cecilie Fritzvold <cecilihf@linpro.no> | 
| 6 |  |  * | 
| 7 |  |  * SPDX-License-Identifier: BSD-2-Clause | 
| 8 |  |  * | 
| 9 |  |  * Redistribution and use in source and binary forms, with or without | 
| 10 |  |  * modification, are permitted provided that the following conditions | 
| 11 |  |  * are met: | 
| 12 |  |  * 1. Redistributions of source code must retain the above copyright | 
| 13 |  |  *    notice, this list of conditions and the following disclaimer. | 
| 14 |  |  * 2. Redistributions in binary form must reproduce the above copyright | 
| 15 |  |  *    notice, this list of conditions and the following disclaimer in the | 
| 16 |  |  *    documentation and/or other materials provided with the distribution. | 
| 17 |  |  * | 
| 18 |  |  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | 
| 19 |  |  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
| 20 |  |  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 
| 21 |  |  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE | 
| 22 |  |  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 
| 23 |  |  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 
| 24 |  |  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 
| 25 |  |  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 
| 26 |  |  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 
| 27 |  |  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 
| 28 |  |  * SUCH DAMAGE. | 
| 29 |  |  */ | 
| 30 |  |  | 
| 31 |  | #include "config.h" | 
| 32 |  |  | 
| 33 |  | #include <sys/types.h> | 
| 34 |  | #include <sys/socket.h> | 
| 35 |  |  | 
| 36 |  | #include <stdio.h> | 
| 37 |  |  | 
| 38 |  | #if defined(HAVE_EDIT_READLINE_READLINE_H) | 
| 39 |  | #  include <edit/readline/readline.h> | 
| 40 |  | #elif defined(HAVE_LIBEDIT) | 
| 41 |  | #  include <editline/readline.h> | 
| 42 |  | #elif defined (HAVE_READLINE_READLINE_H) | 
| 43 |  | #  include <readline/readline.h> | 
| 44 |  | #  ifdef HAVE_READLINE_HISTORY_H | 
| 45 |  | #    include <readline/history.h> | 
| 46 |  | #  else | 
| 47 |  | #    error missing history.h - this should have got caught in configure | 
| 48 |  | #  endif | 
| 49 |  | #else | 
| 50 |  | #  error missing readline.h - this should have got caught in configure | 
| 51 |  | #endif | 
| 52 |  |  | 
| 53 |  | #include <math.h> | 
| 54 |  | #include <fcntl.h> | 
| 55 |  | #include <poll.h> | 
| 56 |  | #include <stdint.h> | 
| 57 |  | #include <stdlib.h> | 
| 58 |  | #include <string.h> | 
| 59 |  | #include <unistd.h> | 
| 60 |  |  | 
| 61 |  | #include "vdef.h" | 
| 62 |  |  | 
| 63 |  | #include "vqueue.h" | 
| 64 |  |  | 
| 65 |  | #include "vapi/vsig.h" | 
| 66 |  | #include "vapi/vsm.h" | 
| 67 |  | #include "vas.h" | 
| 68 |  | #include "vcli.h" | 
| 69 |  | #include "vjsn.h" | 
| 70 |  | #include "vtcp.h" | 
| 71 |  |  | 
| 72 |  | #define RL_EXIT(status) \ | 
| 73 |  |         do { \ | 
| 74 |  |                 rl_callback_handler_remove(); \ | 
| 75 |  |                 exit(status); \ | 
| 76 |  |         } while (0) | 
| 77 |  |  | 
| 78 |  | enum pass_mode_e { | 
| 79 |  |         pass_script, | 
| 80 |  |         pass_interactive, | 
| 81 |  | }; | 
| 82 |  |  | 
| 83 |  | static double timeout = 5; | 
| 84 |  | static int p_arg = 0; | 
| 85 |  | static int line_sock; | 
| 86 |  |  | 
| 87 |  | static void | 
| 88 | 3000 | cli_write(int sock, const char *s) | 
| 89 |  | { | 
| 90 |  |         int i, l; | 
| 91 |  |  | 
| 92 | 3000 |         i = strlen(s); | 
| 93 | 3000 |         l = write (sock, s, i); | 
| 94 | 3000 |         if (i == l) | 
| 95 | 3000 |                 return; | 
| 96 | 0 |         perror("Write error CLI socket"); | 
| 97 | 0 |         RL_EXIT(1); | 
| 98 | 3000 | } | 
| 99 |  |  | 
| 100 |  | /* | 
| 101 |  |  * This function establishes a connection to the specified ip and port and | 
| 102 |  |  * sends a command to varnishd. If varnishd returns an OK status, the result | 
| 103 |  |  * is printed and 0 returned. Else, an error message is printed and 1 is | 
| 104 |  |  * returned | 
| 105 |  |  */ | 
| 106 |  | static int | 
| 107 | 480 | cli_sock(const char *T_arg, const char *S_arg) | 
| 108 |  | { | 
| 109 |  |         int fd; | 
| 110 |  |         int sock; | 
| 111 |  |         unsigned status; | 
| 112 | 480 |         char *answer = NULL; | 
| 113 |  |         char buf[CLI_AUTH_RESPONSE_LEN + 1]; | 
| 114 |  |         const char *err; | 
| 115 |  |  | 
| 116 | 480 |         sock = VTCP_open(T_arg, NULL, timeout, &err); | 
| 117 | 480 |         if (sock < 0) { | 
| 118 | 10 |                 fprintf(stderr, "Connection failed (%s): %s\n", T_arg, err); | 
| 119 | 10 |                 return (-1); | 
| 120 |  |         } | 
| 121 |  |  | 
| 122 | 470 |         (void)VCLI_ReadResult(sock, &status, &answer, timeout); | 
| 123 | 470 |         if (status == CLIS_AUTH) { | 
| 124 | 460 |                 if (S_arg == NULL) { | 
| 125 | 10 |                         fprintf(stderr, "Authentication required\n"); | 
| 126 | 10 |                         free(answer); | 
| 127 | 10 |                         closefd(&sock); | 
| 128 | 10 |                         return (-1); | 
| 129 |  |                 } | 
| 130 | 450 |                 fd = open(S_arg, O_RDONLY); | 
| 131 | 450 |                 if (fd < 0) { | 
| 132 | 20 |                         fprintf(stderr, "Cannot open \"%s\": %s\n", | 
| 133 | 10 |                             S_arg, strerror(errno)); | 
| 134 | 10 |                         closefd(&sock); | 
| 135 | 10 |                         free(answer); | 
| 136 | 10 |                         return (-1); | 
| 137 |  |                 } | 
| 138 | 440 |                 VCLI_AuthResponse(fd, answer, buf); | 
| 139 | 440 |                 closefd(&fd); | 
| 140 | 440 |                 free(answer); | 
| 141 |  |  | 
| 142 | 440 |                 cli_write(sock, "auth "); | 
| 143 | 440 |                 cli_write(sock, buf); | 
| 144 | 440 |                 cli_write(sock, "\n"); | 
| 145 | 440 |                 (void)VCLI_ReadResult(sock, &status, &answer, timeout); | 
| 146 | 440 |         } | 
| 147 | 450 |         if (status != CLIS_OK && status != CLIS_TRUNCATED) { | 
| 148 | 20 |                 fprintf(stderr, "Rejected %u\n%s\n", status, answer); | 
| 149 | 20 |                 closefd(&sock); | 
| 150 | 20 |                 free(answer); | 
| 151 | 20 |                 return (-1); | 
| 152 |  |         } | 
| 153 | 430 |         free(answer); | 
| 154 |  |  | 
| 155 | 430 |         cli_write(sock, "ping\n"); | 
| 156 | 430 |         (void)VCLI_ReadResult(sock, &status, &answer, timeout); | 
| 157 | 430 |         if (status != CLIS_OK || strstr(answer, "PONG") == NULL) { | 
| 158 | 10 |                 fprintf(stderr, "No pong received from server\n"); | 
| 159 | 10 |                 closefd(&sock); | 
| 160 | 10 |                 free(answer); | 
| 161 | 10 |                 return (-1); | 
| 162 |  |         } | 
| 163 | 420 |         free(answer); | 
| 164 |  |  | 
| 165 | 420 |         return (sock); | 
| 166 | 480 | } | 
| 167 |  |  | 
| 168 |  | static unsigned | 
| 169 | 480 | pass_answer(int fd, enum pass_mode_e mode) | 
| 170 |  | { | 
| 171 |  |         unsigned u, status; | 
| 172 | 480 |         char *answer = NULL; | 
| 173 |  |  | 
| 174 | 480 |         u = VCLI_ReadResult(fd, &status, &answer, timeout); | 
| 175 | 480 |         if (u) { | 
| 176 | 0 |                 if (status == CLIS_COMMS) { | 
| 177 | 0 |                         fprintf(stderr, "%s\n", answer); | 
| 178 | 0 |                         RL_EXIT(2); | 
| 179 | 0 |                 } | 
| 180 | 0 |                 if (answer) | 
| 181 | 0 |                         fprintf(stderr, "%s\n", answer); | 
| 182 | 0 |                 RL_EXIT(1); | 
| 183 | 0 |         } | 
| 184 |  |  | 
| 185 | 480 |         if (p_arg && answer != NULL) { | 
| 186 | 70 |                 printf("%-3u %-8zu\n%s", status, strlen(answer), answer); | 
| 187 | 480 |         } else if (p_arg) { | 
| 188 | 0 |                 printf("%-3u %-8u\n", status, 0U); | 
| 189 | 0 |         } else { | 
| 190 | 410 |                 if (mode == pass_interactive) | 
| 191 | 50 |                         printf("%u\n", status); | 
| 192 | 410 |                 if (answer != NULL) | 
| 193 | 410 |                         printf("%s\n", answer); | 
| 194 | 410 |                 if (status == CLIS_TRUNCATED) | 
| 195 | 10 |                         printf("[response was truncated]\n"); | 
| 196 |  |         } | 
| 197 | 480 |         free(answer); | 
| 198 | 480 |         (void)fflush(stdout); | 
| 199 | 480 |         return (status); | 
| 200 |  | } | 
| 201 |  |  | 
| 202 |  | static void v_noreturn_ | 
| 203 | 360 | do_args(int sock, int argc, char * const *argv) | 
| 204 |  | { | 
| 205 |  |         int i; | 
| 206 |  |         unsigned status; | 
| 207 |  |  | 
| 208 | 880 |         for (i = 0; i < argc; i++) { | 
| 209 |  |                 /* XXX: We should really CLI-quote these */ | 
| 210 | 520 |                 if (i > 0) | 
| 211 | 160 |                         cli_write(sock, " "); | 
| 212 | 520 |                 cli_write(sock, argv[i]); | 
| 213 | 520 |         } | 
| 214 | 360 |         cli_write(sock, "\n"); | 
| 215 | 360 |         status = pass_answer(sock, pass_script); | 
| 216 | 360 |         closefd(&sock); | 
| 217 | 360 |         if (status == CLIS_OK || status == CLIS_TRUNCATED) | 
| 218 | 290 |                 exit(0); | 
| 219 | 70 |         if (!p_arg) | 
| 220 | 70 |                 fprintf(stderr, "Command failed with error code %u\n", status); | 
| 221 | 70 |         exit(1); | 
| 222 |  | } | 
| 223 |  |  | 
| 224 |  | /* Callback for readline, doesn't take a private pointer, so we need | 
| 225 |  |  * to have a global variable. | 
| 226 |  |  */ | 
| 227 |  | static void v_matchproto_() | 
| 228 | 40 | send_line(char *l) | 
| 229 |  | { | 
| 230 | 40 |         if (l) { | 
| 231 | 40 |                 cli_write(line_sock, l); | 
| 232 | 40 |                 cli_write(line_sock, "\n"); | 
| 233 | 40 |                 if (*l) | 
| 234 | 40 |                         add_history(l); | 
| 235 | 40 |                 rl_callback_handler_install("varnish> ", send_line); | 
| 236 | 40 |         } else { | 
| 237 | 0 |                 RL_EXIT(0); | 
| 238 |  |         } | 
| 239 | 40 | } | 
| 240 |  |  | 
| 241 |  | static char * | 
| 242 | 140 | command_generator (const char *text, int state) | 
| 243 |  | { | 
| 244 |  |         static struct vjsn *jsn_cmds; | 
| 245 |  |         static const struct vjsn_val *jv; | 
| 246 |  |         struct vjsn_val *jv2; | 
| 247 |  |         unsigned u; | 
| 248 | 140 |         char *answer = NULL; | 
| 249 |  |         const char *err; | 
| 250 |  |  | 
| 251 | 140 |         if (!state) { | 
| 252 | 50 |                 cli_write(line_sock, "help -j\n"); | 
| 253 | 50 |                 u = VCLI_ReadResult(line_sock, NULL, &answer, timeout); | 
| 254 | 50 |                 if (u) { | 
| 255 | 0 |                         free(answer); | 
| 256 | 0 |                         return (NULL); | 
| 257 |  |                 } | 
| 258 | 50 |                 jsn_cmds = vjsn_parse(answer, &err); | 
| 259 | 50 |                 free(answer); | 
| 260 | 50 |                 if (err != NULL) | 
| 261 | 0 |                         return (NULL); | 
| 262 | 50 |                 AN(jsn_cmds); | 
| 263 | 50 |                 AN(jsn_cmds->value); | 
| 264 | 50 |                 assert (vjsn_is_array(jsn_cmds->value)); | 
| 265 | 50 |                 jv = VTAILQ_FIRST(&jsn_cmds->value->children); | 
| 266 | 50 |                 assert (vjsn_is_number(jv)); | 
| 267 | 50 |                 jv = VTAILQ_NEXT(jv, list); | 
| 268 | 50 |                 assert (vjsn_is_array(jv)); | 
| 269 | 50 |                 jv = VTAILQ_NEXT(jv, list); | 
| 270 | 50 |                 assert (vjsn_is_number(jv)); | 
| 271 | 50 |                 jv = VTAILQ_NEXT(jv, list); | 
| 272 | 50 |         } | 
| 273 | 1950 |         while (jv != NULL) { | 
| 274 | 1900 |                 assert (vjsn_is_object(jv)); | 
| 275 | 1900 |                 jv2 = VTAILQ_FIRST(&jv->children); | 
| 276 | 1900 |                 AN(jv2); | 
| 277 | 1900 |                 jv = VTAILQ_NEXT(jv, list); | 
| 278 | 1900 |                 assert (vjsn_is_string(jv2)); | 
| 279 | 1900 |                 assert (!strcmp(jv2->name, "request")); | 
| 280 | 1900 |                 if (!strncmp(text, jv2->value, strlen(text))) | 
| 281 | 90 |                         return (strdup(jv2->value)); | 
| 282 |  |         } | 
| 283 | 50 |         vjsn_delete(&jsn_cmds); | 
| 284 | 50 |         return (NULL); | 
| 285 | 140 | } | 
| 286 |  |  | 
| 287 |  | static char ** | 
| 288 | 50 | varnishadm_completion (const char *text, int start, int end) | 
| 289 |  | { | 
| 290 |  |         char **matches; | 
| 291 | 50 |         (void)end; | 
| 292 | 50 |         matches = (char **)NULL; | 
| 293 | 50 |         if (start == 0) | 
| 294 | 50 |                 matches = rl_completion_matches(text, command_generator); | 
| 295 | 50 |         return (matches); | 
| 296 |  | } | 
| 297 |  |  | 
| 298 |  |  | 
| 299 |  | /* | 
| 300 |  |  * No arguments given, simply pass bytes on stdin/stdout and CLI socket | 
| 301 |  |  * Send a "banner" to varnish, to provoke a welcome message. | 
| 302 |  |  */ | 
| 303 |  | static void v_noreturn_ | 
| 304 | 10 | interactive(int sock) | 
| 305 |  | { | 
| 306 |  |         struct pollfd fds[2]; | 
| 307 |  |         int i; | 
| 308 |  |         unsigned status; | 
| 309 | 10 |         line_sock = sock; | 
| 310 | 10 |         rl_already_prompted = 1; | 
| 311 | 10 |         rl_callback_handler_install("varnish> ", send_line); | 
| 312 | 10 |         rl_attempted_completion_function = varnishadm_completion; | 
| 313 |  |  | 
| 314 | 10 |         fds[0].fd = sock; | 
| 315 | 10 |         fds[0].events = POLLIN; | 
| 316 | 10 |         fds[1].fd = 0; | 
| 317 | 10 |         fds[1].events = POLLIN; | 
| 318 |  |  | 
| 319 | 10 |         cli_write(sock, "banner\n"); | 
| 320 | 380 |         while (1) { | 
| 321 | 380 |                 i = poll(fds, 2, -1); | 
| 322 | 380 |                 if (i == -1 && errno == EINTR) { | 
| 323 | 0 |                         continue; | 
| 324 |  |                 } | 
| 325 | 380 |                 assert(i > 0); | 
| 326 | 380 |                 if (fds[0].revents & POLLIN) { | 
| 327 |  |                         /* Get rid of the prompt, kinda hackish */ | 
| 328 | 50 |                         printf("\r           \r"); | 
| 329 | 50 |                         status = pass_answer(fds[0].fd, pass_interactive); | 
| 330 | 50 |                         rl_forced_update_display(); | 
| 331 | 50 |                         if (status == CLIS_CLOSE) | 
| 332 | 10 |                                 RL_EXIT(0); | 
| 333 | 40 |                 } | 
| 334 | 370 |                 if (fds[1].revents & POLLIN) { | 
| 335 | 330 |                         rl_callback_read_char(); | 
| 336 | 330 |                 } | 
| 337 |  |         } | 
| 338 |  | } | 
| 339 |  |  | 
| 340 |  | /* | 
| 341 |  |  * No arguments given, simply pass bytes on stdin/stdout and CLI socket | 
| 342 |  |  */ | 
| 343 |  | static void v_noreturn_ | 
| 344 | 50 | pass(int sock) | 
| 345 |  | { | 
| 346 |  |         struct pollfd fds[2]; | 
| 347 |  |         char buf[1024]; | 
| 348 |  |         int i; | 
| 349 |  |         ssize_t n; | 
| 350 | 50 |         int busy = 0; | 
| 351 |  |  | 
| 352 | 50 |         fds[0].fd = sock; | 
| 353 | 50 |         fds[0].events = POLLIN; | 
| 354 | 50 |         fds[1].fd = 0; | 
| 355 | 50 |         fds[1].events = POLLIN; | 
| 356 | 190 |         while (1) { | 
| 357 | 190 |                 i = poll(fds, 2, -1); | 
| 358 | 190 |                 if (i == -1 && errno == EINTR) { | 
| 359 | 0 |                         continue; | 
| 360 |  |                 } | 
| 361 | 190 |                 assert(i > 0); | 
| 362 | 190 |                 if (fds[0].revents & POLLIN) { | 
| 363 | 70 |                         (void)pass_answer(fds[0].fd, pass_script); | 
| 364 | 70 |                         busy = 0; | 
| 365 | 70 |                         if (fds[1].fd < 0) | 
| 366 | 40 |                                 RL_EXIT(0); | 
| 367 | 30 |                 } | 
| 368 | 150 |                 if (fds[1].revents & POLLIN || fds[1].revents & POLLHUP) { | 
| 369 | 120 |                         n = read(fds[1].fd, buf, sizeof buf - 1); | 
| 370 | 120 |                         if (n == 0) { | 
| 371 | 50 |                                 if (!busy) | 
| 372 | 10 |                                         RL_EXIT(0); | 
| 373 | 40 |                                 fds[1].fd = -1; | 
| 374 | 110 |                         } else if (n < 0) { | 
| 375 | 0 |                                 RL_EXIT(0); | 
| 376 | 0 |                         } else { | 
| 377 | 70 |                                 busy = 1; | 
| 378 | 70 |                                 buf[n] = '\0'; | 
| 379 | 70 |                                 cli_write(sock, buf); | 
| 380 |  |                         } | 
| 381 | 110 |                 } | 
| 382 |  |         } | 
| 383 |  | } | 
| 384 |  |  | 
| 385 |  |  | 
| 386 |  | static void v_noreturn_ | 
| 387 | 30 | usage(int status) | 
| 388 |  | { | 
| 389 | 30 |         fprintf(stderr, | 
| 390 |  |             "Usage: varnishadm [-h] [-n workdir] [-p] [-S secretfile] " | 
| 391 |  |             "[-T [address]:port] [-t timeout] [command [...]]\n"); | 
| 392 | 30 |         fprintf(stderr, "\t-n is mutually exclusive with -S and -T\n"); | 
| 393 | 30 |         exit(status); | 
| 394 |  | } | 
| 395 |  |  | 
| 396 |  | static int | 
| 397 | 430 | n_arg_sock(const char *n_arg, const char *t_arg) | 
| 398 |  | { | 
| 399 |  |         char *T_arg, *T_start; | 
| 400 |  |         char *S_arg; | 
| 401 |  |         struct vsm *vsm; | 
| 402 |  |         char *p; | 
| 403 |  |         int sock; | 
| 404 |  |  | 
| 405 | 430 |         vsm = VSM_New(); | 
| 406 | 430 |         AN(vsm); | 
| 407 | 850 |         if (VSM_Arg(vsm, 'n', n_arg) < 0 || | 
| 408 | 430 |             VSM_Arg(vsm, 't', t_arg) < 0 || | 
| 409 | 420 |             VSM_Attach(vsm, STDERR_FILENO) < 0) { | 
| 410 | 20 |                 fprintf(stderr, "%s\n", VSM_Error(vsm)); | 
| 411 | 20 |                 VSM_Destroy(&vsm); | 
| 412 | 20 |                 return (-1); | 
| 413 |  |         } | 
| 414 |  |  | 
| 415 | 410 |         T_start = T_arg = VSM_Dup(vsm, "Arg", "-T"); | 
| 416 | 410 |         S_arg = VSM_Dup(vsm, "Arg", "-S"); | 
| 417 | 410 |         VSM_Destroy(&vsm); | 
| 418 |  |  | 
| 419 | 410 |         if (T_arg == NULL) { | 
| 420 | 0 |                 fprintf(stderr, "No -T in shared memory\n"); | 
| 421 | 0 |                 return (-1); | 
| 422 |  |         } | 
| 423 |  |  | 
| 424 | 410 |         sock = -1; | 
| 425 | 410 |         while (*T_arg) { | 
| 426 | 410 |                 p = strchr(T_arg, '\n'); | 
| 427 | 410 |                 AN(p); | 
| 428 | 410 |                 *p = '\0'; | 
| 429 | 410 |                 sock = cli_sock(T_arg, S_arg); | 
| 430 | 410 |                 if (sock >= 0) | 
| 431 | 410 |                         break; | 
| 432 | 0 |                 T_arg = p + 1; | 
| 433 |  |         } | 
| 434 | 410 |         free(T_start); | 
| 435 | 410 |         free(S_arg); | 
| 436 | 410 |         return (sock); | 
| 437 | 430 | } | 
| 438 |  |  | 
| 439 |  | static int | 
| 440 | 30 | t_arg_timeout(const char *t_arg) | 
| 441 |  | { | 
| 442 | 30 |         char *p = NULL; | 
| 443 |  |  | 
| 444 | 30 |         AN(t_arg); | 
| 445 | 30 |         timeout = strtod(t_arg, &p); | 
| 446 | 60 |         if ((p != NULL && *p != '\0') || | 
| 447 | 30 |             !isfinite(timeout) || timeout < 0) { | 
| 448 | 0 |                 fprintf(stderr, "-t: Invalid argument: %s", t_arg); | 
| 449 | 0 |                 return (-1); | 
| 450 |  |         } | 
| 451 | 30 |         return (1); | 
| 452 | 30 | } | 
| 453 |  |  | 
| 454 |  | #define OPTARG "hn:pS:T:t:" | 
| 455 |  |  | 
| 456 |  | int | 
| 457 | 530 | main(int argc, char * const *argv) | 
| 458 |  | { | 
| 459 | 530 |         const char *T_arg = NULL; | 
| 460 | 530 |         const char *S_arg = NULL; | 
| 461 | 530 |         const char *n_arg = NULL; | 
| 462 | 530 |         const char *t_arg = NULL; | 
| 463 |  |         int opt, sock; | 
| 464 |  |  | 
| 465 | 530 |         if (argc == 2 && !strcmp(argv[1], "--optstring")) { | 
| 466 | 0 |                 printf(OPTARG "\n"); | 
| 467 | 0 |                 exit(0); | 
| 468 |  |         } | 
| 469 |  |         /* | 
| 470 |  |          * By default linux::getopt(3) mangles the argv order, such that | 
| 471 |  |          *      varnishadm -n bla param.set foo -bar | 
| 472 |  |          * gets interpreted as | 
| 473 |  |          *      varnishadm -n bla -bar param.set foo | 
| 474 |  |          * The '+' stops that from happening | 
| 475 |  |          * See #1496 | 
| 476 |  |          */ | 
| 477 | 1170 |         while ((opt = getopt(argc, argv, "+" OPTARG)) != -1) { | 
| 478 | 670 |                 switch (opt) { | 
| 479 |  |                 case 'h': | 
| 480 |  |                         /* Usage help */ | 
| 481 | 10 |                         usage(0); | 
| 482 |  |                 case 'n': | 
| 483 | 410 |                         n_arg = optarg; | 
| 484 | 410 |                         break; | 
| 485 |  |                 case 'p': | 
| 486 | 50 |                         p_arg = 1; | 
| 487 | 50 |                         break; | 
| 488 |  |                 case 'S': | 
| 489 | 60 |                         S_arg = optarg; | 
| 490 | 60 |                         break; | 
| 491 |  |                 case 'T': | 
| 492 | 70 |                         T_arg = optarg; | 
| 493 | 70 |                         break; | 
| 494 |  |                 case 't': | 
| 495 | 50 |                         t_arg = optarg; | 
| 496 | 50 |                         break; | 
| 497 |  |                 default: | 
| 498 | 20 |                         usage(1); | 
| 499 |  |                 } | 
| 500 |  |         } | 
| 501 |  |  | 
| 502 | 500 |         argc -= optind; | 
| 503 | 500 |         argv += optind; | 
| 504 |  |  | 
| 505 | 500 |         if (T_arg != NULL) { | 
| 506 | 70 |                 if (n_arg != NULL) | 
| 507 | 0 |                         usage(1); | 
| 508 | 70 |                 sock = cli_sock(T_arg, S_arg); | 
| 509 | 70 |         } else { | 
| 510 | 430 |                 if (S_arg != NULL) | 
| 511 | 0 |                         usage(1); | 
| 512 | 430 |                 sock = n_arg_sock(n_arg, t_arg); | 
| 513 |  |         } | 
| 514 | 500 |         if (sock < 0) | 
| 515 | 80 |                 exit(2); | 
| 516 |  |  | 
| 517 | 420 |         if (t_arg != NULL && t_arg_timeout(t_arg) < 0) | 
| 518 | 0 |                 exit(2); | 
| 519 |  |  | 
| 520 | 420 |         if (argc > 0) { | 
| 521 | 360 |                 VSIG_Arm_int(); | 
| 522 | 360 |                 VSIG_Arm_term(); | 
| 523 | 360 |                 do_args(sock, argc, argv); | 
| 524 |  |                 NEEDLESS(exit(0)); | 
| 525 |  |         } | 
| 526 |  |  | 
| 527 | 60 |         if (isatty(0) && !p_arg) | 
| 528 | 10 |                 interactive(sock); | 
| 529 |  |         else | 
| 530 | 50 |                 pass(sock); | 
| 531 |  |         NEEDLESS(exit(0)); | 
| 532 |  | } |