Line data Source code
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 403 : int pidfile_path_create(const char *path, int *pfd, pid_t *existing_pid)
31 : {
32 5 : struct flock lck;
33 403 : char tmp[64] = { 0 };
34 403 : int fd, ret = 0;
35 5 : int len;
36 5 : ssize_t nwritten;
37 403 : bool retried = false;
38 :
39 403 : fd = open(path, O_CREAT|O_WRONLY|O_NONBLOCK, 0644);
40 403 : if (fd == -1) {
41 0 : return errno;
42 : }
43 :
44 403 : if (! set_close_on_exec(fd)) {
45 0 : ret = errno;
46 0 : goto fail;
47 : }
48 :
49 403 : retry:
50 403 : lck = (struct flock) {
51 : .l_type = F_WRLCK,
52 : .l_whence = SEEK_SET,
53 : };
54 :
55 5 : do {
56 403 : ret = fcntl(fd, F_SETLK, &lck);
57 403 : } while ((ret == -1) && (errno == EINTR));
58 :
59 403 : if (ret != 0) {
60 83 : ret = errno;
61 :
62 83 : if ((ret == EACCES) || (ret == EAGAIN)) {
63 0 : do {
64 83 : ret = fcntl(fd, F_GETLK, &lck);
65 83 : } while ((ret == -1) && (errno == EINTR));
66 :
67 83 : if (ret == -1) {
68 0 : ret = errno;
69 0 : goto fail;
70 : }
71 :
72 83 : 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 : }
78 : /* Something badly wrong */
79 0 : ret = EIO;
80 0 : goto fail;
81 : }
82 :
83 83 : if (existing_pid != NULL) {
84 83 : *existing_pid = lck.l_pid;
85 : }
86 83 : return EAGAIN;
87 : }
88 0 : goto fail;
89 : }
90 :
91 : /*
92 : * PID file is locked by us so from here on we should unlink
93 : * on failure
94 : */
95 320 : len = snprintf(tmp, sizeof(tmp), "%u\n", getpid());
96 320 : if (len < 0) {
97 0 : ret = errno;
98 0 : goto fail_unlink;
99 : }
100 320 : if ((size_t)len >= sizeof(tmp)) {
101 0 : ret = ENOSPC;
102 0 : goto fail_unlink;
103 : }
104 :
105 5 : do {
106 320 : nwritten = write(fd, tmp, len);
107 320 : } while ((nwritten == -1) && (errno == EINTR));
108 :
109 320 : if ((nwritten == -1) || (nwritten != len)) {
110 0 : ret = errno;
111 0 : goto fail_unlink;
112 : }
113 :
114 5 : do {
115 320 : ret = ftruncate(fd, len);
116 320 : } while ((ret == -1) && (errno == EINTR));
117 :
118 320 : if (ret == -1) {
119 0 : ret = errno;
120 0 : goto fail_unlink;
121 : }
122 :
123 320 : *pfd = fd;
124 320 : return 0;
125 :
126 0 : fail_unlink:
127 0 : unlink(path);
128 0 : fail:
129 0 : close(fd);
130 0 : return ret;
131 : }
132 :
133 0 : void pidfile_fd_close(int fd)
134 : {
135 0 : struct flock lck = {
136 : .l_type = F_UNLCK,
137 : .l_whence = SEEK_SET,
138 : };
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 1400 : pid_t pidfile_pid(const char *piddir, const char *name)
156 1400 : {
157 1400 : size_t len = strlen(piddir) + strlen(name) + 6;
158 1400 : char pidFile[len];
159 0 : int fd;
160 1400 : char pidstr[20] = { 0, };
161 1400 : pid_t ret = -1;
162 :
163 1400 : snprintf(pidFile, sizeof(pidFile), "%s/%s.pid", piddir, name);
164 :
165 1400 : fd = open(pidFile, O_NONBLOCK | O_RDONLY, 0644);
166 :
167 1400 : if (fd == -1) {
168 18 : return 0;
169 : }
170 :
171 1382 : if (read(fd, pidstr, sizeof(pidstr)-1) <= 0) {
172 0 : goto noproc;
173 : }
174 :
175 1382 : ret = (pid_t)atoi(pidstr);
176 1382 : if (ret <= 0) {
177 0 : DEBUG(1, ("Could not parse contents of pidfile %s\n",
178 : pidFile));
179 0 : goto noproc;
180 : }
181 :
182 1382 : 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 : }
186 :
187 1382 : 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 : (int)ret));
191 0 : goto noproc;
192 : }
193 :
194 1382 : close(fd);
195 1382 : DEBUG(10, ("Process with PID=%d is running.\n", (int)ret));
196 1382 : return ret;
197 :
198 0 : noproc:
199 0 : close(fd);
200 0 : return 0;
201 : }
202 :
203 : /**
204 : * create a pid file in the pid directory. open it and leave it locked
205 : */
206 219 : void pidfile_create(const char *piddir, const char *name)
207 219 : {
208 219 : size_t len = strlen(piddir) + strlen(name) + 6;
209 219 : char pidFile[len];
210 219 : pid_t pid = (pid_t)-1;
211 5 : int ret, fd;
212 :
213 219 : snprintf(pidFile, sizeof(pidFile), "%s/%s.pid", piddir, name);
214 :
215 219 : ret = pidfile_path_create(pidFile, &fd, &pid);
216 219 : if (ret == EAGAIN) {
217 0 : DEBUG(0,("ERROR: %s is already running. File %s exists and process id %d is running.\n",
218 : name, pidFile, (int)pid));
219 0 : exit(1);
220 : }
221 :
222 : /* Leave pid file open & locked for the duration... */
223 219 : }
224 :
225 153 : void pidfile_unlink(const char *piddir, const char *name)
226 153 : {
227 153 : size_t len = strlen(piddir) + strlen(name) + 6;
228 153 : char pidFile[len];
229 2 : int ret;
230 :
231 153 : snprintf(pidFile, sizeof(pidFile), "%s/%s.pid", piddir, name);
232 :
233 153 : ret = unlink(pidFile);
234 153 : if (ret == -1) {
235 0 : DEBUG(0,("Failed to delete pidfile %s. Error was %s\n",
236 : pidFile, strerror(errno)));
237 : }
238 153 : }
|