summaryrefslogtreecommitdiffstats
path: root/meta-facebook/meta-wedge/recipes-wedge/bmc-log/files/bmc-log.c
diff options
context:
space:
mode:
Diffstat (limited to 'meta-facebook/meta-wedge/recipes-wedge/bmc-log/files/bmc-log.c')
-rw-r--r--meta-facebook/meta-wedge/recipes-wedge/bmc-log/files/bmc-log.c559
1 files changed, 559 insertions, 0 deletions
diff --git a/meta-facebook/meta-wedge/recipes-wedge/bmc-log/files/bmc-log.c b/meta-facebook/meta-wedge/recipes-wedge/bmc-log/files/bmc-log.c
new file mode 100644
index 0000000..078db7b
--- /dev/null
+++ b/meta-facebook/meta-wedge/recipes-wedge/bmc-log/files/bmc-log.c
@@ -0,0 +1,559 @@
+/*
+ * Copyright 2014-present Facebook. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <string.h>
+#include <linux/serial.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <time.h>
+#include <arpa/inet.h>
+#include <sys/stat.h>
+#include <pty.h>
+#include <errno.h>
+#include <signal.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include "bmc-log.h"
+
+FILE *error_file = NULL;
+
+bool kill_received = false; // To check if a killing interrupt is received
+
+speed_t baud_rate = B57600; // Default baud rate - change if user inputs a different one
+
+int fd_tty = -1, fd_soc = -1;
+
+/* Hostname and port of the server */
+char *hostname;
+int port;
+
+struct termios orig_tty_state;
+
+char *get_time()
+{
+ static char mytime[TIME_FORMAT_SIZE];
+ memset(mytime, 0, sizeof(mytime));
+ time_t this_time;
+ struct tm *this_tm;
+ this_time = time(NULL);
+ this_tm = localtime(&this_time);
+
+ snprintf(mytime, sizeof(mytime), "%04d-%02d-%02d %02d:%02d:%02d",
+ 1900 + this_tm->tm_year, this_tm->tm_mon + 1,
+ this_tm->tm_mday, this_tm->tm_hour,
+ this_tm->tm_min, this_tm->tm_sec);
+ return mytime;
+}
+
+void errlog(char *frmt, ...)
+{
+ va_list args;
+ va_start(args, frmt);
+ struct stat st;
+
+ char *time_now = get_time();
+
+ fprintf(stderr, "[%s] ", time_now);
+ vfprintf(stderr, frmt, args);
+
+ if (error_file) {
+ stat(error_log_file, &st);
+ if (st.st_size >= MAX_LOG_FILE_SIZE) {
+ truncate(error_log_file, 0);
+ }
+ fprintf(error_file, "[%s] ", time_now);
+ vfprintf(error_file, frmt, args);
+ fflush(error_file);
+ }
+}
+
+/* Get the address info of netcons server */
+struct addrinfo *get_addr_info(int ip_version)
+{
+ int ip_family = (ip_version == IPV4) ? AF_INET : AF_INET6;
+ struct addrinfo hints;
+
+ struct addrinfo *result;
+ result = malloc(sizeof(*result));
+ if (!result) {
+ errlog("Error: Unable to allocate memory - %m\n");
+ return NULL;
+ }
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = ip_family; /* Allow IPv4 or IPv6 */
+ hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */
+ hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */
+ hints.ai_protocol = 0; /* Any protocol */
+ hints.ai_canonname = NULL;
+ hints.ai_addr = NULL;
+ hints.ai_next = NULL;
+
+ if (getaddrinfo(hostname, NULL, &hints, &result)) {
+ errlog("Error: getaddrinfo failed - %m\n");
+ return NULL;
+ }
+
+ return result;
+}
+
+/* Prepare Ipv4 Socket */
+bool prepare_sock(struct sockaddr_in * tgt_addr)
+{
+ struct addrinfo *addr_info;
+ memset(tgt_addr, 0, sizeof(*tgt_addr));
+
+ if ((addr_info = get_addr_info(IPV4)) == NULL) {
+ errlog("Error: Unable to get address info\n");
+ return false;
+ }
+
+ tgt_addr->sin_addr = ((struct sockaddr_in *)addr_info->ai_addr)->sin_addr;
+ tgt_addr->sin_port = htons(port);
+ tgt_addr->sin_family = AF_INET;
+
+ return true;
+}
+
+/* Prepare Ipv6 Socket */
+bool prepare_sock6(struct sockaddr_in6 * tgt_addr6)
+{
+ struct addrinfo *addr_info;
+ memset(tgt_addr6, 0, sizeof(*tgt_addr6));
+
+ if ((addr_info = get_addr_info(IPV6)) == NULL) {
+ errlog("Erorr: Unable to get address info\n");
+ return false;
+ }
+
+ tgt_addr6->sin6_addr = ((struct sockaddr_in6 *)addr_info->ai_addr)->sin6_addr;
+ tgt_addr6->sin6_port = htons(port);
+ tgt_addr6->sin6_family = AF_INET6;
+
+ return true;
+}
+
+/* Set TTY to raw mode */
+bool set_tty(int fd)
+{
+ struct termios tty_state;
+
+ if (tcgetattr(fd, &tty_state) < 0) {
+ return false;
+ }
+
+ if (tcgetattr(fd, &orig_tty_state) < 0) // Save original settings
+ {
+ return false;
+ }
+
+ if (cfsetspeed(&tty_state, baud_rate) == -1) {
+ errlog("Error: Baud Rate not set - %m\n");
+ return false;
+ }
+
+ tty_state.c_lflag &= ~(ICANON | IEXTEN | ISIG | ECHO);
+ tty_state.c_iflag &= ~(IGNCR | ICRNL | INPCK | ISTRIP | IXON | BRKINT);
+ tty_state.c_iflag |= (IGNCR | ICRNL);
+ tty_state.c_oflag &= ~OPOST;
+ tty_state.c_cflag |= CS8;
+
+ tty_state.c_cc[VMIN] = 1;
+ tty_state.c_cc[VTIME] = 0;
+
+ if (tcsetattr(fd, TCSAFLUSH, &tty_state) < 0) {
+ return false;
+ }
+
+ return true;
+}
+
+/* Create a pseudo terminal for other process to use (as this program is using up the actual TTY) */
+int create_pseudo_tty()
+{
+ int amaster, aslave;
+ int flags;
+
+ if (openpty(&amaster, &aslave, NULL, NULL, NULL) == -1) {
+ errlog("Error: Openpty failed - %m\n");
+ return -1;
+ }
+
+ /* Set to non blocking mode */
+ flags = fcntl(amaster, F_GETFL);
+ flags |= O_NONBLOCK;
+ fcntl(amaster, F_SETFL, flags);
+
+ FILE *pseudo_save_file = fopen(pseudo_tty_save_file, "w+");
+ if (!pseudo_save_file) {
+ errlog("Error: Unable to open the pseudo info file - %m\n");
+ return -1;
+ }
+ /* Save the name of the created pseudo tty in a text file for other processes to use */
+ if (fprintf(pseudo_save_file, "%s\n", ttyname(aslave)) == -1) {
+ errlog("Error writing to the pseudo info file\n");
+ fclose(pseudo_save_file);
+ return -1;
+ }
+ fclose(pseudo_save_file);
+
+ if (set_tty(aslave) == -1) {
+ errlog("Error: Slave TTY not set properly\n");
+ return -1;
+ }
+
+ return amaster;
+}
+
+/* Prepare logs from the read_buf and send them to the server */
+bool prepare_log_send(char *read_buf, int max_read, int fd_socket)
+{
+ size_t buff_index = 0; // Index for the read_buf string
+
+ static char line[LINE_LEN] = { 0 };
+ static size_t line_index = 0; // Index for the line string
+
+ char msg[MSG_LEN] = { 0 }; // Message to be sent to the server
+
+ /* Kernel Version */
+ static char kernel_version[KERNEL_VERSION_LEN] = "dummy_kernel";
+ static int kernel_search_pos = 0;
+
+ while (buff_index < max_read && read_buf[buff_index] != '\0') {
+ if (read_buf[buff_index] == 'L') // Check if there is a possibility of new kernel version
+ {
+ kernel_search_pos = line_index;
+ }
+
+ /* Send the log when a line is read */
+ if (read_buf[buff_index] == '\n') {
+ if (kernel_search_pos > 0) {
+ if (strncmp(line + kernel_search_pos, "Linux version ", kernel_search_len) == 0) {
+ sscanf(line + kernel_search_pos + kernel_search_len, "%s", kernel_version);
+ }
+ kernel_search_pos = 0;
+ }
+
+ /* Prepare the message */
+ memset(msg, 0, sizeof(msg));
+ if (snprintf(msg, sizeof(msg), "%s %s %s %s", "kernel:", kernel_version, "- msg", line) < 0) {
+ errlog("Error copying the message - %m\n");
+ return false;
+ }
+
+ /* Send message to the server */
+ if (write(fd_socket, msg, strlen(msg)) < 0) {
+ errlog("Error: Write to socket failed - %m\n");
+ return false;
+ }
+
+ /* Reset the line buffer */
+ line_index = 0;
+ memset(line, 0, sizeof(line));
+
+ buff_index++;
+ continue;
+ }
+
+ /* If line is too big, send only the first few bytes and discard others. */
+ if (line_index >= sizeof(line)) {
+ line[line_index - 1] = 0;
+ buff_index++;
+ continue;
+ }
+
+ line[line_index++] = read_buf[buff_index++];
+ }
+
+ return true;
+}
+
+/* Read text from the TTY and send to send as logs */
+bool read_send(int fd_tty, int fd_socket)
+{
+ char read_buf[LINE_LEN] = { 0 }; // Buffer to be read into.
+ int read_size = 0;
+ fd_set readset;
+ int sel;
+ int fdmax;
+
+ int pseudo_tty = create_pseudo_tty();
+
+ if (pseudo_tty == -1) {
+ errlog("Error: Cannot create a psuedo terminal\n");
+ return false;
+ }
+
+ fdmax = MAX(fd_tty, pseudo_tty);
+
+ while (!kill_received) {
+ do {
+ FD_ZERO(&readset);
+ FD_SET(fd_tty, &readset);
+ FD_SET(pseudo_tty, &readset);
+
+ sel = select(fdmax + 1, &readset, NULL, NULL, NULL);
+ }
+ while (sel == -1 && errno == EINTR && !kill_received);
+
+ memset(read_buf, 0, sizeof(read_buf));
+ if (FD_ISSET(fd_tty, &readset)) {
+ read_size = read(fd_tty, read_buf, sizeof(read_buf) - 1);
+
+ if (read_size == 0) {
+ continue;
+ }
+ if (read_size < 0) {
+ if (errno == EAGAIN) {
+ continue;
+ }
+ errlog("Error: Read from tty failed - %m\n");
+ return false;
+ }
+
+ /* Send the read data to the pseudo terminal */
+ if (write(pseudo_tty, read_buf, read_size) < 0) {
+ if (errno == EAGAIN) // Output buffer full - flush it.
+ {
+ tcflush(pseudo_tty, TCIOFLUSH);
+ continue;
+ }
+
+ errlog("Error: Write to pseudo tty failed - %m\n");
+ return false;
+ }
+
+ /* Prepare log message and send to the server */
+ if (!prepare_log_send(read_buf, sizeof(read_buf), fd_socket)) {
+ errlog("Error: Sending log failed - %m\n");
+ return false;
+ }
+ }
+ /*if (FD_ISSET(fd_tty, &readset)) */
+ if (kill_received) {
+ break;
+ }
+
+ /* Check if there is an data in the pseudo terminal's buffer */
+ if (FD_ISSET(pseudo_tty, &readset)) {
+ read_size = read(pseudo_tty, read_buf, sizeof(read_buf) - 1);
+
+ if (read_size == 0) {
+ continue;
+ }
+ if (read_size < 0) {
+ if (errno == EAGAIN) {
+ continue;
+ }
+ errlog("Error: Read from pseudo tty failed - %m\n");
+ return false;
+ }
+
+ if (write(fd_tty, read_buf, read_size) < 0) {
+ if (errno == EAGAIN) // Output buffer full - flush it.
+ {
+ tcflush(fd_tty, TCIOFLUSH);
+ continue;
+ }
+
+ errlog("Error: Write to tty failed - %m\n");
+ return false;
+ }
+ } /*if (FD_ISSET(pseudo_tty,&readset)) */
+ } /*while (!kill_received) */
+
+ return true;
+}
+
+void cleanup()
+{
+ remove(pseudo_tty_save_file);
+ tcsetattr(fd_tty, TCSAFLUSH, &orig_tty_state); //Restore original settings
+ close(fd_tty);
+ close(fd_soc);
+ fclose(error_file);
+}
+
+void sig_kill(int signum)
+{
+ kill_received = true;
+}
+
+void register_kill()
+{
+ struct sigaction sigact;
+ sigset_t sigset;
+
+ sigemptyset(&sigset);
+ memset(&sigact, 0, sizeof sigact);
+ sigact.sa_handler = sig_kill;
+ sigact.sa_mask = sigset;
+
+ sigaction(SIGHUP, &sigact, NULL);
+ sigaction(SIGINT, &sigact, NULL);
+ sigaction(SIGQUIT, &sigact, NULL);
+ sigaction(SIGPIPE, &sigact, NULL);
+ sigaction(SIGTERM, &sigact, NULL);
+ sigaction(SIGKILL, &sigact, NULL);
+ sigaction(SIGABRT, &sigact, NULL);
+}
+
+void usage(char *prog_name)
+{
+ printf("Usage:\n");
+ printf("\t%s TTY ip_version(4 or 6) hostname port [baud rate (like 57600)]\n", prog_name);
+ printf("\t%s -h : For this help\n", prog_name);
+ printf("Example:\n\t./bmc-log /dev/ttyS1 4 netcons.any.facebook.com 1514\n");
+ printf("\tOR\n\t./bmc-log /dev/ttyS1 6 netcons6.any.facebook.com 1514 57600\n");
+}
+
+bool parse_user_input(int nargs, char **args, char *read_tty, int read_tty_size, int *ip_version)
+{
+ if (nargs < 5) {
+ if ((nargs > 1) && ((strcmp(args[1], "-h") == 0) || (strcmp(args[1], "--help") == 0))) {
+ usage(args[0]);
+ return false; // Not an error but returning -1 for the main function to return
+ }
+ fprintf(stderr, "Error: Invalid number of arguments\n");
+ usage(args[0]);
+ return false;
+ }
+
+ if (strlen(args[1]) > read_tty_size) {
+ fprintf(stderr, "Error: TTY too long\n");
+ usage(args[0]);
+ return false;
+ }
+
+ /* TTT to read the logs from */
+ strncpy(read_tty, args[1], read_tty_size);
+
+ /* IP Version, IP Address and Port of the netcons server */
+ *ip_version = atoi(args[2]);
+ if (*ip_version != IPV4 && *ip_version != IPV6) {
+ fprintf(stderr, "Error: Invalid IP Version input\n");
+ usage(args[0]);
+ return false;
+ }
+
+ hostname = args[3];
+ port = atoi(args[4]);
+
+ baud_rate = B57600;
+ if (nargs == 6)
+ baud_rate = atoi(args[5]);
+
+ return true;
+}
+
+int main(int argc, char **argv)
+{
+ char read_tty[TTY_LEN] = { 0 };
+ int ip_version;
+ int socket_domain = AF_UNSPEC;
+ char cmd[COMMAND_LEN] = { 0 };
+
+ /* Open the error log file */
+ error_file = fopen(error_log_file, "a+");
+ if (!error_file) {
+ printf("Error: Unable to open log file - %m\n");
+ return 1;
+ }
+
+ /* Register actions upon interrupts */
+ register_kill();
+
+ /* Parse the user input */
+ if (!parse_user_input(argc, argv, read_tty, sizeof(read_tty), &ip_version)) {
+ return 2;
+ }
+
+ snprintf(cmd, sizeof(cmd), "%s %s", uS_console, "connect");
+ if (system(cmd) == -1) {
+ errlog("Error: Unable to connect to the micro-server\n");
+ return 3;
+ }
+
+ /* Create a socket to communicate with the netcons server */
+ socket_domain = (ip_version == IPV4) ? AF_INET : AF_INET6;
+ fd_soc = socket(socket_domain, SOCK_DGRAM, 0);
+ if (fd_soc == -1) {
+ errlog("Error: Socket creation failed - %m\n");
+ return 4;
+ }
+
+ if (ip_version == IPV4) { /* IPv4 */
+ struct sockaddr_in tgt_addr;
+ if (!prepare_sock(&tgt_addr)) {
+ close(fd_soc);
+ errlog("Error: Socket not valid\n");
+ return 5;
+ }
+
+ if (connect(fd_soc, (struct sockaddr *)&tgt_addr, sizeof(tgt_addr)) == -1) {
+ close(fd_soc);
+ errlog("Error: Socket connection failed - %m\n");
+ return 6;
+ }
+
+ } else { /* IPv6 */
+
+ struct sockaddr_in6 tgt_addr6;
+ if (!prepare_sock6(&tgt_addr6)) {
+ close(fd_soc);
+ errlog("Error: Socket not valid\n");
+ return 5;
+ }
+
+ if (connect(fd_soc, (struct sockaddr *)&tgt_addr6, sizeof(tgt_addr6)) == -1) {
+ close(fd_soc);
+ errlog("Error: Socket connection failed - %m\n");
+ return 6;
+ }
+ }
+
+ /* TTY Operations */
+ if ((fd_tty = open(read_tty, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK)) == -1) {
+ close(fd_soc);
+ errlog("Error: Serial Port %s open failed - %m\n", read_tty);
+ return 7;
+ }
+
+ if (!set_tty(fd_tty)) {
+ errlog("Error: tty not set properly\n");
+ cleanup();
+ return 8;
+ }
+
+ /* Read, prepare and send the logs */
+ if (!read_send(fd_tty, fd_soc)) {
+ errlog("Error: Sending logs failed\n");
+ cleanup();
+ return 9;
+ }
+
+ cleanup();
+ return 0;
+}
OpenPOWER on IntegriCloud