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 225 : int pidfile_path_create(const char *path, int *pfd, pid_t *existing_pid)
31 : {
32 : struct flock lck;
33 225 : char tmp[64] = { 0 };
34 225 : int fd, ret = 0;
35 : int len;
36 : ssize_t nwritten;
37 225 : bool retried = false;
38 :
39 225 : fd = open(path, O_CREAT|O_WRONLY|O_NONBLOCK, 0644);
40 225 : if (fd == -1) {
41 0 : return errno;
42 : }
43 :
44 225 : if (! set_close_on_exec(fd)) {
45 0 : ret = errno;
46 0 : goto fail;
47 : }
48 :
49 225 : retry:
50 225 : lck = (struct flock) {
51 : .l_type = F_WRLCK,
52 : .l_whence = SEEK_SET,
53 : };
54 :
55 : do {
56 225 : ret = fcntl(fd, F_SETLK, &lck);
57 225 : } while ((ret == -1) && (errno == EINTR));
58 :
59 225 : if (ret != 0) {
60 3 : ret = errno;
61 :
62 3 : if ((ret == EACCES) || (ret == EAGAIN)) {
63 : do {
64 3 : ret = fcntl(fd, F_GETLK, &lck);
65 3 : } while ((ret == -1) && (errno == EINTR));
66 :
67 3 : if (ret == -1) {
68 0 : ret = errno;
69 0 : goto fail;
70 : }
71 :
72 3 : 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 3 : if (existing_pid != NULL) {
84 3 : *existing_pid = lck.l_pid;
85 : }
86 3 : 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 222 : len = snprintf(tmp, sizeof(tmp), "%u\n", getpid());
96 222 : if (len < 0) {
97 0 : ret = errno;
98 0 : goto fail_unlink;
99 : }
100 222 : if ((size_t)len >= sizeof(tmp)) {
101 0 : ret = ENOSPC;
102 0 : goto fail_unlink;
103 : }
104 :
105 : do {
106 222 : nwritten = write(fd, tmp, len);
107 222 : } while ((nwritten == -1) && (errno == EINTR));
108 :
109 222 : if ((nwritten == -1) || (nwritten != len)) {
110 0 : ret = errno;
111 0 : goto fail_unlink;
112 : }
113 :
114 : do {
115 222 : ret = ftruncate(fd, len);
116 222 : } while ((ret == -1) && (errno == EINTR));
117 :
118 222 : if (ret == -1) {
119 0 : ret = errno;
120 0 : goto fail_unlink;
121 : }
122 :
123 222 : *pfd = fd;
124 222 : 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 : int ret;
140 :
141 : do {
142 0 : ret = fcntl(fd, F_SETLK, &lck);
143 0 : } while ((ret == -1) && (errno == EINTR));
144 :
145 : 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 22 : pid_t pidfile_pid(const char *piddir, const char *name)
156 22 : {
157 22 : size_t len = strlen(piddir) + strlen(name) + 6;
158 22 : char pidFile[len];
159 : int fd;
160 22 : char pidstr[20] = { 0, };
161 22 : pid_t ret = -1;
162 :
163 22 : snprintf(pidFile, sizeof(pidFile), "%s/%s.pid", piddir, name);
164 :
165 22 : fd = open(pidFile, O_NONBLOCK | O_RDONLY, 0644);
166 :
167 22 : if (fd == -1) {
168 3 : return 0;
169 : }
170 :
171 19 : if (read(fd, pidstr, sizeof(pidstr)-1) <= 0) {
172 0 : goto noproc;
173 : }
174 :
175 19 : ret = (pid_t)atoi(pidstr);
176 19 : if (ret <= 0) {
177 0 : DEBUG(1, ("Could not parse contents of pidfile %s\n",
178 : pidFile));
179 0 : goto noproc;
180 : }
181 :
182 19 : 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 19 : 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 19 : close(fd);
195 19 : DEBUG(10, ("Process with PID=%d is running.\n", (int)ret));
196 19 : 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 188 : void pidfile_create(const char *piddir, const char *name)
207 188 : {
208 188 : size_t len = strlen(piddir) + strlen(name) + 6;
209 188 : char pidFile[len];
210 188 : pid_t pid = (pid_t)-1;
211 : int ret, fd;
212 :
213 188 : snprintf(pidFile, sizeof(pidFile), "%s/%s.pid", piddir, name);
214 :
215 188 : ret = pidfile_path_create(pidFile, &fd, &pid);
216 188 : 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 188 : }
224 :
225 53 : void pidfile_unlink(const char *piddir, const char *name)
226 53 : {
227 53 : size_t len = strlen(piddir) + strlen(name) + 6;
228 53 : char pidFile[len];
229 : int ret;
230 :
231 53 : snprintf(pidFile, sizeof(pidFile), "%s/%s.pid", piddir, name);
232 :
233 53 : ret = unlink(pidFile);
234 53 : if (ret == -1) {
235 0 : DEBUG(0,("Failed to delete pidfile %s. Error was %s\n",
236 : pidFile, strerror(errno)));
237 : }
238 53 : }
|