Line data Source code
1 : /*
2 : * Copyright (c) 2015 Cisco and/or its affiliates.
3 : * Licensed under the Apache License, Version 2.0 (the "License");
4 : * you may not use this file except in compliance with the License.
5 : * You may obtain a copy of the License at:
6 : *
7 : * http://www.apache.org/licenses/LICENSE-2.0
8 : *
9 : * Unless required by applicable law or agreed to in writing, software
10 : * distributed under the License is distributed on an "AS IS" BASIS,
11 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : * See the License for the specific language governing permissions and
13 : * limitations under the License.
14 : */
15 : /*
16 : * main.c: Unix main routine
17 : *
18 : * Copyright (c) 2008 Eliot Dresselhaus
19 : *
20 : * Permission is hereby granted, free of charge, to any person obtaining
21 : * a copy of this software and associated documentation files (the
22 : * "Software"), to deal in the Software without restriction, including
23 : * without limitation the rights to use, copy, modify, merge, publish,
24 : * distribute, sublicense, and/or sell copies of the Software, and to
25 : * permit persons to whom the Software is furnished to do so, subject to
26 : * the following conditions:
27 : *
28 : * The above copyright notice and this permission notice shall be
29 : * included in all copies or substantial portions of the Software.
30 : *
31 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32 : * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33 : * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34 : * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35 : * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36 : * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37 : * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 : */
39 : #include <vlib/vlib.h>
40 : #include <vlib/unix/unix.h>
41 : #include <vlib/unix/plugin.h>
42 :
43 : #include <limits.h>
44 : #include <signal.h>
45 : #include <sys/ucontext.h>
46 : #include <syslog.h>
47 : #include <sys/types.h>
48 : #include <sys/stat.h>
49 : #include <fcntl.h>
50 : #include <sys/time.h>
51 : #include <sys/resource.h>
52 : #include <unistd.h>
53 :
54 : /** Default CLI pager limit is not configured in startup.conf */
55 : #define UNIX_CLI_DEFAULT_PAGER_LIMIT 100000
56 :
57 : /** Default CLI history depth if not configured in startup.conf */
58 : #define UNIX_CLI_DEFAULT_HISTORY 50
59 :
60 : char *vlib_default_runtime_dir __attribute__ ((weak));
61 : char *vlib_default_runtime_dir = "vlib";
62 :
63 : unix_main_t unix_main;
64 : clib_file_main_t file_main;
65 :
66 : static clib_error_t *
67 559 : unix_main_init (vlib_main_t * vm)
68 : {
69 559 : unix_main_t *um = &unix_main;
70 559 : um->vlib_main = vm;
71 559 : return 0;
72 : }
73 :
74 : /* *INDENT-OFF* */
75 1679 : VLIB_INIT_FUNCTION (unix_main_init) =
76 : {
77 : .runs_before = VLIB_INITS ("unix_input_init"),
78 : };
79 : /* *INDENT-ON* */
80 :
81 : static int
82 0 : unsetup_signal_handlers (int sig)
83 : {
84 : struct sigaction sa;
85 :
86 0 : sa.sa_handler = SIG_DFL;
87 0 : sa.sa_flags = 0;
88 0 : sigemptyset (&sa.sa_mask);
89 0 : return sigaction (sig, &sa, 0);
90 : }
91 :
92 :
93 : /* allocate this buffer from mheap when setting up the signal handler.
94 : dangerous to vec_resize it when crashing, mheap itself might have been
95 : corrupted already */
96 : static u8 *syslog_msg = 0;
97 : int vlib_last_signum = 0;
98 : uword vlib_last_faulting_address = 0;
99 :
100 : static void
101 559 : unix_signal_handler (int signum, siginfo_t * si, ucontext_t * uc)
102 : {
103 559 : uword fatal = 0;
104 :
105 : /* These come in handy when looking at core files from optimized images */
106 559 : vlib_last_signum = signum;
107 559 : vlib_last_faulting_address = (uword) si->si_addr;
108 :
109 559 : syslog_msg = format (syslog_msg, "received signal %U, PC %U",
110 : format_signal, signum, format_ucontext_pc, uc);
111 :
112 559 : if (signum == SIGSEGV)
113 0 : syslog_msg = format (syslog_msg, ", faulting address %p", si->si_addr);
114 :
115 559 : switch (signum)
116 : {
117 : /* these (caught) signals cause the application to exit */
118 559 : case SIGTERM:
119 : /*
120 : * Ignore SIGTERM if it's sent before we're ready.
121 : */
122 559 : if (unix_main.vlib_main && unix_main.vlib_main->main_loop_exit_set)
123 : {
124 559 : syslog (LOG_ERR | LOG_DAEMON, "received SIGTERM, exiting...");
125 559 : unix_main.vlib_main->main_loop_exit_now = 1;
126 : }
127 : else
128 0 : syslog (LOG_ERR | LOG_DAEMON, "IGNORE early SIGTERM...");
129 559 : break;
130 : /* fall through */
131 0 : case SIGQUIT:
132 : case SIGINT:
133 : case SIGILL:
134 : case SIGBUS:
135 : case SIGSEGV:
136 : case SIGHUP:
137 : case SIGFPE:
138 : case SIGABRT:
139 0 : fatal = 1;
140 0 : break;
141 :
142 : /* by default, print a message and continue */
143 0 : default:
144 0 : fatal = 0;
145 0 : break;
146 : }
147 :
148 : /* Null terminate. */
149 559 : vec_add1 (syslog_msg, 0);
150 :
151 559 : if (fatal)
152 : {
153 0 : syslog (LOG_ERR | LOG_DAEMON, "%s", syslog_msg);
154 :
155 : /* Address of callers: outer first, inner last. */
156 : uword callers[15];
157 0 : uword n_callers = clib_backtrace (callers, ARRAY_LEN (callers), 0);
158 : int i;
159 0 : for (i = 0; i < n_callers; i++)
160 : {
161 0 : vec_reset_length (syslog_msg);
162 :
163 0 : syslog_msg =
164 0 : format (syslog_msg, "#%-2d 0x%016lx %U%c", i, callers[i],
165 : format_clib_elf_symbol_with_address, callers[i], 0);
166 :
167 0 : syslog (LOG_ERR | LOG_DAEMON, "%s", syslog_msg);
168 : }
169 :
170 : /* have to remove SIGABRT to avoid recursive - os_exit calling abort() */
171 0 : unsetup_signal_handlers (SIGABRT);
172 :
173 : /* os_exit(1) causes core generation, skip that for SIGINT, SIGHUP */
174 0 : if (signum == SIGINT || signum == SIGHUP)
175 0 : os_exit (0);
176 : else
177 0 : os_exit (1);
178 : }
179 : else
180 559 : clib_warning ("%s", syslog_msg);
181 :
182 559 : }
183 :
184 : static clib_error_t *
185 559 : setup_signal_handlers (unix_main_t * um)
186 : {
187 : uword i;
188 : struct sigaction sa;
189 :
190 : /* give a big enough buffer for msg, most likely it can avoid vec_resize */
191 559 : vec_alloc (syslog_msg, 2048);
192 :
193 17888 : for (i = 1; i < 32; i++)
194 : {
195 17329 : clib_memset (&sa, 0, sizeof (sa));
196 17329 : sa.sa_sigaction = (void *) unix_signal_handler;
197 17329 : sa.sa_flags = SA_SIGINFO;
198 :
199 17329 : switch (i)
200 : {
201 : /* these signals take the default action */
202 3354 : case SIGKILL:
203 : case SIGCONT:
204 : case SIGSTOP:
205 : case SIGUSR1:
206 : case SIGUSR2:
207 : case SIGPROF:
208 3354 : continue;
209 :
210 : /* ignore SIGPIPE, SIGCHLD */
211 1118 : case SIGPIPE:
212 : case SIGCHLD:
213 1118 : sa.sa_sigaction = (void *) SIG_IGN;
214 1118 : break;
215 :
216 : /* catch and handle all other signals */
217 12857 : default:
218 12857 : break;
219 : }
220 :
221 13975 : if (sigaction (i, &sa, 0) < 0)
222 0 : return clib_error_return_unix (0, "sigaction %U", format_signal, i);
223 : }
224 :
225 559 : return 0;
226 : }
227 :
228 : static void
229 853 : unix_error_handler (void *arg, u8 * msg, int msg_len)
230 : {
231 853 : unix_main_t *um = arg;
232 :
233 : /* Echo to stderr when interactive or syslog is disabled. */
234 853 : if (um->flags & (UNIX_FLAG_INTERACTIVE | UNIX_FLAG_NOSYSLOG))
235 : {
236 0 : CLIB_UNUSED (int r) = write (2, msg, msg_len);
237 : }
238 : else
239 : {
240 853 : syslog (LOG_ERR | LOG_DAEMON, "%.*s", msg_len, msg);
241 : }
242 853 : }
243 :
244 : void
245 14 : vlib_unix_error_report (vlib_main_t * vm, clib_error_t * error)
246 : {
247 14 : unix_main_t *um = &unix_main;
248 :
249 14 : if (um->flags & UNIX_FLAG_INTERACTIVE || error == 0)
250 0 : return;
251 :
252 : {
253 14 : u8 *msg = error->what;
254 14 : u32 len = vec_len (msg);
255 14 : int msg_len = (len > INT_MAX) ? INT_MAX : len;
256 14 : syslog (LOG_ERR | LOG_DAEMON, "%.*s", msg_len, msg);
257 : }
258 : }
259 :
260 : static uword
261 559 : startup_config_process (vlib_main_t * vm,
262 : vlib_node_runtime_t * rt, vlib_frame_t * f)
263 : {
264 559 : unix_main_t *um = &unix_main;
265 : unformat_input_t in;
266 :
267 559 : vlib_process_suspend (vm, 2.0);
268 :
269 451 : while (um->unix_config_complete == 0)
270 0 : vlib_process_suspend (vm, 0.1);
271 :
272 451 : if (!um->startup_config_filename)
273 : {
274 451 : return 0;
275 : }
276 :
277 0 : unformat_init_vector (&in,
278 : format (0, "exec %s", um->startup_config_filename));
279 :
280 0 : vlib_cli_input (vm, &in, 0, 0);
281 :
282 0 : unformat_free (&in);
283 :
284 0 : return 0;
285 : }
286 :
287 : /* *INDENT-OFF* */
288 178120 : VLIB_REGISTER_NODE (startup_config_node,static) = {
289 : .function = startup_config_process,
290 : .type = VLIB_NODE_TYPE_PROCESS,
291 : .name = "startup-config-process",
292 : .process_log2_n_stack_bytes = 18,
293 : };
294 : /* *INDENT-ON* */
295 :
296 : static clib_error_t *
297 559 : unix_config (vlib_main_t * vm, unformat_input_t * input)
298 : {
299 559 : vlib_global_main_t *vgm = vlib_get_global_main ();
300 559 : unix_main_t *um = &unix_main;
301 559 : clib_error_t *error = 0;
302 : gid_t gid;
303 559 : int pidfd = -1;
304 :
305 : /* Defaults */
306 559 : um->cli_pager_buffer_limit = UNIX_CLI_DEFAULT_PAGER_LIMIT;
307 559 : um->cli_history_limit = UNIX_CLI_DEFAULT_HISTORY;
308 :
309 2795 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
310 : {
311 : char *cli_prompt;
312 2236 : if (unformat (input, "interactive"))
313 0 : um->flags |= UNIX_FLAG_INTERACTIVE;
314 2236 : else if (unformat (input, "nodaemon"))
315 559 : um->flags |= UNIX_FLAG_NODAEMON;
316 1677 : else if (unformat (input, "nosyslog"))
317 0 : um->flags |= UNIX_FLAG_NOSYSLOG;
318 1677 : else if (unformat (input, "nocolor"))
319 0 : um->flags |= UNIX_FLAG_NOCOLOR;
320 1677 : else if (unformat (input, "nobanner"))
321 0 : um->flags |= UNIX_FLAG_NOBANNER;
322 1677 : else if (unformat (input, "cli-prompt %s", &cli_prompt))
323 0 : vlib_unix_cli_set_prompt (cli_prompt);
324 : else
325 1677 : if (unformat (input, "cli-listen %s", &um->cli_listen_socket.config))
326 : ;
327 1677 : else if (unformat (input, "runtime-dir %s", &um->runtime_dir))
328 : ;
329 1118 : else if (unformat (input, "cli-line-mode"))
330 0 : um->cli_line_mode = 1;
331 1118 : else if (unformat (input, "cli-no-banner"))
332 0 : um->cli_no_banner = 1;
333 1118 : else if (unformat (input, "cli-no-pager"))
334 0 : um->cli_no_pager = 1;
335 1118 : else if (unformat (input, "poll-sleep-usec %d", &um->poll_sleep_usec))
336 : ;
337 1118 : else if (unformat (input, "cli-pager-buffer-limit %d",
338 : &um->cli_pager_buffer_limit))
339 : ;
340 : else
341 1118 : if (unformat (input, "cli-history-limit %d", &um->cli_history_limit))
342 : ;
343 1118 : else if (unformat (input, "coredump-size"))
344 : {
345 559 : uword coredump_size = 0;
346 559 : if (unformat (input, "unlimited"))
347 : {
348 559 : coredump_size = RLIM_INFINITY;
349 : }
350 : else
351 0 : if (!unformat (input, "%U", unformat_memory_size, &coredump_size))
352 : {
353 0 : return clib_error_return (0,
354 : "invalid coredump-size parameter `%U'",
355 : format_unformat_error, input);
356 : }
357 559 : const struct rlimit new_limit = { coredump_size, coredump_size };
358 559 : if (0 != setrlimit (RLIMIT_CORE, &new_limit))
359 : {
360 0 : clib_unix_warning ("prlimit() failed");
361 : }
362 : }
363 559 : else if (unformat (input, "full-coredump"))
364 : {
365 : int fd;
366 :
367 559 : fd = open ("/proc/self/coredump_filter", O_WRONLY);
368 559 : if (fd >= 0)
369 : {
370 559 : if (write (fd, "0x6f\n", 5) != 5)
371 0 : clib_unix_warning ("coredump filter write failed!");
372 559 : close (fd);
373 : }
374 : else
375 0 : clib_unix_warning ("couldn't open /proc/self/coredump_filter");
376 : }
377 0 : else if (unformat (input, "startup-config %s",
378 : &um->startup_config_filename))
379 : ;
380 0 : else if (unformat (input, "exec %s", &um->startup_config_filename))
381 : ;
382 0 : else if (unformat (input, "log %s", &um->log_filename))
383 : {
384 0 : um->log_fd = open ((char *) um->log_filename,
385 : O_CREAT | O_WRONLY | O_APPEND, 0644);
386 0 : if (um->log_fd < 0)
387 : {
388 0 : clib_warning ("couldn't open log '%s'\n", um->log_filename);
389 0 : um->log_fd = 0;
390 : }
391 : else
392 : {
393 0 : u8 *lv = 0;
394 0 : lv = format (0, "%U: ***** Start: PID %d *****\n",
395 : format_timeval, NULL /* current bat-format */,
396 : 0 /* current bat-time */, getpid ());
397 : {
398 0 : int rv __attribute__ ((unused)) =
399 0 : write (um->log_fd, lv, vec_len (lv));
400 : }
401 0 : vec_free (lv);
402 : }
403 : }
404 0 : else if (unformat (input, "gid %U", unformat_unix_gid, &gid))
405 : {
406 0 : if (setegid (gid) == -1)
407 0 : return clib_error_return_unix (0, "setegid");
408 : }
409 0 : else if (unformat (input, "pidfile %s", &um->pidfile))
410 : ;
411 : else
412 0 : return clib_error_return (0, "unknown input `%U'",
413 : format_unformat_error, input);
414 : }
415 :
416 559 : if (um->runtime_dir == 0)
417 : {
418 0 : uid_t uid = geteuid ();
419 0 : if (uid == 00)
420 0 : um->runtime_dir = format (0, "/run/%s%c",
421 : vlib_default_runtime_dir, 0);
422 : else
423 0 : um->runtime_dir = format (0, "/run/user/%u/%s%c", uid,
424 : vlib_default_runtime_dir, 0);
425 : }
426 :
427 : /* Ensure the runtime directory is created */
428 559 : error = vlib_unix_recursive_mkdir ((char *) um->runtime_dir);
429 559 : if (error)
430 0 : return error;
431 :
432 559 : if (chdir ((char *) um->runtime_dir) < 0)
433 0 : return clib_error_return_unix (0, "chdir('%s')", um->runtime_dir);
434 :
435 559 : error = setup_signal_handlers (um);
436 559 : if (error)
437 0 : return error;
438 :
439 559 : if (um->pidfile)
440 : {
441 0 : if ((error = vlib_unix_validate_runtime_file (um,
442 0 : (char *) um->pidfile,
443 : &um->pidfile)))
444 0 : return error;
445 :
446 0 : if (((pidfd = open ((char *) um->pidfile,
447 : O_CREAT | O_WRONLY | O_TRUNC, 0644)) < 0))
448 : {
449 0 : return clib_error_return_unix (0, "open");
450 : }
451 : }
452 :
453 559 : if (!(um->flags & (UNIX_FLAG_INTERACTIVE | UNIX_FLAG_NOSYSLOG)))
454 : {
455 559 : openlog (vgm->name, LOG_CONS | LOG_PERROR | LOG_PID, LOG_DAEMON);
456 559 : clib_error_register_handler (unix_error_handler, um);
457 :
458 559 : if (!(um->flags & UNIX_FLAG_NODAEMON) && daemon ( /* chdir to / */ 0,
459 : /* stdin/stdout/stderr -> /dev/null */
460 : 0) < 0)
461 0 : clib_error_return (0, "daemon () fails");
462 : }
463 :
464 559 : if (pidfd >= 0)
465 : {
466 0 : u8 *lv = format (0, "%d", getpid ());
467 0 : if (write (pidfd, (char *) lv, vec_len (lv)) != vec_len (lv))
468 : {
469 0 : vec_free (lv);
470 0 : close (pidfd);
471 0 : return clib_error_return_unix (0, "write");
472 : }
473 0 : vec_free (lv);
474 0 : close (pidfd);
475 : }
476 :
477 559 : um->unix_config_complete = 1;
478 :
479 559 : return 0;
480 : }
481 :
482 : /* unix { ... } configuration. */
483 : /*?
484 : *
485 : * @cfgcmd{interactive}
486 : * Attach CLI to stdin/out and provide a debugging command line interface.
487 : * Implies @c nodaemon.
488 : *
489 : * @cfgcmd{nodaemon}
490 : * Do not fork or background the VPP process. Typically used when invoking
491 : * VPP applications from a process monitor.
492 : *
493 : * @cfgcmd{nosyslog}
494 : * Do not send e.g. clib_warning(...) output to syslog. Used
495 : * when invoking VPP applications from a process monitor which
496 : * pipe stdout/stderr to a dedicated logger service.
497 : *
498 : * @cfgcmd{nocolor}
499 : * Do not use colors in outputs.
500 : * *
501 : * @cfgcmd{nobanner}
502 : * Do not display startup banner.
503 : *
504 : * @cfgcmd{exec, <filename>}
505 : * @par <code>startup-config <filename></code>
506 : * Read startup operational configuration from @c filename.
507 : * The contents of the file will be performed as though entered at the CLI.
508 : * The two keywords are aliases for the same function; if both are specified,
509 : * only the last will have an effect.
510 : *
511 : * @cfgcmd{log, <filename>}
512 : * Logs the startup configuration and all subsequent CLI commands in
513 : * @c filename.
514 : * Very useful in situations where folks don't remember or can't be bothered
515 : * to include CLI commands in bug reports.
516 : *
517 : * @cfgcmd{pidfile, <filename>}
518 : * Writes the pid of the main thread in @c filename.
519 : *
520 : * @cfgcmd{full-coredump}
521 : * Ask the Linux kernel to dump all memory-mapped address regions, instead
522 : * of just text+data+bss.
523 : *
524 : * @cfgcmd{runtime-dir}
525 : * Define directory where VPP is going to store all runtime files.
526 : * Default is /run/vpp when running as root, /run/user/<UID>/vpp if running as
527 : * an unprivileged user.
528 : *
529 : * @cfgcmd{cli-listen, <address:port>}
530 : * Bind the CLI to listen at the address and port given. @c localhost
531 : * on TCP port @c 5002, given as <tt>cli-listen localhost:5002</tt>,
532 : * is typical.
533 : *
534 : * @cfgcmd{cli-line-mode}
535 : * Disable character-by-character I/O on stdin. Useful when combined with,
536 : * for example, <tt>emacs M-x gud-gdb</tt>.
537 : *
538 : * @cfgcmd{cli-prompt, <string>}
539 : * Configure the CLI prompt to be @c string.
540 : *
541 : * @cfgcmd{cli-history-limit, <nn>}
542 : * Limit command history to @c nn lines. A value of @c 0
543 : * disables command history. Default value: @c 50
544 : *
545 : * @cfgcmd{cli-no-banner}
546 : * Disable the login banner on stdin and Telnet connections.
547 : *
548 : * @cfgcmd{cli-no-pager}
549 : * Disable the output pager.
550 : *
551 : * @cfgcmd{cli-pager-buffer-limit, <nn>}
552 : * Limit pager buffer to @c nn lines of output.
553 : * A value of @c 0 disables the pager. Default value: @c 100000
554 : *
555 : * @cfgcmd{gid, <nn>}
556 : * Set the effective gid under which the vpp process is to run.
557 : *
558 : * @cfgcmd{poll-sleep-usec, <nn>}
559 : * Set a fixed poll sleep interval between main loop polls.
560 : ?*/
561 7306 : VLIB_EARLY_CONFIG_FUNCTION (unix_config, "unix");
562 :
563 : static clib_error_t *
564 559 : unix_exit (vlib_main_t * vm)
565 : {
566 : /* Close syslog connection. */
567 559 : closelog ();
568 559 : return 0;
569 : }
570 :
571 1678 : VLIB_MAIN_LOOP_EXIT_FUNCTION (unix_exit);
572 :
573 : u8 **vlib_thread_stacks;
574 :
575 : static uword
576 559 : thread0 (uword arg)
577 : {
578 559 : vlib_main_t *vm = (vlib_main_t *) arg;
579 559 : vlib_global_main_t *vgm = vlib_get_global_main ();
580 : unformat_input_t input;
581 : int i;
582 :
583 559 : vlib_process_finish_switch_stack (vm);
584 :
585 559 : unformat_init_command_line (&input, (char **) vgm->argv);
586 559 : i = vlib_main (vm, &input);
587 559 : unformat_free (&input);
588 :
589 559 : return i;
590 : }
591 :
592 : u8 *
593 613 : vlib_thread_stack_init (uword thread_index)
594 : {
595 : void *stack;
596 613 : ASSERT (thread_index < vec_len (vlib_thread_stacks));
597 613 : stack = clib_mem_vm_map_stack (VLIB_THREAD_STACK_SIZE,
598 : CLIB_MEM_PAGE_SZ_DEFAULT,
599 : "thread stack: thread %u", thread_index);
600 :
601 613 : if (stack == CLIB_MEM_VM_MAP_FAILED)
602 0 : clib_panic ("failed to allocate thread %u stack", thread_index);
603 :
604 613 : vlib_thread_stacks[thread_index] = stack;
605 613 : return stack;
606 : }
607 :
608 : #ifndef PATH_MAX
609 : #define PATH_MAX 4096
610 : #endif
611 :
612 : int
613 559 : vlib_unix_main (int argc, char *argv[])
614 : {
615 559 : vlib_global_main_t *vgm = vlib_get_global_main ();
616 559 : vlib_main_t *vm = vlib_get_first_main (); /* one and only time for this! */
617 : unformat_input_t input;
618 : clib_error_t *e;
619 : char buffer[PATH_MAX];
620 : int i;
621 :
622 559 : vec_validate_aligned (vgm->vlib_mains, 0, CLIB_CACHE_LINE_BYTES);
623 :
624 559 : if ((i = readlink ("/proc/self/exe", buffer, sizeof (buffer) - 1)) > 0)
625 : {
626 : int j;
627 559 : buffer[i] = 0;
628 559 : vgm->exec_path = vec_new (char, i + 1);
629 559 : clib_memcpy_fast (vgm->exec_path, buffer, i + 1);
630 1677 : for (j = i - 1; j > 0; j--)
631 1677 : if (buffer[j - 1] == '/')
632 559 : break;
633 559 : vgm->name = vec_new (char, i - j + 1);
634 559 : clib_memcpy_fast (vgm->name, buffer + j, i - j + 1);
635 : }
636 : else
637 0 : vgm->exec_path = vgm->name = argv[0];
638 :
639 559 : vgm->argv = (u8 **) argv;
640 :
641 559 : clib_time_init (&vm->clib_time);
642 :
643 : /* Turn on the event logger at the first possible moment */
644 559 : vgm->configured_elog_ring_size = 128 << 10;
645 559 : elog_init (vlib_get_elog_main (), vgm->configured_elog_ring_size);
646 559 : elog_enable_disable (vlib_get_elog_main (), 1);
647 :
648 559 : unformat_init_command_line (&input, (char **) vgm->argv);
649 559 : if ((e = vlib_plugin_config (vm, &input)))
650 : {
651 0 : clib_error_report (e);
652 0 : return 1;
653 : }
654 559 : unformat_free (&input);
655 :
656 559 : i = vlib_plugin_early_init (vm);
657 559 : if (i)
658 0 : return i;
659 :
660 559 : unformat_init_command_line (&input, (char **) vgm->argv);
661 559 : if (vgm->init_functions_called == 0)
662 0 : vgm->init_functions_called = hash_create (0, /* value bytes */ 0);
663 559 : e = vlib_call_all_config_functions (vm, &input, 1 /* early */ );
664 559 : if (e != 0)
665 : {
666 0 : clib_error_report (e);
667 0 : return 1;
668 : }
669 559 : unformat_free (&input);
670 :
671 : /* always load symbols, for signal handler and mheap memory get/put backtrace */
672 559 : clib_elf_main_init (vgm->exec_path);
673 :
674 559 : vec_validate (vlib_thread_stacks, 0);
675 559 : vlib_thread_stack_init (0);
676 :
677 559 : __os_thread_index = 0;
678 559 : vm->thread_index = 0;
679 :
680 559 : vlib_process_start_switch_stack (vm, 0);
681 1118 : i = clib_calljmp (thread0, (uword) vm,
682 559 : (void *) (vlib_thread_stacks[0] +
683 : VLIB_THREAD_STACK_SIZE));
684 559 : return i;
685 : }
686 :
687 : /*
688 : * fd.io coding-style-patch-verification: ON
689 : *
690 : * Local Variables:
691 : * eval: (c-set-style "gnu")
692 : * End:
693 : */
|