/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 | } |