chiark / gitweb /
6c3da7a579ac052ac903a2da2fdec33fa52e51a0
[disorder] / server / mount.c
1 /*
2  * This file is part of DisOrder.
3  * Copyright (C) 2010 Richard Kettlewell
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * 
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 /** @file server/mount.c
19  * @brief Periodically check for devices being mounted and unmounted
20  */
21 #include "disorder-server.h"
22 #if HAVE_GETFSSTAT
23 # include <sys/param.h>
24 # include <sys/ucred.h>
25 # include <sys/mount.h>
26 #endif
27
28 #if HAVE_GETFSSTAT
29 static int compare_fsstat(const void *av, const void *bv) {
30   const struct statfs *a = av, *b = bv;
31   int c;
32  
33   c = memcmp(&a->f_fsid, &b->f_fsid, sizeof a->f_fsid);
34   if(c)
35     return c;
36   c = strcmp(a->f_mntonname, b->f_mntonname);
37   if(c)
38     return c;
39   return 0;
40 }
41 #endif
42
43 #if HAVE_GETFSSTAT || defined PATH_MTAB
44 void periodic_mount_check(ev_source *ev_) {
45   if(!config->mount_rescan)
46     return;
47 #if HAVE_GETFSSTAT
48   /* On OS X, we keep track of the hash of the kernel's mounted
49    * filesystem list */
50   static int first = 1;
51   static unsigned char last[20];
52   unsigned char *current;
53   int nfilesystems, space;
54   struct statfs *buf;
55   gcrypt_hash_handle h;
56   gcry_error_t e;
57
58   space = getfsstat(NULL, 0, MNT_NOWAIT);
59   buf = xcalloc(space, sizeof *buf);
60   nfilesystems = getfsstat(buf, space * sizeof *buf, MNT_NOWAIT);
61   if(nfilesystems > space)
62     // The array grew between check and use!  We just give up and try later.
63     return;
64   // Put into order so we get a bit of consistency
65   qsort(buf, nfilesystems, sizeof *buf, compare_fsstat);
66   if((e = gcry_md_open(&h, GCRY_MD_SHA1, 0))) {
67     disorder_error(0, "gcry_md_open: %s", gcry_strerror(e));
68     return;
69   }
70   for(int n = 0; n < nfilesystems; ++n) {
71     gcry_md_write(h, &buf[n].f_fsid, sizeof buf[n].f_fsid);
72     gcry_md_write(h, buf[n].f_mntonname, 1 + strlen(buf[n].f_mntonname));
73   }
74   current = gcry_md_read(h, GCRY_MD_SHA1);
75   if(!first && memcmp(current, last, sizeof last))
76     trackdb_rescan(ev_, 1/*check*/, 0, 0);
77   memcpy(last, current, sizeof last);
78   first = 0;
79   gcry_md_close(h);
80 #elif defined PATH_PROC_MOUNTS
81   /* On Linux we hash /proc/mounts */
82   static int first = 1;
83   static unsigned char last[20];
84
85   unsigned char *current;
86   int fd = -1, n;
87   gcrypt_hash_handle h = 0;
88   gcry_error_t e;
89   char buffer[1024];
90
91   if((e = gcry_md_open(&h, GCRY_MD_SHA1, 0))) {
92     disorder_error(0, "gcry_md_open: %s", gcry_strerror(e));
93     goto done;
94   }
95   if((fd = open(PATH_PROC_MOUNTS, O_RDONLY)) < 0) {
96     disorder_error(errno, "open %s", PATH_PROC_MOUNTS);
97     goto done;
98   }
99   for(;;) {
100     n = read(fd, buffer, sizeof buffer);
101     if(n > 0)
102       gcry_md_write(h, buffer, n);
103     else if(n == 0)
104       break;
105     else if(errno != EINTR) {
106       disorder_error(errno, "reading %s", PATH_PROC_MOUNTS);
107       goto done;
108     }
109   }
110   current = gcry_md_read(h, GCRY_MD_SHA1);
111   if(!first && memcmp(current, last, sizeof last))
112     trackdb_rescan(ev_, 1/*check*/, 0, 0);
113   memcpy(last, current, sizeof last);
114   first = 0;
115  done:
116   if(h) gcry_md_close(h);
117   if(fd != -1) close(fd);
118 #elif defined PATH_MTAB
119   /* As a further alternative we track the modification time of /etc/mtab */
120   static time_t last_mount;
121   struct stat sb;
122   
123   if(stat(PATH_MTAB, &sb) >= 0) {
124     if(last_mount != 0 && last_mount != sb.st_mtime)
125       trackdb_rescan(ev_, 1/*check*/, 0, 0);
126     last_mount = sb.st_mtime;
127   }
128 #endif
129 }
130 #else
131 void periodic_mount_check(ev_source attribute((unused)) *ev_ ) {
132 }
133 #endif
134
135 /*
136 Local Variables:
137 c-basic-offset:2
138 comment-column:40
139 fill-column:79
140 indent-tabs-mode:nil
141 End:
142 */