"Fossies" - the Fresh Open Source Software Archive 
Member "shake-1.0/linux.c" (15 Nov 2014, 8725 Bytes) of package /linux/privat/shake-1.0.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "linux.c" see the
Fossies "Dox" file reference documentation.
1 /***************************************************************************/
2 /* Copyright (C) 2006-2011 Brice Arnould. */
3 /* */
4 /* This file is part of ShaKe. */
5 /* */
6 /* ShaKe is free software; you can redistribute it and/or modify */
7 /* it under the terms of the GNU General Public License as published by */
8 /* the Free Software Foundation; either version 3 of the License, or */
9 /* (at your option) any later version. */
10 /* */
11 /* This program is distributed in the hope that it will be useful, */
12 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
13 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
14 /* GNU General Public License for more details. */
15 /* */
16 /* You should have received a copy of the GNU General Public License */
17 /* along with this program. If not, see <http://www.gnu.org/licenses/>. */
18 /***************************************************************************/
19
20 #include "linux.h"
21
22 #include <stdlib.h>
23 #include <stdio.h> // snprintf
24 #include <limits.h> // CHAR_BIT
25 #include <time.h> // time, time_t
26 #include <assert.h> // assert
27 #include <errno.h> // errno
28 #include <error.h> // error()
29 #include <fcntl.h> // fcntl()
30 #include <signal.h> // sigaction()
31 #include <unistd.h> // fcntl()
32 #include <attr/attributes.h> // attr_setf,
33 #include <sys/ioctl.h> // ioctl()
34 #include <linux/fs.h> // FIBMAP, FIGETBSZ
35 #include <arpa/inet.h> // htonl, ntohl
36
37 /* The following try to hide Linux-specific leases behind an interface
38 * similar to Posix locks.
39 * It does a lot of thread-unsafe black magic.
40 */
41
42 #define SIGLOCKEXPIRED OS_RESERVED_SIGNAL
43 #define MAX_LOCKED_FDS 2 // Never greater than 1
44
45 /* Describe locks
46 */
47 struct lock_desc
48 {
49 const char *filename;
50 int fd;
51 bool write;
52 };
53
54 /* All the currently managed locks (thread-unsafe, would require a mutex)
55 */
56 struct lock_desc LOCKS[MAX_LOCKED_FDS];
57
58 /* The current temporary file
59 */
60 const char *TEMPFILE;
61
62 /* Return the position of the given fd in LOCKS or a position for the
63 * invalid fd ( -1 ) if there is no such position
64 * We are sure it exists because there can only be one locked file
65 * and LOCKS has a size of 2.
66 */
67 static int
68 locate_lock (int searchedfd)
69 {
70 int invalidfd_pos = -1;
71 for (int i = 0; i < MAX_LOCKED_FDS; i++)
72 if (LOCKS[i].fd == searchedfd)
73 return i;
74 else if (LOCKS[i].fd == -1)
75 invalidfd_pos = i;
76 assert (invalidfd_pos >= 0);
77 return invalidfd_pos;
78 }
79
80 /* Called when a lease is being cancelled
81 */
82 static void
83 handle_broken_locks (int sig, siginfo_t * info, void *ignored)
84 {
85 assert (SIGLOCKEXPIRED == sig), assert (ignored);
86 int fd = info->si_fd;
87 int pos = locate_lock (fd);
88 assert (LOCKS[pos].fd != -1);
89 if (LOCKS[pos].write)
90 error (0, 0,
91 "%s: Another program is trying to access the file; "
92 "if shaking takes more than lease-break-time seconds "
93 "shake will be killed; if this happens a backup will be "
94 "available in '%s'", LOCKS[pos].filename, TEMPFILE);
95 else
96 {
97 // Cancel this lock
98 LOCKS[pos].fd = -1;
99 error (0, 0, "%s: concurent accesses", LOCKS[pos].filename);
100 }
101 }
102
103 int
104 os_specific_setup (const char *tempfile)
105 {
106 /* Initialize globals */
107 TEMPFILE = tempfile;
108 for (int i = 0; i < MAX_LOCKED_FDS; i++)
109 LOCKS[i].fd = -1;
110 /* Setup SIGLOCKEXPIRED handler */
111 struct sigaction sa;
112 sa.sa_flags = SA_SIGINFO;
113 sa.sa_sigaction = handle_broken_locks;
114 return sigaction (SIGLOCKEXPIRED, &sa, NULL);
115 }
116
117 int
118 readlock_file (int fd, const char *filename)
119 {
120 int pos = locate_lock (fd);
121 assert (LOCKS[pos].fd == -1);
122 // Technically all our locks are write leases
123 if (fcntl (fd, F_SETLEASE, F_WRLCK) != 0)
124 return -1;
125 if (fcntl (fd, F_SETSIG, SIGLOCKEXPIRED) != 0)
126 return -1;
127 /* Register the lock in LOCKS */
128 {
129 LOCKS[pos].filename = filename;
130 LOCKS[pos].fd = fd;
131 LOCKS[pos].write = false;
132 }
133 return 0;
134 }
135
136 int
137 readlock_to_writelock (int fd)
138 {
139 int pos = locate_lock (fd);
140 if (0 > LOCKS[pos].fd)
141 return -1; // The lock has been canceled
142 LOCKS[pos].write = true;
143 return 0;
144 }
145
146 int
147 unlock_file (int fd)
148 {
149 int pos = locate_lock (fd);
150 if (0 > LOCKS[pos].fd)
151 return -1;
152 LOCKS[pos].fd = -1;
153 // TODO(unbrice): This line is so as to help debugging unlock_file()
154 // remove it in a few months.
155 errno = 0;
156 return fcntl (fd, F_SETLEASE, F_UNLCK);
157 }
158
159 bool
160 is_locked (int fd)
161 {
162 return LOCKS[locate_lock (fd)].fd >= 0;
163 }
164
165
166 /* could make an estimation of the required size, but should'nt because attr_setf
167 * set fixed size attributes, so it would cause problems when moving the disk
168 */
169 #define DATE_SIZE sizeof(uint32_t) // TODO: change this value before 2107
170
171 int
172 set_ptime (int fd)
173 {
174 assert (fd > -1);
175 uint32_t date = htonl ((uint32_t) time (NULL));
176 return attr_setf (fd, "shake.ptime", (char *) &date, DATE_SIZE,
177 ATTR_DONTFOLLOW);
178 }
179
180 time_t
181 get_ptime (int fd)
182 {
183 assert (fd > -1);
184 uint32_t date;
185 int size = DATE_SIZE;
186 if (-1 ==
187 attr_getf (fd, "shake.ptime", (char *) &date, &size, ATTR_DONTFOLLOW))
188 return (time_t) - 1;
189 date = ntohl (date);
190 if (date > time (NULL))
191 return (time_t) - 1;
192 return (time_t) date;
193 }
194
195
196 int
197 get_testimony (struct accused *a, struct law *l)
198 {
199 const size_t BUFFSTEP = 32;
200 /* General stats */
201 uint physbsize;
202 int crumbsize;
203 /* Framents logs */
204 llint *sizelog = NULL, *poslog = NULL; // Framgents sizes and positions
205 unsigned int logs_pos = 0; // Position in logs
206 /* Convert sizes in number of physical blocks */
207 {
208 if (-1 == ioctl (a->fd, FIGETBSZ, &physbsize))
209 {
210 error (0, errno, "%s: FIGETBSZ() failed", a->name);
211 return -1;
212 }
213 a->blocks = (a->size + physbsize - 1) / physbsize;
214 crumbsize = (int) ((double) a->size * l->crumbratio);
215 }
216 /* Create the log of fragment, terminated by <-1,-1> */
217 if (l->verbosity >= 3)
218 {
219 sizelog = malloc (BUFFSTEP * sizeof (*sizelog));
220 poslog = malloc (BUFFSTEP * sizeof (*poslog));
221 if (!sizelog || !poslog)
222 error (1, errno, "%s: malloc() failed", a->name);
223 sizelog[logs_pos] = -1;
224 poslog[logs_pos] = -1;
225 }
226 /* FIBMAP return physical block's position. We use it to detect start and end
227 * of fragments, by checking if the physical position of a block is not
228 * adjacent to the previous one.
229 * Please refer to comp.os.linux.development.system for information about
230 * FIBMAP (or ask me but I don't know anything which is not in this file).
231 */
232 {
233 llint physpos = 0, prevphyspos = 0;
234 uint fragsize = 0;
235 for (int i = 0; i < a->blocks; i++)
236 {
237 if (INT_MAX == i)
238 break; // The file is too large for FIBMAP
239 /* Query the physical pos of the i-nth block */
240 prevphyspos = physpos;
241 physpos = i;
242 if (-1 == ioctl (a->fd, FIBMAP, &physpos))
243 {
244 error (0, errno, "%s: FIBMAP failed", a->name);
245 return -1;
246 }
247 physpos = physpos * physbsize;
248 /* workaround reiser4 bug fixed 2006-08-27, TODO : remove */
249 if (physpos < 0)
250 {
251 error (0, 0, "ReiserFS4 bug : UPDATE to at least 2006-08-27");
252 physpos = 0;
253 }
254 /* physpos == 0 if sparse file */
255 if (physpos)
256 {
257 if (!a->start)
258 a->start = physpos;
259 a->end = physpos;
260 /* Check if we have a new fragment, */
261 if (llabs (physpos - prevphyspos) > MAGICLEAP)
262 {
263 /* log it */
264 if (l->verbosity >= 3)
265 {
266 /* Periodically enlarge the log */
267 if (0 == (logs_pos + 2) % BUFFSTEP)
268 {
269 size_t nsize =
270 (logs_pos + 2 + BUFFSTEP) * sizeof (*sizelog);
271 sizelog = realloc (sizelog, nsize);
272 poslog = realloc (poslog, nsize);
273 if (!sizelog || !poslog)
274 error (1, errno, "%s: malloc() failed", a->name);
275 }
276 /* Record the pos of the new frag */
277 poslog[logs_pos] = physpos;
278 /* Record the size of the old frag */
279 if (logs_pos)
280 sizelog[logs_pos - 1] = fragsize;
281 logs_pos++;
282 }
283 if (fragsize && fragsize < crumbsize)
284 a->crumbc++;
285 a->fragc++;
286 fragsize = 0;
287 }
288 }
289 fragsize += physbsize;
290 }
291 /* Record the last size, and close the log */
292 if (l->verbosity >= 3 && fragsize)
293 {
294 if (logs_pos)
295 sizelog[logs_pos - 1] = fragsize;
296 poslog[logs_pos] = -1;
297 sizelog[logs_pos] = -1;
298 a->poslog = poslog;
299 a->sizelog = sizelog;
300 }
301 }
302 return 0;
303 }