journal.c 3.8 KB

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