mirror of
https://github.com/ps5-payload-dev/klogsrv.git
synced 2026-10-21 11:12:18 -05:00
367 lines
8.0 KiB
C
367 lines
8.0 KiB
C
/* Copyright (C) 2025 John Törnblom
|
|
|
|
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 3, 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; see the file COPYING. If not, see
|
|
<http://www.gnu.org/licenses/>. */
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <arpa/inet.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <ifaddrs.h>
|
|
#include <netinet/in.h>
|
|
#include <pthread.h>
|
|
#include <signal.h>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/sysctl.h>
|
|
#include <sys/syscall.h>
|
|
#include <unistd.h>
|
|
|
|
#ifdef __PROSPERO__
|
|
#include <ps5/klog.h>
|
|
#endif
|
|
|
|
#ifdef __ORBIS__
|
|
#include <ps4/klog.h>
|
|
#endif
|
|
|
|
|
|
#define LOG_PUTS(s) { \
|
|
puts(s); \
|
|
klog_puts(s); \
|
|
}
|
|
|
|
#define LOG_PRINTF(s, ...) { \
|
|
fprintf(stdout, s, __VA_ARGS__); \
|
|
klog_printf(s, __VA_ARGS__); \
|
|
}
|
|
|
|
#define LOG_PERROR(s) { \
|
|
fprintf(stderr, "%s:%d:%s: %s\n", __FILE__, __LINE__, \
|
|
s, strerror(errno)); \
|
|
klog_printf("%s:%d:%s: %s\n", __FILE__, __LINE__, \
|
|
s, strerror(errno)); \
|
|
}
|
|
|
|
|
|
typedef struct notify_request {
|
|
char useless[45];
|
|
char message[3075];
|
|
} notify_request_t;
|
|
|
|
|
|
int sceKernelSendNotificationRequest(int, notify_request_t*, size_t, int);
|
|
|
|
|
|
static void
|
|
notify(const char *fmt, ...) {
|
|
notify_request_t req = {0};
|
|
va_list args = {0};
|
|
|
|
va_start(args, fmt);
|
|
vsnprintf(req.message, sizeof req.message, fmt, args);
|
|
va_end(args);
|
|
|
|
sceKernelSendNotificationRequest(0, &req, sizeof req, 0);
|
|
LOG_PUTS(req.message);
|
|
}
|
|
|
|
|
|
static int
|
|
serve_file_while_connected(const char *path, int server_fd) {
|
|
struct timeval timeout;
|
|
size_t nb_connections;
|
|
fd_set output_set;
|
|
fd_set input_set;
|
|
fd_set temp_set;
|
|
int client_fd;
|
|
char buf[255];
|
|
ssize_t len;
|
|
int file_fd;
|
|
int err = 0;
|
|
|
|
if((file_fd=open(path, O_RDONLY)) < 0) {
|
|
LOG_PERROR("open");
|
|
return -1;
|
|
}
|
|
|
|
FD_ZERO(&input_set);
|
|
FD_ZERO(&output_set);
|
|
|
|
FD_SET(server_fd, &input_set);
|
|
FD_SET(file_fd, &input_set);
|
|
|
|
timeout.tv_sec = 0;
|
|
timeout.tv_usec = 1000*10; //10ms
|
|
nb_connections = 0;
|
|
|
|
do {
|
|
temp_set = input_set;
|
|
switch(select(FD_SETSIZE, &temp_set, NULL, NULL, &timeout)) {
|
|
case 0:
|
|
continue;
|
|
case -1:
|
|
LOG_PERROR("select");
|
|
close(file_fd);
|
|
return -1;
|
|
}
|
|
|
|
// new connection
|
|
if(FD_ISSET(server_fd, &temp_set)) {
|
|
if((client_fd=accept(server_fd, NULL, NULL)) < 0) {
|
|
LOG_PERROR("accept");
|
|
err = -1;
|
|
break;
|
|
}
|
|
FD_SET(client_fd, &output_set);
|
|
nb_connections++;
|
|
}
|
|
|
|
// new data from file
|
|
if(FD_ISSET(file_fd, &temp_set)) {
|
|
if((len=read(file_fd, buf, sizeof(buf))) < 1) {
|
|
LOG_PERROR("read");
|
|
err = -1;
|
|
break;
|
|
}
|
|
|
|
for(client_fd=0; client_fd<FD_SETSIZE; client_fd++) {
|
|
if(FD_ISSET(client_fd, &output_set)) {
|
|
if(write(client_fd, buf, len) != len) {
|
|
FD_CLR(client_fd, &output_set);
|
|
close(client_fd);
|
|
nb_connections--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} while(nb_connections > 0);
|
|
|
|
for(client_fd=0; client_fd<FD_SETSIZE; client_fd++) {
|
|
if(FD_ISSET(client_fd, &output_set)) {
|
|
FD_CLR(client_fd, &output_set);
|
|
close(client_fd);
|
|
}
|
|
}
|
|
close(file_fd);
|
|
|
|
return err;
|
|
}
|
|
|
|
static int
|
|
serve_file(const char *path, uint16_t port, int notify_user) {
|
|
char ip[INET_ADDRSTRLEN];
|
|
struct ifaddrs *ifaddr;
|
|
struct sockaddr_in sin;
|
|
int ifaddr_wait = 1;
|
|
fd_set set;
|
|
int sockfd;
|
|
|
|
if(getifaddrs(&ifaddr) == -1) {
|
|
LOG_PERROR("getifaddrs");
|
|
return -1;
|
|
}
|
|
|
|
// Enumerate all AF_INET IPs
|
|
for(struct ifaddrs *ifa=ifaddr; ifa!=NULL; ifa=ifa->ifa_next) {
|
|
if(ifa->ifa_addr == NULL) {
|
|
continue;
|
|
}
|
|
|
|
if(ifa->ifa_addr->sa_family != AF_INET) {
|
|
continue;
|
|
}
|
|
|
|
// skip localhost
|
|
if(!strncmp("lo", ifa->ifa_name, 2)) {
|
|
continue;
|
|
}
|
|
|
|
struct sockaddr_in *in = (struct sockaddr_in*)ifa->ifa_addr;
|
|
inet_ntop(AF_INET, &(in->sin_addr), ip, sizeof(ip));
|
|
|
|
// skip interfaces without an ip
|
|
if(!strncmp("0.", ip, 2)) {
|
|
continue;
|
|
}
|
|
if(notify_user) {
|
|
notify("Serving /dev/klog on %s:%d (%s)", ip, port, ifa->ifa_name);
|
|
}
|
|
ifaddr_wait = 0;
|
|
}
|
|
notify_user = 0;
|
|
|
|
freeifaddrs(ifaddr);
|
|
|
|
if(ifaddr_wait) {
|
|
return 0;
|
|
}
|
|
|
|
if((sockfd=socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
|
LOG_PERROR("socket");
|
|
return -1;
|
|
}
|
|
|
|
if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)) < 0) {
|
|
LOG_PERROR("setsockopt");
|
|
close(sockfd);
|
|
return -1;
|
|
}
|
|
|
|
memset(&sin, 0, sizeof(sin));
|
|
sin.sin_family = AF_INET;
|
|
sin.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
sin.sin_port = htons(port);
|
|
|
|
if(bind(sockfd, (struct sockaddr*)&sin, sizeof(sin)) < 0) {
|
|
LOG_PERROR("bind");
|
|
close(sockfd);
|
|
return -1;
|
|
}
|
|
|
|
if(listen(sockfd, 5) < 0) {
|
|
LOG_PERROR("listen");
|
|
close(sockfd);
|
|
return -1;
|
|
}
|
|
|
|
while(1) {
|
|
// wait for a connection
|
|
FD_ZERO(&set);
|
|
FD_SET(sockfd, &set);
|
|
if(select(sockfd+1, &set, NULL, NULL, NULL) < 0) {
|
|
LOG_PERROR("select");
|
|
close(sockfd);
|
|
return -1;
|
|
}
|
|
|
|
// someone wants to connect
|
|
if(FD_ISSET(sockfd, &set)) {
|
|
if(serve_file_while_connected(path, sockfd) < 0) {
|
|
close(sockfd);
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
* Fint the pid of a process with the given name.
|
|
**/
|
|
static pid_t
|
|
find_pid(const char* name) {
|
|
int mib[4] = {1, 14, 8, 0};
|
|
pid_t mypid = getpid();
|
|
pid_t pid = -1;
|
|
size_t buf_size;
|
|
uint8_t *buf;
|
|
|
|
if(sysctl(mib, 4, 0, &buf_size, 0, 0)) {
|
|
LOG_PERROR("sysctl");
|
|
return -1;
|
|
}
|
|
|
|
if(!(buf=malloc(buf_size))) {
|
|
LOG_PERROR("malloc");
|
|
return -1;
|
|
}
|
|
|
|
if(sysctl(mib, 4, buf, &buf_size, 0, 0)) {
|
|
LOG_PERROR("sysctl");
|
|
free(buf);
|
|
return -1;
|
|
}
|
|
|
|
for(uint8_t *ptr=buf; ptr<(buf+buf_size);) {
|
|
int ki_structsize = *(int*)ptr;
|
|
pid_t ki_pid = *(pid_t*)&ptr[72];
|
|
char *ki_tdname = (char*)&ptr[447];
|
|
|
|
ptr += ki_structsize;
|
|
if(!strcmp(name, ki_tdname) && ki_pid != mypid) {
|
|
pid = ki_pid;
|
|
}
|
|
}
|
|
|
|
free(buf);
|
|
|
|
return pid;
|
|
}
|
|
|
|
|
|
int
|
|
main(int argc, char* argv[]) {
|
|
uint16_t port = 3232;
|
|
int notify_user = 1;
|
|
pid_t pid;
|
|
char c;
|
|
|
|
syscall(SYS_thr_set_name, -1, "klogsrv.elf");
|
|
signal(SIGPIPE, SIG_IGN);
|
|
|
|
while((c=getopt(argc, argv, "p:qh")) != -1) {
|
|
switch(c) {
|
|
case 'p':
|
|
port = atoi(optarg);
|
|
break;
|
|
|
|
case 'q':
|
|
notify_user = 0;
|
|
break;
|
|
|
|
case 'h':
|
|
default:
|
|
printf("usage: %s [-p PORT] [-q]\n", argv[0]);
|
|
puts("");
|
|
printf("options:");
|
|
printf(" -p PORT Bind the socket server to the given PORT (default: 3232)\n");
|
|
printf(" -q Do not send an on-screen notification when the server starts\n");
|
|
return EXIT_FAILURE;
|
|
}
|
|
}
|
|
|
|
puts(".----------------------------------------------------------------------.");
|
|
puts("| _ _ _ __ |");
|
|
puts("| | | __ | | ___ __ _ ___ _ __ __ __ ___ | | / _| |");
|
|
puts("| | |/ / | | / _ \\ / _` | / __| | '__| \\ \\ / / / _ \\ | | | |_ |");
|
|
puts("| | < | | | (_) | | (_| | \\__ \\ | | \\ V / _ | __/ | | | _| |");
|
|
puts("| |_|\\_\\ |_| \\___/ \\__/ | |___/ |_| \\_/ (_) \\___| |_| |_| |");
|
|
puts("| |___/ |");
|
|
printf("| %-35s Copyright (C) 2025 John Törnblom |\n", VERSION_TAG);
|
|
puts("'----------------------------------------------------------------------'");
|
|
|
|
while((pid=find_pid("klogsrv.elf")) > 0) {
|
|
if(kill(pid, SIGKILL)) {
|
|
LOG_PERROR("kill");
|
|
return EXIT_FAILURE;
|
|
}
|
|
sleep(1);
|
|
}
|
|
|
|
while(1) {
|
|
serve_file("/dev/klog", port, notify_user);
|
|
notify_user = 0;
|
|
sleep(3);
|
|
}
|
|
|
|
return 0;
|
|
}
|