clib_error_t * clib_file_read_contents (char *file, u8 * result, uword n_bytes) { int fd = -1; uword n_done, n_left; clib_error_t *error = 0; u8 *v = result; if ((fd = open (file, 0)) < 0) return clib_error_return_unix (0, "open `%s'", file); n_left = n_bytes; n_done = 0; while (n_left > 0) { int n_read; if ((n_read = read (fd, v + n_done, n_left)) < 0) { error = clib_error_return_unix (0, "open `%s'", file); goto done; } /* End of file. */ if (n_read == 0) break; n_left -= n_read; n_done += n_read; } if (n_left > 0) { error = clib_error_return (0, " `%s' expected to read %wd bytes; read only %wd", file, n_bytes, n_bytes - n_left); goto done; } done: close (fd); return error; }
clib_error_t * foreach_directory_file (char *dir_name, clib_error_t * (*f) (void *arg, u8 * path_name, u8 * file_name), void *arg, int scan_dirs) { DIR *d; struct dirent *e; clib_error_t *error = 0; u8 *s, *t; d = opendir (dir_name); if (!d) { if (errno == ENOENT) return 0; return clib_error_return_unix (0, "open `%s'", dir_name); } s = t = 0; while (1) { e = readdir (d); if (!e) break; if (scan_dirs) { if (e->d_type == DT_DIR && (!strcmp (e->d_name, ".") || !strcmp (e->d_name, ".."))) continue; } else { if (e->d_type == DT_DIR) continue; } s = format (s, "%s/%s", dir_name, e->d_name); t = format (t, "%s", e->d_name); error = f (arg, s, t); _vec_len (s) = 0; _vec_len (t) = 0; if (error) break; } vec_free (s); closedir (d); return error; }
clib_error_t * vlib_sysfs_read (char *file_name, char *fmt, ...) { unformat_input_t input; u8 *s = 0; int fd; ssize_t sz; uword result; fd = open (file_name, O_RDONLY); if (fd < 0) return clib_error_return_unix (0, "open `%s'", file_name); vec_validate (s, 4095); sz = read (fd, s, vec_len (s)); if (sz < 0) { close (fd); vec_free (s); return clib_error_return_unix (0, "read `%s'", file_name); } _vec_len (s) = sz; unformat_init_vector (&input, s); va_list va; va_start (va, fmt); result = va_unformat (&input, fmt, &va); va_end (va); vec_free (s); close (fd); if (result == 0) return clib_error_return (0, "unformat error"); return 0; }
clib_error_t * vlib_sysfs_write (char *file_name, char *fmt, ...) { u8 *s; int fd; fd = open (file_name, O_WRONLY); if (fd < 0) return clib_error_return_unix (0, "open `%s'", file_name); va_list va; va_start (va, fmt); s = va_format (0, fmt, &va); va_end (va); if (write (fd, s, vec_len (s)) < 0) return clib_error_return_unix (0, "write `%s'", file_name); vec_free (s); close (fd); return 0; }
clib_error_t * unix_proc_file_contents (char *file, u8 ** result) { u8 *rv = 0; uword pos; int bytes, fd; /* Unfortunately, stat(/proc/XXX) returns zero... */ fd = open (file, O_RDONLY); if (fd < 0) return clib_error_return_unix (0, "open `%s'", file); vec_validate (rv, 4095); pos = 0; while (1) { bytes = read (fd, rv + pos, 4096); if (bytes < 0) { close (fd); vec_free (rv); return clib_error_return_unix (0, "read '%s'", file); } if (bytes == 0) { _vec_len (rv) = pos; break; } pos += bytes; vec_validate (rv, pos + 4095); } *result = rv; close (fd); return 0; }
clib_error_t * clib_file_n_bytes (char *file, uword * result) { struct stat s; if (stat (file, &s) < 0) return clib_error_return_unix (0, "stat `%s'", file); if (S_ISREG (s.st_mode)) *result = s.st_size; else *result = 0; return /* no error */ 0; }
static clib_error_t * catchup_socket_read_ready (unix_file_t * uf, int is_server) { unix_main_t * um = &unix_main; mc_socket_main_t *msm = (mc_socket_main_t *)uf->private_data; mc_main_t *mcm = &msm->mc_main; mc_socket_catchup_t * c = find_catchup_from_file_descriptor (msm, uf->file_descriptor); word l, n, is_eof; l = vec_len (c->input_vector); vec_resize (c->input_vector, 4096); n = read (uf->file_descriptor, c->input_vector + l, vec_len (c->input_vector) - l); is_eof = n == 0; if (n < 0) { if (errno == EAGAIN) n = 0; else { catchup_cleanup (msm, c, um, uf); return clib_error_return_unix (0, "read"); } } _vec_len (c->input_vector) = l + n; if (is_eof && vec_len (c->input_vector) > 0) { if (is_server) { mc_msg_catchup_request_handler (mcm, (void *) c->input_vector, c - msm->catchups); _vec_len (c->input_vector) = 0; } else { mc_msg_catchup_reply_handler (mcm, (void *) c->input_vector, c - msm->catchups); c->input_vector = 0; /* reply handler is responsible for freeing vector */ catchup_cleanup (msm, c, um, uf); } } return 0 /* no error */; }
static clib_error_t * setup_signal_handlers (unix_main_t * um) { uword i; struct sigaction sa; /* give a big enough buffer for msg, most likely it can avoid vec_resize */ vec_alloc (syslog_msg, 2048); for (i = 1; i < 32; i++) { clib_memset (&sa, 0, sizeof (sa)); sa.sa_sigaction = (void *) unix_signal_handler; sa.sa_flags = SA_SIGINFO; switch (i) { /* these signals take the default action */ case SIGKILL: case SIGSTOP: case SIGUSR1: case SIGUSR2: continue; /* ignore SIGPIPE, SIGCHLD */ case SIGPIPE: case SIGCHLD: sa.sa_sigaction = (void *) SIG_IGN; break; /* catch and handle all other signals */ default: break; } if (sigaction (i, &sa, 0) < 0) return clib_error_return_unix (0, "sigaction %U", format_signal, i); } return 0; }
static clib_error_t * unix_config (vlib_main_t * vm, unformat_input_t * input) { unix_main_t *um = &unix_main; clib_error_t *error = 0; gid_t gid; int pidfd = -1; /* Defaults */ um->cli_pager_buffer_limit = UNIX_CLI_DEFAULT_PAGER_LIMIT; um->cli_history_limit = UNIX_CLI_DEFAULT_HISTORY; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { char *cli_prompt; if (unformat (input, "interactive")) um->flags |= UNIX_FLAG_INTERACTIVE; else if (unformat (input, "nodaemon")) um->flags |= UNIX_FLAG_NODAEMON; else if (unformat (input, "cli-prompt %s", &cli_prompt)) vlib_unix_cli_set_prompt (cli_prompt); else if (unformat (input, "cli-listen %s", &um->cli_listen_socket.config)) ; else if (unformat (input, "runtime-dir %s", &um->runtime_dir)) ; else if (unformat (input, "cli-line-mode")) um->cli_line_mode = 1; else if (unformat (input, "cli-no-banner")) um->cli_no_banner = 1; else if (unformat (input, "cli-no-pager")) um->cli_no_pager = 1; else if (unformat (input, "poll-sleep-usec %d", &um->poll_sleep_usec)) ; else if (unformat (input, "cli-pager-buffer-limit %d", &um->cli_pager_buffer_limit)) ; else if (unformat (input, "cli-history-limit %d", &um->cli_history_limit)) ; else if (unformat (input, "coredump-size")) { uword coredump_size = 0; if (unformat (input, "unlimited")) { coredump_size = RLIM_INFINITY; } else if (!unformat (input, "%U", unformat_memory_size, &coredump_size)) { return clib_error_return (0, "invalid coredump-size parameter `%U'", format_unformat_error, input); } const struct rlimit new_limit = { coredump_size, coredump_size }; if (0 != setrlimit (RLIMIT_CORE, &new_limit)) { clib_unix_warning ("prlimit() failed"); } } else if (unformat (input, "full-coredump")) { int fd; fd = open ("/proc/self/coredump_filter", O_WRONLY); if (fd >= 0) { if (write (fd, "0x6f\n", 5) != 5) clib_unix_warning ("coredump filter write failed!"); close (fd); } else clib_unix_warning ("couldn't open /proc/self/coredump_filter"); } else if (unformat (input, "startup-config %s", &um->startup_config_filename)) ; else if (unformat (input, "exec %s", &um->startup_config_filename)) ; else if (unformat (input, "log %s", &um->log_filename)) { um->log_fd = open ((char *) um->log_filename, O_CREAT | O_WRONLY | O_APPEND, 0644); if (um->log_fd < 0) { clib_warning ("couldn't open log '%s'\n", um->log_filename); um->log_fd = 0; } else { u8 *lv = 0; lv = format (0, "%U: ***** Start: PID %d *****\n", format_timeval, 0 /* current bat-time */ , 0 /* current bat-format */ , getpid ()); { int rv __attribute__ ((unused)) = write (um->log_fd, lv, vec_len (lv)); } vec_free (lv); } } else if (unformat (input, "gid %U", unformat_unix_gid, &gid)) { if (setegid (gid) == -1) return clib_error_return_unix (0, "setegid"); } else if (unformat (input, "pidfile %s", &um->pidfile)) ; else return clib_error_return (0, "unknown input `%U'", format_unformat_error, input); } if (um->runtime_dir == 0) { uid_t uid = geteuid (); if (uid == 00) um->runtime_dir = format (0, "/run/%s%c", vlib_default_runtime_dir, 0); else um->runtime_dir = format (0, "/run/user/%u/%s%c", uid, vlib_default_runtime_dir, 0); } error = setup_signal_handlers (um); if (error) return error; if (um->pidfile) { if ((error = vlib_unix_validate_runtime_file (um, (char *) um->pidfile, &um->pidfile))) return error; if (((pidfd = open ((char *) um->pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644)) < 0)) { return clib_error_return_unix (0, "open"); } } if (!(um->flags & UNIX_FLAG_INTERACTIVE)) { openlog (vm->name, LOG_CONS | LOG_PERROR | LOG_PID, LOG_DAEMON); clib_error_register_handler (unix_error_handler, um); if (!(um->flags & UNIX_FLAG_NODAEMON) && daemon ( /* chdir to / */ 0, /* stdin/stdout/stderr -> /dev/null */ 0) < 0) clib_error_return (0, "daemon () fails"); } if (pidfd >= 0) { u8 *lv = format (0, "%d", getpid ()); if (write (pidfd, (char *) lv, vec_len (lv)) != vec_len (lv)) { vec_free (lv); close (pidfd); return clib_error_return_unix (0, "write"); } vec_free (lv); close (pidfd); } um->unix_config_complete = 1; return 0; }
clib_error_t * pcap_write (pcap_main_t * pm) { clib_error_t * error = 0; if (! (pm->flags & PCAP_MAIN_INIT_DONE)) { pcap_file_header_t fh; int n; if (! pm->file_name) pm->file_name = "/tmp/vnet.pcap"; pm->file_descriptor = open (pm->file_name, O_CREAT | O_TRUNC | O_WRONLY, 0664); if (pm->file_descriptor < 0) { error = clib_error_return_unix (0, "failed to open `%s'", pm->file_name); goto done; } pm->flags |= PCAP_MAIN_INIT_DONE; pm->n_packets_captured = 0; pm->n_pcap_data_written = 0; /* Write file header. */ memset (&fh, 0, sizeof (fh)); fh.magic = 0xa1b2c3d4; fh.major_version = 2; fh.minor_version = 4; fh.time_zone = 0; fh.max_packet_size_in_bytes = 1 << 16; fh.packet_type = pm->packet_type; n = write (pm->file_descriptor, &fh, sizeof (fh)); if (n != sizeof (fh)) { if (n < 0) error = clib_error_return_unix (0, "write file header `%s'", pm->file_name); else error = clib_error_return (0, "short write of file header `%s'", pm->file_name); goto done; } } do { int n = vec_len (pm->pcap_data) - pm->n_pcap_data_written; if (n > 0) { n = write (pm->file_descriptor, vec_elt_at_index (pm->pcap_data, pm->n_pcap_data_written), n); if (n < 0 && unix_error_is_fatal (errno)) { error = clib_error_return_unix (0, "write `%s'", pm->file_name); goto done; } } pm->n_pcap_data_written += n; if (pm->n_pcap_data_written >= vec_len (pm->pcap_data)) { vec_reset_length (pm->pcap_data); break; } } while (pm->n_packets_captured >= pm->n_packets_to_capture); if (pm->n_packets_captured >= pm->n_packets_to_capture) { close (pm->file_descriptor); pm->flags &= ~PCAP_MAIN_INIT_DONE; pm->file_descriptor = -1; } done: if (error) { if (pm->file_descriptor >= 0) close (pm->file_descriptor); } return error; }
clib_error_t * pcap_read (pcap_main_t * pm) { clib_error_t * error = 0; int fd, need_swap, n; pcap_file_header_t fh; pcap_packet_header_t ph; fd = open (pm->file_name, O_RDONLY); if (fd < 0) { error = clib_error_return_unix (0, "open `%s'", pm->file_name); goto done; } if (read (fd, &fh, sizeof (fh)) != sizeof (fh)) { error = clib_error_return_unix (0, "read file header `%s'", pm->file_name); goto done; } need_swap = 0; if (fh.magic == 0xd4c3b2a1) { need_swap = 1; #define _(t,f) fh.f = clib_byte_swap_##t (fh.f); foreach_pcap_file_header; #undef _ } if (fh.magic != 0xa1b2c3d4) { error = clib_error_return (0, "bad magic `%s'", pm->file_name); goto done; } pm->min_packet_bytes = 0; pm->max_packet_bytes = 0; while ((n = read (fd, &ph, sizeof (ph))) != 0) { u8 * data; if (need_swap) { #define _(t,f) ph.f = clib_byte_swap_##t (ph.f); foreach_pcap_packet_header; #undef _ } data = vec_new (u8, ph.n_bytes_in_packet); if (read (fd, data, ph.n_packet_bytes_stored_in_file) != ph.n_packet_bytes_stored_in_file) { error = clib_error_return (0, "short read `%s'", pm->file_name); goto done; } if (vec_len (pm->packets_read) == 0) pm->min_packet_bytes = pm->max_packet_bytes = ph.n_bytes_in_packet; else { pm->min_packet_bytes = clib_min (pm->min_packet_bytes, ph.n_bytes_in_packet); pm->max_packet_bytes = clib_max (pm->max_packet_bytes, ph.n_bytes_in_packet); } vec_add1 (pm->packets_read, data); } done: if (fd >= 0) close (fd); return error; }
static clib_error_t * catchup_socket_write_ready (unix_file_t * uf, int is_server) { unix_main_t * um = &unix_main; mc_socket_main_t *msm = (mc_socket_main_t *)uf->private_data; mc_socket_catchup_t *c = find_catchup_from_file_descriptor (msm, uf->file_descriptor); clib_error_t * error = 0; int n; if (c->connect_in_progress) { u32 len, value; c->connect_in_progress = 0; len = sizeof (value); if (getsockopt (c->socket, SOL_SOCKET, SO_ERROR, &value, &len) < 0) { error = clib_error_return_unix (0, "getsockopt SO_ERROR"); goto error_quit; } if (value != 0) { error = clib_error_return_code (0, value, CLIB_ERROR_ERRNO_VALID, "connect fails"); goto error_quit; } } while (1) { u32 n_this_write; n_this_write = clib_min (vec_len (c->output_vector) - c->output_vector_n_written, msm->rx_mtu_n_bytes - 64 /* ip + tcp + option allowance */); if (n_this_write <= 0) break; do { n = write (uf->file_descriptor, c->output_vector + c->output_vector_n_written, n_this_write); } while (n < 0 && errno == EAGAIN); if (n < 0) { error = clib_error_return_unix (0, "write"); goto error_quit; } c->output_vector_n_written += n; } if (c->output_vector_n_written >= vec_len (c->output_vector)) { if (! is_server) { uf->flags &= ~UNIX_FILE_DATA_AVAILABLE_TO_WRITE; unix_main.file_update (uf, UNIX_FILE_UPDATE_MODIFY); /* Send EOF to other side. */ shutdown (uf->file_descriptor, SHUT_WR); return error; } else { error_quit: catchup_cleanup (msm, c, um, uf); } } return error; }
static clib_error_t * recvmsg_helper (mc_socket_main_t * msm, int socket, struct sockaddr_in * rx_addr, u32 * buffer_index, u32 drop_message) { vlib_main_t * vm = msm->mc_main.vlib_main; vlib_buffer_t * b; uword n_left, n_alloc, n_mtu, i, i_rx; const uword buffer_size = VLIB_BUFFER_DEFAULT_FREE_LIST_BYTES; word n_bytes_left; /* Make sure we have at least a MTU worth of buffers. */ n_mtu = msm->rx_mtu_n_buffers; n_left = vec_len (msm->rx_buffers); if (n_left < n_mtu) { uword max_alloc = 8 * n_mtu; vec_validate (msm->rx_buffers, max_alloc - 1); n_alloc = vlib_buffer_alloc (vm, msm->rx_buffers + n_left, max_alloc - n_left); _vec_len (msm->rx_buffers) = n_left + n_alloc; } ASSERT (vec_len (msm->rx_buffers) >= n_mtu); vec_validate (msm->iovecs, n_mtu - 1); /* Allocate RX buffers from end of rx_buffers. Turn them into iovecs to pass to readv. */ i_rx = vec_len (msm->rx_buffers) - 1; for (i = 0; i < n_mtu; i++) { b = vlib_get_buffer (vm, msm->rx_buffers[i_rx - i]); msm->iovecs[i].iov_base = b->data; msm->iovecs[i].iov_len = buffer_size; } _vec_len (msm->iovecs) = n_mtu; { struct msghdr h; memset (&h, 0, sizeof (h)); if (rx_addr) { h.msg_name = rx_addr; h.msg_namelen = sizeof (rx_addr[0]); } h.msg_iov = msm->iovecs; h.msg_iovlen = vec_len (msm->iovecs); n_bytes_left = recvmsg (socket, &h, 0); if (n_bytes_left < 0) return clib_error_return_unix (0, "recvmsg"); } if (drop_message) { *buffer_index = ~0; return 0; } *buffer_index = msm->rx_buffers[i_rx]; while (1) { b = vlib_get_buffer (vm, msm->rx_buffers[i_rx]); b->flags = 0; b->current_data = 0; b->current_length = n_bytes_left < buffer_size ? n_bytes_left : buffer_size; n_bytes_left -= buffer_size; if (n_bytes_left <= 0) break; i_rx--; b->flags |= VLIB_BUFFER_NEXT_PRESENT; b->next_buffer = msm->rx_buffers[i_rx]; } _vec_len (msm->rx_buffers) = i_rx; return 0 /* no error */; }