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