]> mj.ucw.cz Git - umpf.git/blob - lock.c
219f199f32ba16812654c6618c30c5d5063c4955
[umpf.git] / lock.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 #define _GNU_SOURCE
6 #include <unistd.h>
7 #include <fcntl.h>
8 #include <errno.h>
9 #include <sys/stat.h>
10
11 #include "brum.h"
12
13 #define LOCK_MAX_TRIES 30
14
15 static void
16 random_sleep(unsigned int about, unsigned int offset)
17 {
18         int myrand;
19
20         if (about == 0 || offset > about)
21                 die("random sleep: Bad input data: %d +- %d", about, offset);
22
23         myrand = random() % offset * (random()%2?1:-1);
24
25         usleep(about * 1000000 + myrand * 500000);
26 }
27
28 static char*
29 cat(char* l, char* r)
30 {
31         char* res = xmalloc(strlen(l) + strlen (r) + 1);
32         strcpy(res, l);
33         strcat(res, r);
34
35         return res;     
36 }
37
38 /* FIXME: what about privileges? */
39 static int
40 dot_lock(char* path)
41 {
42         int i;
43         int fd;
44         int res = -1;
45         char* lockfile = cat(path, ".lock");
46         
47         for (i = 0; i < LOCK_MAX_TRIES; i++){
48                 if ((fd = open(lockfile, O_WRONLY | O_EXCL | O_CREAT, 0)) 
49                         >= 0) {
50                         close(fd);
51                         res = 0;
52                         break;
53                 }
54
55                 if (errno != EEXIST)
56                         break;
57
58                 /* FIXME: deal with old locks */
59
60                 random_sleep(1, 1);
61         }
62
63         free(lockfile);
64         return res;
65 }
66
67 static void
68 dot_unlock(char* path)
69 {
70         char* lockfile = cat(path, ".lock");
71
72         unlink(lockfile);
73
74         free(lockfile);
75 }
76
77 int
78 open_mailbox(char* path, int use_default_mailbox)
79 {
80         int fd;
81
82         /* attempt to dot_lock first */
83         if (dot_lock(path))
84                 return -1;
85
86         /* if OK, try to open the file:
87                 either we are saving to default mailbox (no problem here)
88                 or we are saving somewhere else (no need to be privileged)
89         */      
90         if (use_default_mailbox){
91                 /* get our preciousss out of pocket */
92                 gid_t ruid, euid, suid;
93                 getresgid(&ruid, &euid, &suid);
94                 setresgid(ruid, suid, suid);
95
96                 /* we are not going to create default mailbox */
97                 fd = open(path, O_RDWR);
98                 if (fd < 0){
99                         dot_unlock(path);
100                         return -1;
101                 }
102
103                 /* hide it again */
104                 setresgid(ruid, ruid, suid);
105         } else {
106                 fd = open(path, O_RDWR);
107                 if (fd < 0 && errno == ENOENT){
108                         fd = open(path, O_RDWR | O_CREAT | O_EXCL,
109                                 S_IRUSR | S_IWUSR);
110                         if (fd < 0){
111                                 dot_unlock(path);
112                                 return -1;      
113                         }
114
115                 } else if (fd < 0){
116                         dot_unlock(path);
117                         return -1;
118                 }       
119         }       
120
121         /* fcntl then */
122         struct flock mb_lock;
123         memset(&mb_lock, 0, sizeof(struct flock));
124         mb_lock.l_type = F_WRLCK;
125         mb_lock.l_whence = SEEK_SET;
126
127         if (fcntl(fd, F_GETLK, &mb_lock) < 0){
128                 close(fd);
129                 dot_unlock(path);
130                 return -1;
131         }
132
133         return fd; 
134 }
135
136 void
137 close_mailbox(int fd, char* path)
138 {
139         struct flock mb_lock;
140         memset(&mb_lock, 0, sizeof(struct flock));
141         mb_lock.l_type = F_UNLCK; 
142         fcntl(fd, F_SETLK, &mb_lock);
143         close(fd);
144         dot_unlock(path);
145 }
146
147 int
148 main(int argc, char** argv)
149 {
150         /* FIXME: move somewhere */
151         int fd;
152         gid_t ruid, euid, suid;
153         if (argc < 2)
154                 return 1;
155         char* mb = argv[1]; 
156         getresgid(&ruid, &euid, &suid);
157         setresgid(ruid, ruid, euid);
158         fd = open_mailbox(mb, 0);
159         printf("%d\n", fd); 
160         if (fd < 0)
161                 return 1;       
162
163         close_mailbox(fd, mb);
164
165         return 0;
166 }