source: trunk/src/ct/status.c @ 1139

Revision 1139, 4.6 KB checked in by alonbl, 3 years ago (diff)

Fix openst status lock

By Stanislav Brabec.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 * Shared status file for OpenCT readers
3 *
4 * Copyright (C) 2003 Olaf Kirch <okir@suse.de>
5 */
6
7#ifdef HAVE_CONFIG_H
8#include <config.h>
9#endif
10#include <sys/types.h>
11#include <sys/mman.h>
12#include <sys/stat.h>
13#include <sys/types.h>
14#include <pwd.h>
15#include <signal.h>
16#include <unistd.h>
17#include <fcntl.h>
18#include <stdio.h>
19#include <stdlib.h>
20#include <errno.h>
21#include <string.h>
22#include <limits.h>
23
24#include <openct/openct.h>
25#include <openct/path.h>
26#include <openct/logging.h>
27
28static int ct_status_lock(void);
29static void ct_status_unlock(void);
30
31static void *ct_map_status(int flags, size_t * size)
32{
33        struct stat stb;
34        int fd, prot;
35        void *addr = NULL;
36        char status_path[PATH_MAX];
37
38        if (!ct_format_path(status_path, PATH_MAX, "status")) {
39                return NULL;
40        }
41
42        if ((fd = open(status_path, flags)) < 0) {
43                ct_error("can't open %s: %s", status_path, strerror(errno));
44                return NULL;
45        }
46
47        if (fstat(fd, &stb) < 0) {
48                ct_error("unable to stat %s: %m", status_path);
49                goto done;
50        }
51        *size = stb.st_size;
52
53        prot = PROT_READ;
54        if ((flags & O_ACCMODE) == O_RDWR)
55                prot |= PROT_WRITE;
56
57        addr = mmap(NULL, *size, prot, MAP_SHARED, fd, 0);
58        if (addr == MAP_FAILED) {
59                addr = NULL;
60        }
61
62      done:close(fd);
63        return addr;
64}
65
66int ct_status_destroy(void)
67{
68        char status_path[PATH_MAX];
69
70        if (!ct_format_path(status_path, PATH_MAX, "status")) {
71                return -1;
72        }
73
74        return unlink(status_path);
75}
76
77int ct_status_clear(unsigned int count, const char *owner)
78{
79        int fd = -1;
80        char status_path[PATH_MAX];
81
82        if (!ct_format_path(status_path, PATH_MAX, "status")) {
83                return -1;
84        }
85
86        unlink(status_path);
87        if ((fd = open(status_path, O_RDWR | O_CREAT, 0644)) < 0
88            || ftruncate(fd, count * sizeof(ct_info_t)) < 0
89            || fchmod(fd, 0644) < 0) {
90                ct_error("cannot create %s: %m", status_path);
91                goto error;
92        }
93
94        if (owner != NULL) {
95                struct passwd *p = getpwnam(owner);
96
97                if (p == NULL) {
98                        ct_error("cannot parse user %s", owner);
99                        goto error;
100                }
101
102                if (fchown(fd, p->pw_uid, -1) == -1) {
103                        ct_error("cannot chown %s to %s: %m", status_path, owner);
104                        goto error;
105                }
106        }
107
108        return 0;
109
110error:
111
112        unlink(status_path);
113        if (fd >= 0)
114                close(fd);
115        return -1;
116}
117
118int ct_status(const ct_info_t ** result)
119{
120        static const ct_info_t *reader_status;
121        static unsigned int num_status;
122
123        if (reader_status == NULL) {
124                size_t size;
125
126                reader_status = (ct_info_t *) ct_map_status(O_RDONLY, &size);
127                if (reader_status == NULL)
128                        return -1;
129                num_status = size / sizeof(ct_info_t);
130        }
131
132        *result = reader_status;
133        return num_status;
134}
135
136ct_info_t *ct_status_alloc_slot(int *num)
137{
138        ct_info_t *info;
139        size_t size;
140        unsigned int n, max;
141
142        info = (ct_info_t *) ct_map_status(O_RDWR, &size);
143        if (info == NULL)
144                return NULL;
145
146        max = size / sizeof(ct_info_t);
147        if (*num == -1) {
148                sigset_t sigset;
149
150                /* Block all signals while holding the lock */
151                sigfillset(&sigset);
152                sigprocmask(SIG_SETMASK, &sigset, &sigset);
153
154                /* Lock the status file against concurrent access */
155                ct_status_lock();
156
157                /* find a free slot */
158                for (n = 0; n < max; n++, info) {
159                        if (info[n].ct_pid == 0
160                            || (kill(info[n].ct_pid, 0) < 0
161                                && errno == ESRCH)) {
162                                *num = n;
163                                break;
164                        }
165                }
166
167                /* Done, unlock the file again */
168                ct_status_unlock();
169
170                /* unblock signals */
171                sigprocmask(SIG_SETMASK, &sigset, NULL);
172        } else if (*num >= max) {
173                munmap((void *)info, size);
174                return NULL;
175        }
176
177        memset(&info[*num], 0, sizeof(ct_info_t));
178        info[*num].ct_pid = getpid();
179
180        msync((void *)info, size, MS_SYNC);
181        return info + *num;
182}
183
184#define ALIGN(x, size)  (((caddr_t) (x)) - ((unsigned long) (x) % (size)))
185int ct_status_update(ct_info_t * status)
186{
187        size_t size;
188        caddr_t page;
189
190        /* get the page this piece of data is sitting on */
191        size = getpagesize();
192        page = ALIGN(status, size);
193
194        /* flush two pages if data spans two pages */
195        if (page != ALIGN(status + 1, size))
196                size <<= 1;
197
198        if (msync(page, size, MS_SYNC) < 0) {
199                ct_error("msync: %m");
200                return -1;
201        }
202
203        return 0;
204}
205
206/*
207 * Lock file handling
208 */
209static int ct_status_lock(void)
210{
211        int fd, retries = 10;
212        int ret = -1;
213        char status_lock_path[PATH_MAX];
214        char status_temp_path[PATH_MAX];
215
216        if (!ct_format_path(status_lock_path, PATH_MAX, "status.lock")) {
217                return -1;
218        }
219
220        snprintf(status_temp_path, PATH_MAX,
221                 "%s.%u", status_lock_path, (unsigned int)getpid());
222
223        if ((fd = open(status_temp_path, O_CREAT | O_RDWR, 0600)) < 0)
224                return -1;
225
226        while (retries--) {
227                if (link(status_temp_path, status_lock_path) >= 0) {
228                        ret = 0;
229                        break;
230                }
231        }
232
233        close(fd);
234        unlink(status_temp_path);
235        return ret;
236}
237
238static void ct_status_unlock(void)
239{
240        char status_lock_path[PATH_MAX];
241
242        if (!ct_format_path(status_lock_path, PATH_MAX, "status.lock")) {
243                return;
244        }
245
246        unlink(status_lock_path);
247}
Note: See TracBrowser for help on using the repository browser.