]> mj.ucw.cz Git - umpf.git/blob - lock.c
started work on locking mailboxes
[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                         break;
52                 }
53
54                 if (errno != EEXIST)
55                         break;
56
57                 /* FIXME: deal with old locks */
58
59                 random_sleep(1, 1);
60         }
61
62         free(lockfile);
63         return res;
64 }
65
66 static void
67 dot_unlock(char* path)
68 {
69         char* lockfile = cat(path, ".lock");
70
71         unlink(lockfile);
72
73         free(lockfile);
74 }
75
76 int
77 open_mailbox(char* path, int use_default_mailbox)
78 {
79         int fd;
80
81         /* attempt to dot_lock first */
82         if (dot_lock(path))
83                 return -1;
84
85         /* if OK, try to open the file:
86                 either we are saving to default mailbox (no problem here)
87                 or we are saving somewhere else (no need to be privileged)
88         */      
89         if (use_default_mailbox){
90                 /* get our preciousss out of pocket */
91                 gid_t ruid, euid, suid;
92                 getresgid(&ruid, &euid, &suid);
93                 setresgid(ruid, suid, suid);
94
95                 /* we are not going to create default mailbox */
96                 fd = open(path, O_RDWR);
97                 if (fd < 0)
98                         return -1;      
99
100                 /* hide it again */
101                 setresgid(ruid, ruid, suid);
102         } else {
103                 fd = open(path, O_RDWR);
104                 if (fd < 0 && errno == ENOENT){
105                         fd = open(path, O_RDWR | O_CREAT | O_EXCL,
106                                 S_IRUSR | S_IWUSR);
107                         if (fd < 0)
108                                 return -1;      
109
110                 } else if (fd < 0)
111                         return -1;      
112         }       
113
114         /* fcntl then */
115         struct flock mb_lock;
116         memset(&mb_lock, 0, sizeof(struct flock));
117         mb_lock.l_type = F_WRLCK;
118         mb_lock.l_whence = SEEK_SET;
119
120         if (fcntl(fd, F_GETLK, &mb_lock) < 0){
121                 close(fd);
122                 dot_unlock(path);
123                 return -1;
124         }
125
126         return fd; 
127 }
128
129 void
130 close_mailbox(int fd, char* path)
131 {
132         struct flock mb_lock;
133         memset(&mb_lock, 0, sizeof(struct flock));
134         mb_lock.l_type = F_UNLCK; 
135         fcntl(fd, F_SETLK, &mb_lock);
136         close(fd);
137         dot_unlock(path);
138 }
139
140 int
141 main(int argc, char** argv)
142 {
143         /* FIXME: move somewhere */
144         int fd;
145         gid_t ruid, euid, suid;
146         if (argc < 2)
147                 return 1;
148         char* mb = argv[1]; 
149         getresgid(&ruid, &euid, &suid);
150         setresgid(ruid, ruid, euid);
151         fd = open_mailbox(mb, 1);
152         printf("%d\n", fd); 
153         if (fd < 0)
154                 return 1;       
155
156         close_mailbox(fd, mb);
157
158         return 0;
159 }