Coverage Report

Created: 2025-08-03 06:43

/src/tarantool/src/systemd.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2010-2017, Tarantool AUTHORS, please see AUTHORS file.
3
 *
4
 * Redistribution and use in source and binary forms, with or
5
 * without modification, are permitted provided that the following
6
 * conditions are met:
7
 *
8
 * 1. Redistributions of source code must retain the above
9
 *    copyright notice, this list of conditions and the
10
 *    following disclaimer.
11
 *
12
 * 2. Redistributions in binary form must reproduce the above
13
 *    copyright notice, this list of conditions and the following
14
 *    disclaimer in the documentation and/or other materials
15
 *    provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21
 * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
25
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
28
 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29
 * SUCH DAMAGE.
30
 */
31
#include "systemd.h"
32
33
#if defined(WITH_NOTIFY_SOCKET)
34
#include <errno.h>
35
#include <stdio.h>
36
#include <stdarg.h>
37
#include <stddef.h>
38
#include <stdlib.h>
39
#include <string.h>
40
#include <fcntl.h>
41
42
#include <unistd.h>
43
44
#include <netinet/in.h>
45
#include <sys/socket.h>
46
#include <sys/un.h>
47
48
#include "say.h"
49
50
static int systemd_fd = -1;
51
static const char *sd_unix_path = NULL;
52
53
0
int systemd_init(void) {
54
0
  sd_unix_path = getenv_safe("NOTIFY_SOCKET", NULL, 0);
55
0
  if (sd_unix_path == NULL) {
56
    /* Do nothing if the path is not set. */
57
0
    return 0;
58
0
  }
59
0
  if ((sd_unix_path[0] != '@' && sd_unix_path[0] != '/') ||
60
0
      (sd_unix_path[1] == '\0')) {
61
0
    say_error("systemd: NOTIFY_SOCKET contains bad value");
62
0
    goto error;
63
0
  }
64
  /* To be sure, that path to unix socket is OK */
65
0
  struct sockaddr_un sa = {
66
0
    .sun_family = AF_UNIX,
67
0
    .sun_path = { '\0' }
68
0
  };
69
0
  if (strlen(sd_unix_path) >= sizeof(sa.sun_path)) {
70
0
    say_error("systemd: NOTIFY_SOCKET is longer than MAX_UNIX_PATH");
71
0
    goto error;
72
0
  }
73
0
  if ((systemd_fd = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1) {
74
0
    say_syserror("systemd: failed to create unix socket");
75
0
    goto error;
76
0
  }
77
0
  if (fcntl(systemd_fd, F_SETFD, FD_CLOEXEC) == -1) {
78
0
    say_syserror("systemd: fcntl failed to set FD_CLOEXEC");
79
0
    goto error;
80
0
  }
81
82
#if defined(HAVE_SO_NOSIGPIPE)
83
  int val = 1;
84
  if (setsockopt(systemd_fd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&val,
85
      sizeof(val)) < 0) {
86
    say_syserror("systemd: failed to set NOSIGPIPE");
87
    goto error;
88
  }
89
#endif
90
91
0
  int sndbuf_sz = 4 * 1024 * 1024;
92
0
  if (setsockopt(systemd_fd, SOL_SOCKET, SO_SNDBUF, &sndbuf_sz,
93
0
          sizeof(int)) < 0) {
94
0
    say_syserror("systemd: failed to set sndbuf size");
95
0
    goto error;
96
0
  };
97
0
  return 0;
98
0
error:
99
0
  if (systemd_fd > 0) {
100
0
    close(systemd_fd);
101
0
    systemd_fd = -1;
102
0
  }
103
0
  free((char *)sd_unix_path);
104
0
  sd_unix_path = NULL;
105
0
  return -1;
106
0
}
107
108
0
void systemd_free(void) {
109
0
  if (systemd_fd > 0)
110
0
    close(systemd_fd);
111
0
  free((char *)sd_unix_path);
112
0
}
113
114
0
int systemd_notify(const char *message) {
115
0
  if (systemd_fd == -1 || sd_unix_path == NULL)
116
0
    return 0;
117
118
0
  struct sockaddr_un sa = {
119
0
    .sun_family = AF_UNIX,
120
0
  };
121
122
0
  strlcpy(sa.sun_path, sd_unix_path, sizeof(sa.sun_path));
123
0
  if (sa.sun_path[0] == '@')
124
0
    sa.sun_path[0] = '\0';
125
126
0
  say_debug("systemd: sending message '%s'", message);
127
0
  int flags = 0;
128
0
#if defined(HAVE_MSG_NOSIGNAL)
129
0
  flags |= MSG_NOSIGNAL;
130
0
#endif
131
0
  ssize_t sent = sendto(systemd_fd, message, (size_t) strlen(message),
132
0
    flags, (struct sockaddr *) &sa, sizeof(sa));
133
0
  if (sent == -1) {
134
0
    say_syserror("systemd: failed to send message");
135
0
    return -1;
136
0
  }
137
0
  return sent;
138
0
}
139
140
int
141
systemd_vsnotify(const char *format, va_list ap)
142
0
{
143
0
  if (systemd_fd == -1 || sd_unix_path == NULL)
144
0
    return 0;
145
0
  char *buf = NULL;
146
0
  int rv = vasprintf(&buf, format, ap);
147
0
  if (rv < 0 || buf == NULL) {
148
0
    say_syserror("systemd: failed to format string '%s'", format);
149
0
    return -1;
150
0
  }
151
0
  rv = systemd_notify(buf);
152
0
  free(buf);
153
0
  return rv;
154
0
}
155
156
CFORMAT(printf, 1, 2) int
157
systemd_snotify(const char *format, ...)
158
0
{
159
0
  if (systemd_fd == -1 || sd_unix_path == NULL)
160
0
    return 0;
161
0
  va_list args;
162
0
  va_start(args, format);
163
0
  size_t res = systemd_vsnotify(format, args);
164
0
  va_end(args);
165
0
  return res;
166
0
}
167
#endif /* defined(WITH_NOTIFY_SOCKET) */