chiark / gitweb /
*** empty log message ***
[sympathy.git] / src / lockfile.c
1 /*
2  * lockfile.c:
3  *
4  * Copyright (c) 2008 James McKenzie <james@fishsoup.dhs.org>,
5  * All rights reserved.
6  *
7  */
8
9 static char rcsid[] = "$Id$";
10
11 /*
12  * $Log$
13  * Revision 1.3  2008/02/15 18:16:35  james
14  * *** empty log message ***
15  *
16  * Revision 1.2  2008/02/15 16:48:56  james
17  * *** empty log message ***
18  *
19  * Revision 1.1  2008/02/15 15:09:17  james
20  * *** empty log message ***
21  *
22  */
23
24 #define LOCK_ASCII
25 #undef LOCK_BINARY
26
27 #include <stdio.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <malloc.h>
31 #include <unistd.h>
32 #include <string.h>
33 #include <strings.h>
34 #include <stdlib.h>
35 #include <pwd.h>
36 #include <fcntl.h>
37 #include <dirent.h>
38
39 #include "lockfile.h"
40
41 Filelist *
42 filelist_new (void)
43 {
44   Filelist *fl = (Filelist *) malloc (sizeof (Filelist));
45
46   fl->head = NULL;
47
48   return fl;
49 }
50
51 void
52 filelist_remove (Filelist * fl, Filelist_ent * fle)
53 {
54   Filelist_ent **ep;
55
56   for (ep = &fl->head; *ep; ep = &((*ep)->next))
57     if (fle == *ep)
58       break;
59
60
61   if (!*ep)
62     return;
63
64   *ep = fle->next;
65
66   free (fle);
67 }
68
69 void
70 filelist_add (Filelist * fl, char *fn)
71 {
72   Filelist_ent *fle;
73   int i = strlen (fn);
74
75   if (i >= FILE_LIST_MAX_LEN)
76     return;
77
78   for (fle=fl->head;fle;fle=fle->next) 
79         if (!strcmp(fle->name,fn)) return;
80
81   fle = malloc (sizeof (Filelist_ent));
82
83   strcpy (fle->name, fn);
84
85   fle->next = fl->head;
86   fl->head = fle;
87 }
88
89 void
90 filelist_free (Filelist * fl)
91 {
92   while (fl->head)
93     filelist_remove (fl, fl->head);
94   free (fl);
95 }
96
97 void filelist_print(Filelist *fl,FILE *f)
98 {
99 Filelist_ent *fle;
100 if (!fl) {
101   fprintf(f,"(empty list)\n");
102   return;
103 }
104   for (fle=fl->head;fle;fle=fle->next) 
105   fprintf(f,"%s\n",fle->name);
106 }
107
108
109
110
111 static int
112 chown_uucp (fd)
113      int fd;
114 {
115   static int uuid = -1, ugid;
116   struct passwd *pw;
117
118   if (uuid < 0)
119     {
120       if (pw = getpwnam ("uucp"))
121         {
122           uuid = pw->pw_uid;
123           ugid = pw->pw_gid;
124         }
125       else
126         {
127           return -1;
128         }
129     }
130   return fchown (fd, uuid, ugid);
131 }
132
133 int
134 lockfile_make (char *name)
135 {
136   char buf[1024], tmpfn[1024];
137   char *ptr;
138   int fd;
139   int i;
140
141   strcpy (tmpfn, name);
142
143   ptr = rindex (tmpfn, '/');
144   if (!ptr)
145     return -1;
146
147   ptr++;
148
149   ptr += sprintf (ptr, "LTMP.%d", getpid ());
150   *ptr = 0;
151
152   i = sprintf (buf, "%10d\n", getpid ());
153
154   unlink (tmpfn);
155   fd = open (tmpfn, O_WRONLY | O_CREAT | O_TRUNC, 0444);
156   if (fd < 0)
157     {
158       unlink (tmpfn);
159       return -1;
160     }
161
162   write (fd, buf, i);
163   fchmod (fd, 044);
164   if (chown_uucp (fd))
165     {
166       close (fd);
167       unlink (tmpfn);
168       return -1;
169     }
170
171   close (fd);
172
173   if (link (tmpfn, name) < 0)
174     {
175       unlink (tmpfn);
176       return -1;
177     }
178
179   unlink (tmpfn);
180   return 0;
181 }
182
183
184 void
185 lockfile_add_places (Filelist * fl, char *leaf)
186 {
187   char buf[1024];
188   struct stat stbuf;
189   char *lock_dirs[] =
190     { "/var/lock/uucp", "/var/spool/lock", "/var/spool/uucp", "/etc/locks",
191     "/usr/spool/uucp", "/var/spool/locks", "/usr/spool/lock",
192       "/usr/spool/locks",
193     "/usr/spool/uucp/LCK"
194   };
195   int i;
196
197   for (i = 0; i < (sizeof (lock_dirs) / sizeof (char *)); ++i)
198     {
199       if (stat (lock_dirs[i], &stbuf))
200         continue;
201       strcpy (buf, lock_dirs[i]);
202       strcat (buf, "/");
203       strcat (buf, leaf);
204       filelist_add (fl, buf);
205     }
206 }
207
208
209 static void
210 do_tedious_mangling (Filelist * fl, char *buf, char *ptr, char inv, int lower)
211 {
212   while (*ptr)
213     {
214       if (lower && (*ptr >= 'A') && (*ptr <= 'Z'))
215         *ptr |= 32;
216       if (*ptr == '/')
217         *ptr = inv;
218       ptr++;
219     }
220
221   lockfile_add_places (fl, buf);
222 }
223
224
225 void
226 lockfile_regularize_and_add (Filelist * fl, char *leaf)
227 {
228   char buf[1024] = "LCK..";
229   char *ptr;
230
231   if (*leaf == '/')
232     leaf++;
233
234   ptr = buf;
235   while (*ptr)
236     ptr++;
237
238   strcpy (ptr, leaf);
239   do_tedious_mangling (fl, buf, ptr, '_', 0);
240   strcpy (ptr, leaf);
241   do_tedious_mangling (fl, buf, ptr, '_', 1);
242   strcpy (ptr, leaf);
243   do_tedious_mangling (fl, buf, ptr, '.', 0);
244   strcpy (ptr, leaf);
245   do_tedious_mangling (fl, buf, ptr, '.', 1);
246 }
247
248 void
249 lockfile_add_name_from_path (Filelist * fl, char *file)
250 {
251   char *ptr = file;
252
253
254   if (*ptr == '/')
255     ptr++;
256   lockfile_regularize_and_add (fl, ptr);
257
258   if (!strncmp (ptr, "dev/", 4))
259     {
260       ptr += 4;
261       lockfile_regularize_and_add (fl, ptr);
262     }
263
264 }
265
266 void
267 lockfile_add_name_from_dev (Filelist * fl, dev_t dev)
268 {
269   char buf[1024];
270   sprintf (buf, "LCK.%03d.%03d", major (dev), minor (dev));
271   lockfile_add_places (fl, buf);
272 }
273
274 void
275 lockfile_check_dir_for_dev (Filelist * fl, char *dir, dev_t dev)
276 {
277   char buf[1024];
278   struct stat ent_stat;
279   struct dirent *de;
280   DIR *d;
281
282   d = opendir (dir);
283
284   if (!d) return;
285
286    while ((de = readdir (d)))
287     {
288       strcpy (buf, dir);
289       strcat (buf, de->d_name);
290
291       if (stat (buf, &ent_stat))
292         continue;
293       if (!S_ISCHR (ent_stat.st_mode))
294         continue;
295       if (ent_stat.st_rdev != dev)
296         continue;
297
298       lockfile_add_name_from_path (fl, buf);
299
300     }
301   closedir (d);
302 }
303
304 Filelist *
305 lockfile_make_list(char *device)
306 {
307   struct stat dev_stat;
308   Filelist *ret = NULL;
309
310
311   if (stat (device, &dev_stat))
312     return ret;
313   if (!S_ISCHR (dev_stat.st_mode))
314     return ret;
315
316   ret = filelist_new ();
317
318   lockfile_add_name_from_dev (ret, dev_stat.st_rdev);
319
320   lockfile_add_name_from_path (ret, device);
321
322   lockfile_check_dir_for_dev (ret, "/dev/", dev_stat.st_rdev);
323   lockfile_check_dir_for_dev (ret, "/dev/usb/", dev_stat.st_rdev);
324   lockfile_check_dir_for_dev (ret, "/dev/tts/", dev_stat.st_rdev);
325
326   return ret;
327 }
328
329 void lockfile_remove_stale(Filelist *fl)
330 {
331
332
333 }
334
335
336 Filelist *lockfile_lock(Filelist *fl)
337 {
338 Filelist *ret;
339 Filelist_ent *fle;
340
341 ret=filelist_new();
342
343 lockfile_remove_stale(fl);
344
345 for (fle=fl->head;fle;fle=fle->next) {
346         if (lockfile_make(fle->name)) {
347                 fprintf(stderr,"Failed to get lockfile %s\n",fle->name);
348                 filelist_free(ret);
349                 return NULL;
350         }
351         filelist_add(ret,fle->name);
352 }
353
354 return ret;
355 }
356
357 #if 1
358 int main(int argc,char *argv[])
359 {
360 Filelist *fl=lockfile_make_list("/dev/ttyS0");
361 Filelist *fll;
362 Filelist_ent *fle;
363
364 filelist_print(fl,stdout);
365
366 fll=lockfile_lock(fl);
367
368 filelist_print(fll,stdout);
369 }
370 #endif
371