1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
// SPDX-License-Identifier: GPL-3.0-or-later
#include "journal.h"
bool is_path_unix_socket(const char *path) {
if(!path || !*path)
return false;
struct stat statbuf;
// Check if the path is valid
if (!path || !*path)
return false;
// Use stat to check if the file exists and is a socket
if (stat(path, &statbuf) == -1)
// The file does not exist or cannot be accessed
return false;
// Check if the file is a socket
if (S_ISSOCK(statbuf.st_mode))
return true;
return false;
}
bool is_stderr_connected_to_journal(void) {
const char *journal_stream = getenv("JOURNAL_STREAM");
if (!journal_stream)
return false; // JOURNAL_STREAM is not set
struct stat stderr_stat;
if (fstat(STDERR_FILENO, &stderr_stat) < 0)
return false; // Error in getting stderr info
// Parse device and inode from JOURNAL_STREAM
char *endptr;
long journal_dev = strtol(journal_stream, &endptr, 10);
if (*endptr != ':')
return false; // Format error in JOURNAL_STREAM
long journal_ino = strtol(endptr + 1, NULL, 10);
return (stderr_stat.st_dev == (dev_t)journal_dev) && (stderr_stat.st_ino == (ino_t)journal_ino);
}
int journal_direct_fd(const char *path) {
if(!path || !*path)
path = JOURNAL_DIRECT_SOCKET;
if(!is_path_unix_socket(path))
return -1;
int fd = socket(AF_UNIX, SOCK_DGRAM, 0);
if (fd < 0) return -1;
struct sockaddr_un addr;
memset(&addr, 0, sizeof(struct sockaddr_un));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
// Connect the socket (optional, but can simplify send operations)
if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
close(fd);
return -1;
}
return fd;
}
static inline bool journal_send_with_memfd(int fd, const char *msg, size_t msg_len) {
#if defined(__NR_memfd_create) && defined(MFD_ALLOW_SEALING) && defined(F_ADD_SEALS) && defined(F_SEAL_SHRINK) && defined(F_SEAL_GROW) && defined(F_SEAL_WRITE)
// Create a memory file descriptor
int memfd = (int)syscall(__NR_memfd_create, "journald", MFD_ALLOW_SEALING);
if (memfd < 0) return false;
// Write data to the memfd
if (write(memfd, msg, msg_len) != (ssize_t)msg_len) {
close(memfd);
return false;
}
// Seal the memfd to make it immutable
if (fcntl(memfd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE) < 0) {
close(memfd);
return false;
}
struct iovec iov = {0};
struct msghdr msghdr = {0};
struct cmsghdr *cmsghdr;
char cmsgbuf[CMSG_SPACE(sizeof(int))];
msghdr.msg_iov = &iov;
msghdr.msg_iovlen = 1;
msghdr.msg_control = cmsgbuf;
msghdr.msg_controllen = sizeof(cmsgbuf);
cmsghdr = CMSG_FIRSTHDR(&msghdr);
cmsghdr->cmsg_level = SOL_SOCKET;
cmsghdr->cmsg_type = SCM_RIGHTS;
cmsghdr->cmsg_len = CMSG_LEN(sizeof(int));
memcpy(CMSG_DATA(cmsghdr), &memfd, sizeof(int));
ssize_t r = sendmsg(fd, &msghdr, 0);
close(memfd);
return r >= 0;
#else
return false;
#endif
}
bool journal_direct_send(int fd, const char *msg, size_t msg_len) {
// Send the datagram
if (send(fd, msg, msg_len, 0) < 0) {
if(errno != EMSGSIZE)
return false;
// datagram is too large, fallback to memfd
if(!journal_send_with_memfd(fd, msg, msg_len))
return false;
}
return true;
}
void journal_construct_path(char *dst, size_t dst_len, const char *host_prefix, const char *namespace_str) {
if(!host_prefix)
host_prefix = "";
if(namespace_str)
snprintfz(dst, dst_len, "%s/run/systemd/journal.%s/socket",
host_prefix, namespace_str);
else
snprintfz(dst, dst_len, "%s" JOURNAL_DIRECT_SOCKET,
host_prefix);
}
|