18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) 48c2ecf20Sopenharmony_ci * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <errno.h> 88c2ecf20Sopenharmony_ci#include <string.h> 98c2ecf20Sopenharmony_ci#include <unistd.h> 108c2ecf20Sopenharmony_ci#include <sys/socket.h> 118c2ecf20Sopenharmony_ci#include <sys/uio.h> 128c2ecf20Sopenharmony_ci#include <sys/un.h> 138c2ecf20Sopenharmony_ci#include "mconsole.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cistatic struct mconsole_command commands[] = { 168c2ecf20Sopenharmony_ci /* 178c2ecf20Sopenharmony_ci * With uts namespaces, uts information becomes process-specific, so 188c2ecf20Sopenharmony_ci * we need a process context. If we try handling this in interrupt 198c2ecf20Sopenharmony_ci * context, we may hit an exiting process without a valid uts 208c2ecf20Sopenharmony_ci * namespace. 218c2ecf20Sopenharmony_ci */ 228c2ecf20Sopenharmony_ci { "version", mconsole_version, MCONSOLE_PROC }, 238c2ecf20Sopenharmony_ci { "halt", mconsole_halt, MCONSOLE_PROC }, 248c2ecf20Sopenharmony_ci { "reboot", mconsole_reboot, MCONSOLE_PROC }, 258c2ecf20Sopenharmony_ci { "config", mconsole_config, MCONSOLE_PROC }, 268c2ecf20Sopenharmony_ci { "remove", mconsole_remove, MCONSOLE_PROC }, 278c2ecf20Sopenharmony_ci { "sysrq", mconsole_sysrq, MCONSOLE_INTR }, 288c2ecf20Sopenharmony_ci { "help", mconsole_help, MCONSOLE_INTR }, 298c2ecf20Sopenharmony_ci { "cad", mconsole_cad, MCONSOLE_INTR }, 308c2ecf20Sopenharmony_ci { "stop", mconsole_stop, MCONSOLE_PROC }, 318c2ecf20Sopenharmony_ci { "go", mconsole_go, MCONSOLE_INTR }, 328c2ecf20Sopenharmony_ci { "log", mconsole_log, MCONSOLE_INTR }, 338c2ecf20Sopenharmony_ci { "proc", mconsole_proc, MCONSOLE_PROC }, 348c2ecf20Sopenharmony_ci { "stack", mconsole_stack, MCONSOLE_INTR }, 358c2ecf20Sopenharmony_ci}; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci/* Initialized in mconsole_init, which is an initcall */ 388c2ecf20Sopenharmony_cichar mconsole_socket_name[256]; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic int mconsole_reply_v0(struct mc_request *req, char *reply) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci struct iovec iov; 438c2ecf20Sopenharmony_ci struct msghdr msg; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci iov.iov_base = reply; 468c2ecf20Sopenharmony_ci iov.iov_len = strlen(reply); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci msg.msg_name = &(req->origin); 498c2ecf20Sopenharmony_ci msg.msg_namelen = req->originlen; 508c2ecf20Sopenharmony_ci msg.msg_iov = &iov; 518c2ecf20Sopenharmony_ci msg.msg_iovlen = 1; 528c2ecf20Sopenharmony_ci msg.msg_control = NULL; 538c2ecf20Sopenharmony_ci msg.msg_controllen = 0; 548c2ecf20Sopenharmony_ci msg.msg_flags = 0; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci return sendmsg(req->originating_fd, &msg, 0); 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic struct mconsole_command *mconsole_parse(struct mc_request *req) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci struct mconsole_command *cmd; 628c2ecf20Sopenharmony_ci int i; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(commands); i++) { 658c2ecf20Sopenharmony_ci cmd = &commands[i]; 668c2ecf20Sopenharmony_ci if (!strncmp(req->request.data, cmd->command, 678c2ecf20Sopenharmony_ci strlen(cmd->command))) { 688c2ecf20Sopenharmony_ci return cmd; 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci return NULL; 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci#define MIN(a,b) ((a)<(b) ? (a):(b)) 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci#define STRINGX(x) #x 778c2ecf20Sopenharmony_ci#define STRING(x) STRINGX(x) 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ciint mconsole_get_request(int fd, struct mc_request *req) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci int len; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci req->originlen = sizeof(req->origin); 848c2ecf20Sopenharmony_ci req->len = recvfrom(fd, &req->request, sizeof(req->request), 0, 858c2ecf20Sopenharmony_ci (struct sockaddr *) req->origin, &req->originlen); 868c2ecf20Sopenharmony_ci if (req->len < 0) 878c2ecf20Sopenharmony_ci return 0; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci req->originating_fd = fd; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci if (req->request.magic != MCONSOLE_MAGIC) { 928c2ecf20Sopenharmony_ci /* Unversioned request */ 938c2ecf20Sopenharmony_ci len = MIN(sizeof(req->request.data) - 1, 948c2ecf20Sopenharmony_ci strlen((char *) &req->request)); 958c2ecf20Sopenharmony_ci memmove(req->request.data, &req->request, len); 968c2ecf20Sopenharmony_ci req->request.data[len] = '\0'; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci req->request.magic = MCONSOLE_MAGIC; 998c2ecf20Sopenharmony_ci req->request.version = 0; 1008c2ecf20Sopenharmony_ci req->request.len = len; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci mconsole_reply_v0(req, "ERR Version 0 mconsole clients are " 1038c2ecf20Sopenharmony_ci "not supported by this driver"); 1048c2ecf20Sopenharmony_ci return 0; 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci if (req->request.len >= MCONSOLE_MAX_DATA) { 1088c2ecf20Sopenharmony_ci mconsole_reply(req, "Request too large", 1, 0); 1098c2ecf20Sopenharmony_ci return 0; 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci if (req->request.version != MCONSOLE_VERSION) { 1128c2ecf20Sopenharmony_ci mconsole_reply(req, "This driver only supports version " 1138c2ecf20Sopenharmony_ci STRING(MCONSOLE_VERSION) " clients", 1, 0); 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci req->request.data[req->request.len] = '\0'; 1178c2ecf20Sopenharmony_ci req->cmd = mconsole_parse(req); 1188c2ecf20Sopenharmony_ci if (req->cmd == NULL) { 1198c2ecf20Sopenharmony_ci mconsole_reply(req, "Unknown command", 1, 0); 1208c2ecf20Sopenharmony_ci return 0; 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci return 1; 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ciint mconsole_reply_len(struct mc_request *req, const char *str, int total, 1278c2ecf20Sopenharmony_ci int err, int more) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci /* 1308c2ecf20Sopenharmony_ci * XXX This is a stack consumption problem. It'd be nice to 1318c2ecf20Sopenharmony_ci * make it global and serialize access to it, but there are a 1328c2ecf20Sopenharmony_ci * ton of callers to this function. 1338c2ecf20Sopenharmony_ci */ 1348c2ecf20Sopenharmony_ci struct mconsole_reply reply; 1358c2ecf20Sopenharmony_ci int len, n; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci do { 1388c2ecf20Sopenharmony_ci reply.err = err; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci /* err can only be true on the first packet */ 1418c2ecf20Sopenharmony_ci err = 0; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci len = MIN(total, MCONSOLE_MAX_DATA - 1); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci if (len == total) reply.more = more; 1468c2ecf20Sopenharmony_ci else reply.more = 1; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci memcpy(reply.data, str, len); 1498c2ecf20Sopenharmony_ci reply.data[len] = '\0'; 1508c2ecf20Sopenharmony_ci total -= len; 1518c2ecf20Sopenharmony_ci str += len; 1528c2ecf20Sopenharmony_ci reply.len = len + 1; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci len = sizeof(reply) + reply.len - sizeof(reply.data); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci n = sendto(req->originating_fd, &reply, len, 0, 1578c2ecf20Sopenharmony_ci (struct sockaddr *) req->origin, req->originlen); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci if (n < 0) 1608c2ecf20Sopenharmony_ci return -errno; 1618c2ecf20Sopenharmony_ci } while (total > 0); 1628c2ecf20Sopenharmony_ci return 0; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ciint mconsole_reply(struct mc_request *req, const char *str, int err, int more) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci return mconsole_reply_len(req, str, strlen(str), err, more); 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ciint mconsole_unlink_socket(void) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci unlink(mconsole_socket_name); 1748c2ecf20Sopenharmony_ci return 0; 1758c2ecf20Sopenharmony_ci} 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_cistatic int notify_sock = -1; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ciint mconsole_notify(char *sock_name, int type, const void *data, int len) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci struct sockaddr_un target; 1828c2ecf20Sopenharmony_ci struct mconsole_notify packet; 1838c2ecf20Sopenharmony_ci int n, err = 0; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci lock_notify(); 1868c2ecf20Sopenharmony_ci if (notify_sock < 0) { 1878c2ecf20Sopenharmony_ci notify_sock = socket(PF_UNIX, SOCK_DGRAM, 0); 1888c2ecf20Sopenharmony_ci if (notify_sock < 0) { 1898c2ecf20Sopenharmony_ci err = -errno; 1908c2ecf20Sopenharmony_ci printk(UM_KERN_ERR "mconsole_notify - socket failed, " 1918c2ecf20Sopenharmony_ci "errno = %d\n", errno); 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci unlock_notify(); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci if (err) 1978c2ecf20Sopenharmony_ci return err; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci target.sun_family = AF_UNIX; 2008c2ecf20Sopenharmony_ci strcpy(target.sun_path, sock_name); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci packet.magic = MCONSOLE_MAGIC; 2038c2ecf20Sopenharmony_ci packet.version = MCONSOLE_VERSION; 2048c2ecf20Sopenharmony_ci packet.type = type; 2058c2ecf20Sopenharmony_ci len = (len > sizeof(packet.data)) ? sizeof(packet.data) : len; 2068c2ecf20Sopenharmony_ci packet.len = len; 2078c2ecf20Sopenharmony_ci memcpy(packet.data, data, len); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci err = 0; 2108c2ecf20Sopenharmony_ci len = sizeof(packet) + packet.len - sizeof(packet.data); 2118c2ecf20Sopenharmony_ci n = sendto(notify_sock, &packet, len, 0, (struct sockaddr *) &target, 2128c2ecf20Sopenharmony_ci sizeof(target)); 2138c2ecf20Sopenharmony_ci if (n < 0) { 2148c2ecf20Sopenharmony_ci err = -errno; 2158c2ecf20Sopenharmony_ci printk(UM_KERN_ERR "mconsole_notify - sendto failed, " 2168c2ecf20Sopenharmony_ci "errno = %d\n", errno); 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci return err; 2198c2ecf20Sopenharmony_ci} 220