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 }