"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 }