ctdb-common: Add run_event abstraction
[gd/samba-autobuild/.git] / ctdb / common / pidfile.c
1 /*
2    Create and remove pidfile
3
4    Copyright (C) Amitay Isaacs  2016
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "replace.h"
21 #include "system/filesys.h"
22
23 #include <talloc.h>
24
25 #include "common/pidfile.h"
26
27 struct pidfile_context {
28         const char *pidfile;
29         int fd;
30         pid_t pid;
31 };
32
33 static int pidfile_context_destructor(struct pidfile_context *pid_ctx);
34
35 int pidfile_create(TALLOC_CTX *mem_ctx, const char *pidfile,
36                    struct pidfile_context **result)
37 {
38         struct pidfile_context *pid_ctx;
39         struct flock lck;
40         char tmp[64];
41         int fd, ret = 0;
42         int len;
43         ssize_t nwritten;
44
45         pid_ctx = talloc_zero(mem_ctx, struct pidfile_context);
46         if (pid_ctx == NULL) {
47                 return ENOMEM;
48         }
49
50         pid_ctx->pidfile = talloc_strdup(pid_ctx, pidfile);
51         if (pid_ctx->pidfile == NULL) {
52                 ret = ENOMEM;
53                 goto fail;
54         }
55
56         pid_ctx->pid = getpid();
57
58         fd = open(pidfile, O_CREAT|O_WRONLY|O_NONBLOCK, 0644);
59         if (fd == -1) {
60                 ret = errno;
61                 goto fail;
62         }
63
64         pid_ctx->fd = fd;
65
66         lck = (struct flock) {
67                 .l_type = F_WRLCK,
68                 .l_whence = SEEK_SET,
69         };
70
71         do {
72                 ret = fcntl(fd, F_SETLK, &lck);
73         } while ((ret == -1) && (errno == EINTR));
74
75         if (ret != 0) {
76                 ret = errno;
77                 goto fail;
78         }
79
80         do {
81                 ret = ftruncate(fd, 0);
82         } while ((ret == -1) && (errno == EINTR));
83
84         if (ret == -1) {
85                 ret = EIO;
86                 goto fail_unlink;
87         }
88
89         len = snprintf(tmp, sizeof(tmp), "%u\n", pid_ctx->pid);
90         if (len < 0) {
91                 ret = EIO;
92                 goto fail_unlink;
93         }
94
95         do {
96                 nwritten = write(fd, tmp, len);
97         } while ((nwritten == -1) && (errno == EINTR));
98
99         if ((nwritten == -1) || (nwritten != len)) {
100                 ret = EIO;
101                 goto fail_unlink;
102         }
103
104         talloc_set_destructor(pid_ctx, pidfile_context_destructor);
105
106         *result = pid_ctx;
107         return 0;
108
109 fail_unlink:
110         unlink(pidfile);
111         close(fd);
112
113 fail:
114         talloc_free(pid_ctx);
115         return ret;
116 }
117
118 static int pidfile_context_destructor(struct pidfile_context *pid_ctx)
119 {
120         struct flock lck;
121         int ret;
122
123         if (getpid() != pid_ctx->pid) {
124                 return 0;
125         }
126
127         lck = (struct flock) {
128                 .l_type = F_UNLCK,
129                 .l_whence = SEEK_SET,
130         };
131
132         (void) unlink(pid_ctx->pidfile);
133
134         do {
135                 ret = fcntl(pid_ctx->fd, F_SETLK, &lck);
136         } while ((ret == -1) && (errno == EINTR));
137
138         do {
139                 ret = close(pid_ctx->fd);
140         } while ((ret == -1) && (errno == EINTR));
141
142         return 0;
143 }