diff --git a/tools/acrn-crashlog/usercrash/Makefile b/tools/acrn-crashlog/usercrash/Makefile index 5975048c5..8475b3b73 100644 --- a/tools/acrn-crashlog/usercrash/Makefile +++ b/tools/acrn-crashlog/usercrash/Makefile @@ -1,11 +1,18 @@ all: check_obj usercrash_s usercrash_c +CURRDIR := $(shell pwd) +INCLUDE += -I $(CURRDIR)/include/ + LIBS = -levent -lpthread -usercrash_s: $(BUILDDIR)/usercrash/obj/server.o +usercrash_s: $(BUILDDIR)/usercrash/obj/protocol.o \ + $(BUILDDIR)/usercrash/obj/server.o \ + $(BUILDDIR)/common/obj/log_sys.o $(CC) -g $(CFLAGS) $(LIBS) $(INCLUDE) $^ -o $(BUILDDIR)/usercrash/bin/$@ -lsystemd -usercrash_c: $(BUILDDIR)/usercrash/obj/client.o +usercrash_c: $(BUILDDIR)/usercrash/obj/protocol.o \ + $(BUILDDIR)/usercrash/obj/client.o \ + $(BUILDDIR)/common/obj/log_sys.o $(CC) -g $(CFLAGS) $(INCLUDE) $^ -o $(BUILDDIR)/usercrash/bin/$@ -lsystemd $(BUILDDIR)/usercrash/obj/%.o:%.c diff --git a/tools/acrn-crashlog/usercrash/include/protocol.h b/tools/acrn-crashlog/usercrash/include/protocol.h new file mode 100644 index 000000000..21a5ba83a --- /dev/null +++ b/tools/acrn-crashlog/usercrash/include/protocol.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) <2018> Intel Corporation + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef PROTOCOL_H +#define PROTOCOL_H + +#include +#include +#include +#include +#include +#include + +#define RESERVED_SOCKET_PREFIX "/tmp/" + +int linux_get_control_socket(const char *name); + +int socket_local_client(const char *name, int type); +ssize_t send_fd(int sockfd, const void *data, size_t len, int fd); +ssize_t recv_fd(int sockfd, void *data, size_t len, int *out_fd); + +#endif diff --git a/tools/acrn-crashlog/usercrash/protocol.c b/tools/acrn-crashlog/usercrash/protocol.c new file mode 100644 index 000000000..9fd40a194 --- /dev/null +++ b/tools/acrn-crashlog/usercrash/protocol.c @@ -0,0 +1,222 @@ +/* + * Copyright (C) <2018> Intel Corporation + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * Copyright (C) 2018 Intel Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#include "protocol.h" +#include "log_sys.h" + +/* Documented in header file. */ +static int socket_make_sockaddr_un(const char *name, + struct sockaddr_un *p_addr, socklen_t *alen) +{ + size_t namelen; + + memset(p_addr, 0, sizeof(struct sockaddr_un)); + namelen = strlen(name) + strlen(RESERVED_SOCKET_PREFIX); + /* unix_path_max appears to be missing on linux */ + if (namelen > sizeof(*p_addr)- + offsetof(struct sockaddr_un, sun_path) - 1) { + return -1; + } + strcpy(p_addr->sun_path, RESERVED_SOCKET_PREFIX); + strcat(p_addr->sun_path, name); + p_addr->sun_family = AF_LOCAL; + *alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1; + return 0; +} + +/** + * connect to peer named "name" on fd + * returns same fd or -1 on error. + * fd is not closed on error. that's your job. + * + */ +static int socket_local_client_connect(int fd, const char *name) +{ + struct sockaddr_un addr; + socklen_t alen; + int err; + + err = socket_make_sockaddr_un(name, &addr, &alen); + + if (err < 0) + goto error; + + if (connect(fd, (struct sockaddr *) &addr, alen) < 0) { + LOGE("connect to usercrashd failed ,error (%s)\n", + strerror(errno)); + goto error; + } + + return fd; + +error: + return -1; +} + +/** + * connect to peer named "name" + * returns fd or -1 on error + */ +int socket_local_client(const char *name, int type) +{ + int s; + + s = socket(AF_LOCAL, type, 0); + if (s < 0) + return -1; + + if (socket_local_client_connect(s, name) < 0) { + close(s); + return -1; + } + + return s; +} + +static int socket_bind(int fd, const char *name) +{ + struct sockaddr_un addr; + socklen_t alen; + + addr.sun_family = AF_UNIX; + strcpy(addr.sun_path, name); + unlink(addr.sun_path); + alen = strlen(addr.sun_path) + sizeof(addr.sun_family); + + if (bind(fd, (struct sockaddr *)&addr, alen) == -1) + return -1; + + return fd; +} + +static int create_socket_server(const char *name, int type) +{ + int err; + int fd; + + fd = socket(AF_UNIX, type, 0); + if (fd < 0) + return -1; + + err = socket_bind(fd, name); + + if (err < 0) { + close(fd); + return -1; + } + + return fd; +} + +int linux_get_control_socket(const char *name) +{ + char socketName[64]; + + snprintf(socketName, sizeof(socketName), RESERVED_SOCKET_PREFIX "%s", + name); + return create_socket_server(socketName, SOCK_SEQPACKET); +} + +ssize_t send_fd(int sockfd, const void *data, size_t len, int fd) +{ + char cmsg_buf[CMSG_SPACE(sizeof(int))]; + struct msghdr msg; + struct iovec iov; + struct cmsghdr *cmsg; + + memset(&iov, 0, sizeof(iov)); + iov.iov_base = (void *)data; + iov.iov_len = len; + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = cmsg_buf; + msg.msg_controllen = sizeof(cmsg_buf); + + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + *(int *)(CMSG_DATA(cmsg)) = fd; + + return sendmsg(sockfd, &msg, 0); +} + +ssize_t recv_fd(int sockfd, void *data, size_t len, int *out_fd) +{ + char cmsg_buf[CMSG_SPACE(sizeof(int))]; + struct msghdr msg; + struct iovec iov; + struct cmsghdr *cmsg; + ssize_t result; + bool received_fd; + int fd; + + memset(&iov, 0, sizeof(iov)); + iov.iov_base = (void *)data; + iov.iov_len = len; + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = cmsg_buf; + msg.msg_controllen = sizeof(cmsg_buf); + msg.msg_flags = 0; + + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + + result = recvmsg(sockfd, &msg, 0); + if (result == -1) + return -1; + + received_fd = msg.msg_controllen == sizeof(cmsg_buf); + if (received_fd) + fd = *(int *)(CMSG_DATA(cmsg)); + else + return -1; + + if ((msg.msg_flags & MSG_TRUNC) != 0) { + errno = EFBIG; + goto fail; + } else if ((msg.msg_flags & MSG_CTRUNC) != 0) { + errno = ERANGE; + goto fail; + } + + if (out_fd) { + *out_fd = fd; + } else if (received_fd) { + errno = ERANGE; + goto fail; + } + + return result; +fail: + close(fd); + return -1; +}