1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2013 Damian Bogel.  All rights reserved.
  14  */
  15 
  16 #include <fcntl.h>
  17 #include <libfsd.h>
  18 #include <string.h>
  19 #include <stropts.h>
  20 #include <sys/debug.h>
  21 #include <sys/errno.h>
  22 #include <sys/fsd.h>
  23 #include <sys/stat.h>
  24 #include <sys/types.h>
  25 #include <unistd.h>
  26 
  27 
  28 /*
  29  * libfsd
  30  * Library used to drive the fsd pseudo-device driver.
  31  *
  32  * 1. Usage.
  33  * fsd_handle_t is used for every operation on the fsd driver. It is acquired by
  34  * a call to fsd_open(). Every handle must be released by calling fsd_close().
  35  *
  36  * A handle is a structure that contains data needed to drive the fsd and get
  37  * information about errors.
  38  *
  39  *
  40  * Basics:
  41  * A disturber is a hook for filesystem operations. There are different types of
  42  * disturbers, but the property that connects them is that EVERY program that
  43  * uses filesystem API should expect that kind of behaviour. Doing otherwise is
  44  * a bug and could lead to serious problems.
  45  * Omnipresent disturber is a hook that is being installed whenever a new vfs_t
  46  * is mounted.
  47  *
  48  *
  49  * Errors:
  50  * In almost all the functions (except fsd_close()) return value equal to -1
  51  * indicates that there was an error. Last error data is contained in the
  52  * handle in two fields: fsd_errno and errno.
  53  * fsd_errno could be one of EFSD_XXX. errno is nonzero if and only if fsd_errno
  54  * is set to EFSD_CANT_OPEN_DRIVER or EFSD_CANT_OPEN_MOUNTPOINT.
  55  * fsd_strerr() is used to get the error message from fsd_errno. errno should be
  56  * treated according to Intro(2).
  57  *
  58  * Handle management:
  59  * fsd_open()
  60  *      Returns a handle.
  61  *
  62  * fsd_close(handle)
  63  *      Destroys a handle.
  64  *
  65  *
  66  * Enabling/disabling fsd:
  67  * fsd_enable(handle)
  68  * fsd_disable(handle)
  69  *      When fsd is enabled, it cannot be detached from the system. Otherwise,
  70  *      it could be and all the information that the fsd contains could be lost.
  71  *      The client should keep the fsd enabled whenever he needs to. No
  72  *      operations on fsd could be made if it's not enabled.
  73  *
  74  *
  75  * Getting information:
  76  * fsd_get_info(handle, info)
  77  *      Used to retrieve information such as:
  78  *      * whether fsd is enabled (system-wide)
  79  *      * whether there is an omnipresent disturber installed
  80  *      * omnipresent disturber's parameters
  81  *      * count of disturbers installed
  82  *
  83  * fsd_get_list(handle, fslist, count)
  84  *      Gets a list of disturbers installed. count is the maximum count of
  85  *      entries that could be returned by the function to the user-allocated
  86  *      buffer. count is changed to min(count, number of disturbers installed).
  87  *      There is no error returned if the number of disturbers installed exceeds
  88  *      the user-provided count. It just gets the maximal allowed amount of
  89  *      informaton.
  90  *
  91  * fsd_get_param(handle, path, param)
  92  *      Gets disturber parameters from a filesystem of the file pointed by the
  93  *      path.
  94  *
  95  *
  96  * Installing/removing disturbers:
  97  * fsd_disturb(handle, path, param)
  98  *      Installs (or changes, if a disturber on this filesystem already exists)
  99  *      a disturber on a filesystem of the file pointed by the path.
 100  *
 101  * fsd_disturb_omni(handle, param)
 102  *      Installs (or changes, if an omnipresent disturber already exists) an
 103  *      omnipresent disturber. Only one omnipresent disturber exists at a time.
 104  *
 105  * fsd_disturb_off(handle, path)
 106  * fsd_disturb_omni_off(handle)
 107  *      Removes a disturber. It is guaranteed that after this function returns,
 108  *      the disturber won't change the behaviour of filesystem operations.
 109  *
 110  * 2. Multithreading.
 111  * It is safe to use the libfsd API concurrently.
 112  *
 113  * Error information is encapsulated in a handle, so it's the client's job to
 114  * properly share the handle between threads to preserve the consistency of
 115  * error data within a handle.
 116  */
 117 
 118 extern int errno;
 119 
 120 const char *
 121 fsd_strerr(int e)
 122 {
 123         switch (e) {
 124         case EFSD_NOERROR:
 125                 return ("no error");
 126         case EFSD_BAD_PARAM:
 127                 return ("incorrect disturbance parameters");
 128         case EFSD_INTERNAL:
 129                 return ("internal library error");
 130         case EFSD_NOT_ENABLED:
 131                 return ("fsd is not enabled");
 132         case EFSD_CANT_OPEN_DRIVER:
 133                 return ("cannot open fsd device");
 134         case EFSD_CANT_OPEN_MOUNTPOINT:
 135                 return ("cannot open mountpoint");
 136         case EFSD_ENTRY_NOT_FOUND:
 137                 return ("this filesystem is not being disturbed");
 138         case EFSD_FAULT:
 139                 return ("bad pointer");
 140         case EFSD_TOO_MANY_HOOKS:
 141                 return ("too many hooks");
 142         case EFSD_UNKNOWN_ERROR:
 143         default:
 144                 return ("unknown error");
 145         }
 146 }
 147 
 148 static int
 149 xlate_errno(int e)
 150 {
 151         switch (e) {
 152         case 0:
 153                 return (0);
 154         case (-1):
 155                 switch (errno) {
 156                 case 0:
 157                         return (EFSD_NOERROR);
 158                 case EFAULT:
 159                         return (EFSD_FAULT);
 160                 case ENOTTY:
 161                         return (EFSD_INTERNAL);
 162                 default:
 163                         return (EFSD_UNKNOWN_ERROR);
 164                 }
 165         case ENOTACTIVE:
 166                 return (EFSD_NOT_ENABLED);
 167         case ENOENT:
 168                 return (EFSD_ENTRY_NOT_FOUND);
 169         case EINVAL:
 170                 return (EFSD_BAD_PARAM);
 171         case EBADFD:
 172                 return (EFSD_INTERNAL);
 173         case EAGAIN:
 174                 return (EFSD_TOO_MANY_HOOKS);
 175         default:
 176                 return (EFSD_UNKNOWN_ERROR);
 177         }
 178 }
 179 
 180 static int
 181 ioctl_set_handle(fsd_handle_t *handle, int ioctlret)
 182 {
 183         handle->fsd_errno = xlate_errno(ioctlret);
 184         handle->errno = 0;
 185 
 186         if (handle->fsd_errno == 0)
 187                 return (0);
 188         else
 189                 return (-1);
 190 }
 191 
 192 int
 193 fsd_open(fsd_handle_t *handle)
 194 {
 195         if ((handle->fd = open(FSD_DEV_PATH, O_RDWR)) == -1) {
 196                 handle->fsd_errno = EFSD_CANT_OPEN_DRIVER;
 197                 handle->errno = errno;
 198                 return (-1);
 199         }
 200         return (0);
 201 }
 202 
 203 void
 204 fsd_close(fsd_handle_t *handle)
 205 {
 206         (void) close(handle->fd);
 207         handle->fd = -1;
 208 }
 209 
 210 
 211 int
 212 fsd_enable(fsd_handle_t *handle)
 213 {
 214         return (ioctl_set_handle(handle, ioctl(handle->fd, FSD_ENABLE)));
 215 
 216 }
 217 
 218 int
 219 fsd_disable(fsd_handle_t *handle)
 220 {
 221         return (ioctl_set_handle(handle, ioctl(handle->fd, FSD_DISABLE)));
 222 }
 223 
 224 int
 225 fsd_disturb(fsd_handle_t *handle, const char *mnt_path, fsd_t *param)
 226 {
 227         fsd_ioc_t ioc;
 228         int error;
 229 
 230         (void) memcpy(&ioc.fsdioc_dis.fsdd_param, param,
 231             sizeof (ioc.fsdioc_dis.fsdd_param));
 232 
 233         if ((ioc.fsdioc_dis.fsdd_mnt = open(mnt_path, O_RDONLY)) == -1) {
 234                 handle->fsd_errno = EFSD_CANT_OPEN_MOUNTPOINT;
 235                 handle->errno = errno;
 236                 return (-1);
 237         }
 238 
 239         error = ioctl(handle->fd, FSD_DISTURB, &ioc);
 240         (void) close(ioc.fsdioc_dis.fsdd_mnt);
 241         return (ioctl_set_handle(handle, error));
 242 }
 243 
 244 int
 245 fsd_disturb_off(fsd_handle_t *handle, const char *mnt_path)
 246 {
 247         fsd_ioc_t ioc;
 248         int error;
 249 
 250         if ((ioc.fsdioc_mnt = open(mnt_path, O_RDONLY)) == -1) {
 251                 handle->fsd_errno = EFSD_CANT_OPEN_MOUNTPOINT;
 252                 handle->errno = errno;
 253                 return (-1);
 254         }
 255 
 256         error = ioctl(handle->fd, FSD_DISTURB_OFF, &ioc);
 257         (void) close(ioc.fsdioc_mnt);
 258         return (ioctl_set_handle(handle, error));
 259 }
 260 
 261 int
 262 fsd_disturb_omni(fsd_handle_t *handle, fsd_t *param)
 263 {
 264         fsd_ioc_t ioc;
 265 
 266         (void) memcpy(&ioc.fsdioc_param, param, sizeof (ioc.fsdioc_param));
 267 
 268         return (ioctl_set_handle(handle, ioctl(handle->fd, FSD_DISTURB_OMNI,
 269             &ioc)));
 270 }
 271 
 272 int
 273 fsd_disturb_omni_off(fsd_handle_t *handle)
 274 {
 275         return (ioctl_set_handle(handle, ioctl(handle->fd,
 276             FSD_DISTURB_OMNI_OFF)));
 277 }
 278 
 279 int
 280 fsd_get_param(fsd_handle_t *handle, const char *mnt_path, fsd_t *param)
 281 {
 282         fsd_ioc_t ioc;
 283         int error;
 284         int mntfd;
 285 
 286         if ((ioc.fsdioc_mnt = open(mnt_path, O_RDONLY)) == -1) {
 287                 handle->fsd_errno = EFSD_CANT_OPEN_MOUNTPOINT;
 288                 handle->errno = errno;
 289                 return (-1);
 290         }
 291         mntfd = ioc.fsdioc_mnt;
 292 
 293         error = ioctl(handle->fd, FSD_GET_PARAM, &ioc);
 294         if (error == 0)
 295                 (void) memcpy(param, &ioc.fsdioc_param, sizeof (*param));
 296 
 297         (void) close(mntfd);
 298 
 299         return (ioctl_set_handle(handle, error));
 300 }
 301 
 302 int
 303 fsd_get_info(fsd_handle_t *handle, fsd_info_t *info)
 304 {
 305         fsd_ioc_t ioc;
 306         int error;
 307 
 308         error = ioctl(handle->fd, FSD_GET_INFO, &ioc);
 309         if (error == 0)
 310                 (void) memcpy(info, &ioc.fsdioc_info, sizeof (*info));
 311 
 312         return (ioctl_set_handle(handle, error));
 313 }
 314 
 315 int
 316 fsd_get_list(fsd_handle_t *handle, fsd_fs_t *fslist, int *count)
 317 {
 318         fsd_ioc_t ioc;
 319         int error;
 320 
 321         ioc.fsdioc_list.listp = (uintptr_t)fslist;
 322         ioc.fsdioc_list.count = *count;
 323 
 324         error = ioctl(handle->fd, FSD_GET_LIST, &ioc);
 325         *count = ioc.fsdioc_list.count;
 326         return (ioctl_set_handle(handle, error));
 327 }