journal.c 3.8 KB

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