util: New functions pidfile_path_create(), pidfile_fd_close()
[Samba.git] / lib / util / pidfile.c
blob2be61966e26d5e0d10c2cedc7af5648a8a130073
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 /**
31 * @file
32 * @brief Pid file handling
35 int pidfile_path_create(const char *path, int *outfd)
37 struct flock lck;
38 char tmp[64] = { 0 };
39 pid_t pid;
40 int fd, ret = 0;
41 int len;
42 ssize_t nwritten;
44 pid = getpid();
46 fd = open(path, O_CREAT|O_WRONLY|O_NONBLOCK, 0644);
47 if (fd == -1) {
48 return errno;
51 if (! set_close_on_exec(fd)) {
52 close(fd);
53 return EIO;
56 lck = (struct flock) {
57 .l_type = F_WRLCK,
58 .l_whence = SEEK_SET,
61 do {
62 ret = fcntl(fd, F_SETLK, &lck);
63 } while ((ret == -1) && (errno == EINTR));
65 if (ret != 0) {
66 ret = errno;
67 close(fd);
68 return ret;
72 * PID file is locked by us so from here on we should unlink
73 * on failure
76 do {
77 ret = ftruncate(fd, 0);
78 } while ((ret == -1) && (errno == EINTR));
80 if (ret == -1) {
81 ret = EIO;
82 goto fail_unlink;
85 len = snprintf(tmp, sizeof(tmp), "%u\n", pid);
86 if (len < 0) {
87 ret = errno;
88 goto fail_unlink;
90 if (len >= sizeof(tmp)) {
91 ret = ENOSPC;
92 goto fail_unlink;
95 do {
96 nwritten = write(fd, tmp, len);
97 } while ((nwritten == -1) && (errno == EINTR));
99 if ((nwritten == -1) || (nwritten != len)) {
100 ret = EIO;
101 goto fail_unlink;
104 if (outfd != NULL) {
105 *outfd = fd;
107 return 0;
109 fail_unlink:
110 unlink(path);
111 close(fd);
112 return ret;
115 void pidfile_fd_close(int fd)
117 struct flock lck = {
118 .l_type = F_UNLCK,
119 .l_whence = SEEK_SET,
121 int ret;
123 do {
124 ret = fcntl(fd, F_SETLK, &lck);
125 } while ((ret == -1) && (errno == EINTR));
127 do {
128 ret = close(fd);
129 } while ((ret == -1) && (errno == EINTR));
134 * return the pid in a pidfile. return 0 if the process (or pidfile)
135 * does not exist
137 pid_t pidfile_pid(const char *piddir, const char *name)
139 size_t len = strlen(piddir) + strlen(name) + 6;
140 char pidFile[len];
141 int fd;
142 char pidstr[20];
143 pid_t ret = -1;
145 snprintf(pidFile, sizeof(pidFile), "%s/%s.pid", piddir, name);
147 fd = open(pidFile, O_NONBLOCK | O_RDONLY, 0644);
149 if (fd == -1) {
150 return 0;
153 ZERO_STRUCT(pidstr);
155 if (read(fd, pidstr, sizeof(pidstr)-1) <= 0) {
156 goto noproc;
159 ret = (pid_t)atoi(pidstr);
160 if (ret <= 0) {
161 DEBUG(1, ("Could not parse contents of pidfile %s\n",
162 pidFile));
163 goto noproc;
166 if (!process_exists_by_pid(ret)) {
167 DEBUG(10, ("Process with PID=%d does not exist.\n", (int)ret));
168 goto noproc;
171 if (fcntl_lock(fd,F_SETLK,0,1,F_RDLCK)) {
172 /* we could get the lock - it can't be a Samba process */
173 DEBUG(10, ("Process with PID=%d is not a Samba process.\n",
174 (int)ret));
175 goto noproc;
178 close(fd);
179 DEBUG(10, ("Process with PID=%d is running.\n", (int)ret));
180 return ret;
182 noproc:
183 close(fd);
184 return 0;
188 * create a pid file in the pid directory. open it and leave it locked
190 void pidfile_create(const char *piddir, const char *name)
192 size_t len = strlen(piddir) + strlen(name) + 6;
193 char pidFile[len];
194 int fd;
195 char buf[20];
196 pid_t pid;
198 snprintf(pidFile, sizeof(pidFile), "%s/%s.pid", piddir, name);
200 pid = pidfile_pid(piddir, name);
201 if (pid != 0) {
202 DEBUG(0,("ERROR: %s is already running. File %s exists and process id %d is running.\n",
203 name, pidFile, (int)pid));
204 exit(1);
207 fd = open(pidFile, O_NONBLOCK | O_CREAT | O_WRONLY, 0644);
208 if (fd == -1) {
209 DEBUG(0,("ERROR: can't open %s: Error was %s\n", pidFile,
210 strerror(errno)));
211 exit(1);
214 smb_set_close_on_exec(fd);
216 if (fcntl_lock(fd,F_SETLK,0,1,F_WRLCK)==false) {
217 DEBUG(0,("ERROR: %s : fcntl lock of file %s failed. Error was %s\n",
218 name, pidFile, strerror(errno)));
219 exit(1);
222 memset(buf, 0, sizeof(buf));
223 slprintf(buf, sizeof(buf) - 1, "%u\n", (unsigned int) getpid());
224 if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf)) {
225 DEBUG(0,("ERROR: can't write to file %s: %s\n",
226 pidFile, strerror(errno)));
227 exit(1);
230 /* Leave pid file open & locked for the duration... */
233 void pidfile_unlink(const char *piddir, const char *name)
235 int ret;
236 char *pidFile = NULL;
238 if (asprintf(&pidFile, "%s/%s.pid", piddir, name) < 0) {
239 DEBUG(0,("ERROR: Out of memory\n"));
240 exit(1);
242 ret = unlink(pidFile);
243 if (ret == -1) {
244 DEBUG(0,("Failed to delete pidfile %s. Error was %s\n",
245 pidFile, strerror(errno)));