Coverage Report

Created: 2026-04-01 06:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/lib/util/pidfile.c
Line
Count
Source
1
/*
2
   Unix SMB/CIFS implementation.
3
   pidfile handling
4
   Copyright (C) Andrew Tridgell 1998
5
   Copyright (C) Amitay Isaccs  2016
6
7
   This program is free software; you can redistribute it and/or modify
8
   it under the terms of the GNU General Public License as published by
9
   the Free Software Foundation; either version 3 of the License, or
10
   (at your option) any later version.
11
12
   This program is distributed in the hope that it will be useful,
13
   but WITHOUT ANY WARRANTY; without even the implied warranty of
14
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
   GNU General Public License for more details.
16
17
   You should have received a copy of the GNU General Public License
18
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
*/
20
21
#include "replace.h"
22
#include "system/filesys.h"
23
24
#include "lib/util/blocking.h"
25
#include "lib/util/debug.h"
26
#include "lib/util/samba_util.h"  /* For process_exists_by_pid() */
27
28
#include "lib/util/pidfile.h"
29
30
int pidfile_path_create(const char *path, int *pfd, pid_t *existing_pid)
31
0
{
32
0
  struct flock lck;
33
0
  char tmp[64] = { 0 };
34
0
  int fd, ret = 0;
35
0
  int len;
36
0
  ssize_t nwritten;
37
0
  bool retried = false;
38
39
0
  fd = open(path, O_CREAT|O_WRONLY|O_NONBLOCK, 0644);
40
0
  if (fd == -1) {
41
0
    return errno;
42
0
  }
43
44
0
  if (! set_close_on_exec(fd)) {
45
0
    ret = errno;
46
0
    goto fail;
47
0
  }
48
49
0
retry:
50
0
  lck = (struct flock) {
51
0
    .l_type = F_WRLCK,
52
0
    .l_whence = SEEK_SET,
53
0
  };
54
55
0
  do {
56
0
    ret = fcntl(fd, F_SETLK, &lck);
57
0
  } while ((ret == -1) && (errno == EINTR));
58
59
0
  if (ret != 0) {
60
0
    ret = errno;
61
62
0
    if ((ret == EACCES) || (ret == EAGAIN)) {
63
0
      do {
64
0
        ret = fcntl(fd, F_GETLK, &lck);
65
0
      } while ((ret == -1) && (errno == EINTR));
66
67
0
      if (ret == -1) {
68
0
        ret = errno;
69
0
        goto fail;
70
0
      }
71
72
0
      if (lck.l_type == F_UNLCK) {
73
0
        if (!retried) {
74
          /* Lock holder died, retry once */
75
0
          retried = true;
76
0
          goto retry;
77
0
        }
78
        /* Something badly wrong */
79
0
        ret = EIO;
80
0
        goto fail;
81
0
      }
82
83
0
      if (existing_pid != NULL) {
84
0
        *existing_pid = lck.l_pid;
85
0
      }
86
0
      return EAGAIN;
87
0
    }
88
0
    goto fail;
89
0
  }
90
91
  /*
92
   * PID file is locked by us so from here on we should unlink
93
   * on failure
94
   */
95
0
  len = snprintf(tmp, sizeof(tmp), "%u\n", getpid());
96
0
  if (len < 0) {
97
0
    ret = errno;
98
0
    goto fail_unlink;
99
0
  }
100
0
  if ((size_t)len >= sizeof(tmp)) {
101
0
    ret = ENOSPC;
102
0
    goto fail_unlink;
103
0
  }
104
105
0
  do {
106
0
    nwritten = write(fd, tmp, len);
107
0
  } while ((nwritten == -1) && (errno == EINTR));
108
109
0
  if ((nwritten == -1) || (nwritten != len)) {
110
0
    ret = errno;
111
0
    goto fail_unlink;
112
0
  }
113
114
0
  do {
115
0
    ret = ftruncate(fd, len);
116
0
  } while ((ret == -1) && (errno == EINTR));
117
118
0
  if (ret == -1) {
119
0
    ret = errno;
120
0
    goto fail_unlink;
121
0
  }
122
123
0
  *pfd = fd;
124
0
  return 0;
125
126
0
fail_unlink:
127
0
  unlink(path);
128
0
fail:
129
0
  close(fd);
130
0
  return ret;
131
0
}
132
133
void pidfile_fd_close(int fd)
134
0
{
135
0
  struct flock lck = {
136
0
    .l_type = F_UNLCK,
137
0
    .l_whence = SEEK_SET,
138
0
  };
139
0
  int ret;
140
141
0
  do {
142
0
    ret = fcntl(fd, F_SETLK, &lck);
143
0
  } while ((ret == -1) && (errno == EINTR));
144
145
0
  do {
146
0
    ret = close(fd);
147
0
  } while ((ret == -1) && (errno == EINTR));
148
0
}
149
150
151
/**
152
 * return the pid in a pidfile. return 0 if the process (or pidfile)
153
 * does not exist
154
 */
155
pid_t pidfile_pid(const char *piddir, const char *name)
156
0
{
157
0
  size_t len = strlen(piddir) + strlen(name) + 6;
158
0
  char pidFile[len];
159
0
  int fd;
160
0
  char pidstr[20] = { 0, };
161
0
  pid_t ret = -1;
162
163
0
  snprintf(pidFile, sizeof(pidFile), "%s/%s.pid", piddir, name);
164
165
0
  fd = open(pidFile, O_NONBLOCK | O_RDONLY, 0644);
166
167
0
  if (fd == -1) {
168
0
    return 0;
169
0
  }
170
171
0
  if (read(fd, pidstr, sizeof(pidstr)-1) <= 0) {
172
0
    goto noproc;
173
0
  }
174
175
0
  ret = (pid_t)atoi(pidstr);
176
0
  if (ret <= 0) {
177
0
    DEBUG(1, ("Could not parse contents of pidfile %s\n",
178
0
      pidFile));
179
0
    goto noproc;
180
0
  }
181
182
0
  if (!process_exists_by_pid(ret)) {
183
0
    DEBUG(10, ("Process with PID=%d does not exist.\n", (int)ret));
184
0
    goto noproc;
185
0
  }
186
187
0
  if (fcntl_lock(fd,F_SETLK,0,1,F_RDLCK)) {
188
    /* we could get the lock - it can't be a Samba process */
189
0
    DEBUG(10, ("Process with PID=%d is not a Samba process.\n",
190
0
      (int)ret));
191
0
    goto noproc;
192
0
  }
193
194
0
  close(fd);
195
0
  DEBUG(10, ("Process with PID=%d is running.\n", (int)ret));
196
0
  return ret;
197
198
0
 noproc:
199
0
  close(fd);
200
0
  return 0;
201
0
}
202
203
/**
204
 * create a pid file in the pid directory. open it and leave it locked
205
 */
206
void pidfile_create(const char *piddir, const char *name)
207
0
{
208
0
  size_t len = strlen(piddir) + strlen(name) + 6;
209
0
  char pidFile[len];
210
0
  pid_t pid = (pid_t)-1;
211
0
  int ret, fd;
212
213
0
  snprintf(pidFile, sizeof(pidFile), "%s/%s.pid", piddir, name);
214
215
0
  ret = pidfile_path_create(pidFile, &fd, &pid);
216
0
  if (ret == EAGAIN) {
217
0
    DEBUG(0,("ERROR: %s is already running. File %s exists and process id %d is running.\n",
218
0
       name, pidFile, (int)pid));
219
0
    exit(1);
220
0
  }
221
222
  /* Leave pid file open & locked for the duration... */
223
0
}
224
225
void pidfile_unlink(const char *piddir, const char *name)
226
0
{
227
0
  size_t len = strlen(piddir) + strlen(name) + 6;
228
0
  char pidFile[len];
229
0
  int ret;
230
231
0
  snprintf(pidFile, sizeof(pidFile), "%s/%s.pid", piddir, name);
232
233
0
  ret = unlink(pidFile);
234
0
  if (ret == -1) {
235
    DEBUG(0,("Failed to delete pidfile %s. Error was %s\n",
236
0
      pidFile, strerror(errno)));
237
0
  }
238
0
}