VERSION: Bump version up to Samba 4.17.8...
[Samba.git] / lib / util / pidfile.c
blob6ffbbeac5ee35537551099a0c391984cc0bf130e
1 /*
2 Unix SMB/CIFS implementation.
3 pidfile handling
4 Copyright (C) Andrew Tridgell 1998
5 Copyright (C) Amitay Isaccs 2016
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.
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.
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/>.
21 #include "replace.h"
22 #include "system/filesys.h"
24 #include "lib/util/blocking.h"
25 #include "lib/util/debug.h"
26 #include "lib/util/samba_util.h" /* For process_exists_by_pid() */
28 #include "lib/util/pidfile.h"
30 int pidfile_path_create(const char *path, int *pfd, pid_t *existing_pid)
32 struct flock lck;
33 char tmp[64] = { 0 };
34 int fd, ret = 0;
35 int len;
36 ssize_t nwritten;
37 bool retried = false;
39 fd = open(path, O_CREAT|O_WRONLY|O_NONBLOCK, 0644);
40 if (fd == -1) {
41 return errno;
44 if (! set_close_on_exec(fd)) {
45 ret = errno;
46 goto fail;
49 retry:
50 lck = (struct flock) {
51 .l_type = F_WRLCK,
52 .l_whence = SEEK_SET,
55 do {
56 ret = fcntl(fd, F_SETLK, &lck);
57 } while ((ret == -1) && (errno == EINTR));
59 if (ret != 0) {
60 ret = errno;
62 if ((ret == EACCES) || (ret == EAGAIN)) {
63 do {
64 ret = fcntl(fd, F_GETLK, &lck);
65 } while ((ret == -1) && (errno == EINTR));
67 if (ret == -1) {
68 ret = errno;
69 goto fail;
72 if (lck.l_type == F_UNLCK) {
73 if (!retried) {
74 /* Lock holder died, retry once */
75 retried = true;
76 goto retry;
78 /* Something badly wrong */
79 ret = EIO;
80 goto fail;
83 if (existing_pid != NULL) {
84 *existing_pid = lck.l_pid;
86 return EAGAIN;
88 goto fail;
92 * PID file is locked by us so from here on we should unlink
93 * on failure
95 len = snprintf(tmp, sizeof(tmp), "%u\n", getpid());
96 if (len < 0) {
97 ret = errno;
98 goto fail_unlink;
100 if ((size_t)len >= sizeof(tmp)) {
101 ret = ENOSPC;
102 goto fail_unlink;
105 do {
106 nwritten = write(fd, tmp, len);
107 } while ((nwritten == -1) && (errno == EINTR));
109 if ((nwritten == -1) || (nwritten != len)) {
110 ret = errno;
111 goto fail_unlink;
114 do {
115 ret = ftruncate(fd, len);
116 } while ((ret == -1) && (errno == EINTR));
118 if (ret == -1) {
119 ret = errno;
120 goto fail_unlink;
123 *pfd = fd;
124 return 0;
126 fail_unlink:
127 unlink(path);
128 fail:
129 close(fd);
130 return ret;
133 void pidfile_fd_close(int fd)
135 struct flock lck = {
136 .l_type = F_UNLCK,
137 .l_whence = SEEK_SET,
139 int ret;
141 do {
142 ret = fcntl(fd, F_SETLK, &lck);
143 } while ((ret == -1) && (errno == EINTR));
145 do {
146 ret = close(fd);
147 } while ((ret == -1) && (errno == EINTR));
152 * return the pid in a pidfile. return 0 if the process (or pidfile)
153 * does not exist
155 pid_t pidfile_pid(const char *piddir, const char *name)
157 size_t len = strlen(piddir) + strlen(name) + 6;
158 char pidFile[len];
159 int fd;
160 char pidstr[20] = { 0, };
161 pid_t ret = -1;
163 snprintf(pidFile, sizeof(pidFile), "%s/%s.pid", piddir, name);
165 fd = open(pidFile, O_NONBLOCK | O_RDONLY, 0644);
167 if (fd == -1) {
168 return 0;
171 if (read(fd, pidstr, sizeof(pidstr)-1) <= 0) {
172 goto noproc;
175 ret = (pid_t)atoi(pidstr);
176 if (ret <= 0) {
177 DEBUG(1, ("Could not parse contents of pidfile %s\n",
178 pidFile));
179 goto noproc;
182 if (!process_exists_by_pid(ret)) {
183 DEBUG(10, ("Process with PID=%d does not exist.\n", (int)ret));
184 goto noproc;
187 if (fcntl_lock(fd,F_SETLK,0,1,F_RDLCK)) {
188 /* we could get the lock - it can't be a Samba process */
189 DEBUG(10, ("Process with PID=%d is not a Samba process.\n",
190 (int)ret));
191 goto noproc;
194 close(fd);
195 DEBUG(10, ("Process with PID=%d is running.\n", (int)ret));
196 return ret;
198 noproc:
199 close(fd);
200 return 0;
204 * create a pid file in the pid directory. open it and leave it locked
206 void pidfile_create(const char *piddir, const char *name)
208 size_t len = strlen(piddir) + strlen(name) + 6;
209 char pidFile[len];
210 pid_t pid = (pid_t)-1;
211 int ret, fd;
213 snprintf(pidFile, sizeof(pidFile), "%s/%s.pid", piddir, name);
215 ret = pidfile_path_create(pidFile, &fd, &pid);
216 if (ret == EAGAIN) {
217 DEBUG(0,("ERROR: %s is already running. File %s exists and process id %d is running.\n",
218 name, pidFile, (int)pid));
219 exit(1);
222 /* Leave pid file open & locked for the duration... */
225 void pidfile_unlink(const char *piddir, const char *name)
227 size_t len = strlen(piddir) + strlen(name) + 6;
228 char pidFile[len];
229 int ret;
231 snprintf(pidFile, sizeof(pidFile), "%s/%s.pid", piddir, name);
233 ret = unlink(pidFile);
234 if (ret == -1) {
235 DEBUG(0,("Failed to delete pidfile %s. Error was %s\n",
236 pidFile, strerror(errno)));