]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libcuse/cuse_lib.c
libcbor: update to 0.10.2
[FreeBSD/FreeBSD.git] / lib / libcuse / cuse_lib.c
1 /* $FreeBSD$ */
2 /*-
3  * Copyright (c) 2010-2022 Hans Petter Selasky. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <stdio.h>
28 #include <stdint.h>
29 #include <pthread.h>
30 #include <signal.h>
31 #include <unistd.h>
32 #include <string.h>
33 #include <errno.h>
34 #include <stdlib.h>
35 #include <stdarg.h>
36
37 #include <sys/types.h>
38 #include <sys/queue.h>
39 #include <sys/fcntl.h>
40 #include <sys/mman.h>
41 #include <sys/param.h>
42
43 #include <fs/cuse/cuse_ioctl.h>
44
45 #include "cuse.h"
46
47 int     cuse_debug_level;
48
49 #ifdef HAVE_DEBUG
50 static const char *cuse_cmd_str(int cmd);
51
52 #define DPRINTF(...) do {                       \
53         if (cuse_debug_level != 0)              \
54                 printf(__VA_ARGS__);            \
55 } while (0)
56 #else
57 #define DPRINTF(...) do { } while (0)
58 #endif
59
60 struct cuse_vm_allocation {
61         uint8_t *ptr;
62         uint32_t size;
63 };
64
65 struct cuse_dev_entered {
66         TAILQ_ENTRY(cuse_dev_entered) entry;
67         pthread_t thread;
68         void   *per_file_handle;
69         struct cuse_dev *cdev;
70         int     cmd;
71         int     is_local;
72         int     got_signal;
73 };
74
75 struct cuse_dev {
76         TAILQ_ENTRY(cuse_dev) entry;
77         const struct cuse_methods *mtod;
78         void   *priv0;
79         void   *priv1;
80 };
81
82 static int f_cuse = -1;
83
84 static pthread_mutex_t m_cuse;
85 static TAILQ_HEAD(, cuse_dev) h_cuse __guarded_by(m_cuse);
86 static TAILQ_HEAD(, cuse_dev_entered) h_cuse_entered __guarded_by(m_cuse);
87 static struct cuse_vm_allocation a_cuse[CUSE_ALLOC_UNIT_MAX]
88     __guarded_by(m_cuse);
89
90 #define CUSE_LOCK() \
91         pthread_mutex_lock(&m_cuse)
92
93 #define CUSE_UNLOCK() \
94         pthread_mutex_unlock(&m_cuse)
95
96 int
97 cuse_init(void)
98 {
99         pthread_mutexattr_t attr;
100
101         f_cuse = open("/dev/cuse", O_RDWR);
102         if (f_cuse < 0) {
103                 if (feature_present("cuse") == 0)
104                         return (CUSE_ERR_NOT_LOADED);
105                 else
106                         return (CUSE_ERR_INVALID);
107         }
108         pthread_mutexattr_init(&attr);
109         pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
110         pthread_mutex_init(&m_cuse, &attr);
111
112         TAILQ_INIT(&h_cuse);
113         TAILQ_INIT(&h_cuse_entered);
114
115         return (0);
116 }
117
118 int
119 cuse_uninit(void)
120 {
121         int f;
122
123         if (f_cuse < 0)
124                 return (CUSE_ERR_INVALID);
125
126         f = f_cuse;
127         f_cuse = -1;
128
129         close(f);
130
131         pthread_mutex_destroy(&m_cuse);
132
133         memset(a_cuse, 0, sizeof(a_cuse));
134
135         return (0);
136 }
137
138 unsigned long
139 cuse_vmoffset(void *_ptr)
140 {
141         uint8_t *ptr_min;
142         uint8_t *ptr_max;
143         uint8_t *ptr = _ptr;
144         unsigned long remainder;
145         unsigned long n;
146
147         CUSE_LOCK();
148         for (n = remainder = 0; n != CUSE_ALLOC_UNIT_MAX; n++) {
149                 if (a_cuse[n].ptr == NULL)
150                         continue;
151
152                 ptr_min = a_cuse[n].ptr;
153                 ptr_max = a_cuse[n].ptr + a_cuse[n].size - 1;
154
155                 if ((ptr >= ptr_min) && (ptr <= ptr_max)) {
156                         remainder = (ptr - ptr_min);
157                         break;
158                 }
159         }
160         CUSE_UNLOCK();
161
162         return ((n << CUSE_ALLOC_UNIT_SHIFT) + remainder);
163 }
164
165 void   *
166 cuse_vmalloc(unsigned size)
167 {
168         struct cuse_alloc_info info;
169         unsigned long pgsize;
170         unsigned long x;
171         unsigned long m;
172         unsigned long n;
173         void *ptr;
174         int error;
175
176         /* some sanity checks */
177         if (f_cuse < 0 || size < 1 || size > CUSE_ALLOC_BYTES_MAX)
178                 return (NULL);
179
180         memset(&info, 0, sizeof(info));
181
182         pgsize = getpagesize();
183         info.page_count = howmany(size, pgsize);
184
185         /* compute how many units the allocation needs */
186         m = howmany(size, 1 << CUSE_ALLOC_UNIT_SHIFT);
187         if (m == 0 || m > CUSE_ALLOC_UNIT_MAX)
188                 return (NULL);
189
190         CUSE_LOCK();
191         for (n = 0; n <= CUSE_ALLOC_UNIT_MAX - m; ) {
192                 if (a_cuse[n].size != 0) {
193                         /* skip to next available unit, depending on allocation size */
194                         n += howmany(a_cuse[n].size, 1 << CUSE_ALLOC_UNIT_SHIFT);
195                         continue;
196                 }
197                 /* check if there are "m" free units ahead */
198                 for (x = 1; x != m; x++) {
199                         if (a_cuse[n + x].size != 0)
200                                 break;
201                 }
202                 if (x != m) {
203                         /* skip to next available unit, if any */
204                         n += x + 1;
205                         continue;
206                 }
207                 /* reserve this unit by setting the size to a non-zero value */
208                 a_cuse[n].size = size;
209                 CUSE_UNLOCK();
210
211                 info.alloc_nr = n;
212
213                 error = ioctl(f_cuse, CUSE_IOCTL_ALLOC_MEMORY, &info);
214
215                 if (error == 0) {
216                         ptr = mmap(NULL, info.page_count * pgsize,
217                             PROT_READ | PROT_WRITE,
218                             MAP_SHARED, f_cuse, n << CUSE_ALLOC_UNIT_SHIFT);
219
220                         if (ptr != MAP_FAILED) {
221                                 CUSE_LOCK();
222                                 a_cuse[n].ptr = ptr;
223                                 CUSE_UNLOCK();
224
225                                 return (ptr);           /* success */
226                         }
227
228                         (void) ioctl(f_cuse, CUSE_IOCTL_FREE_MEMORY, &info);
229                 }
230
231                 CUSE_LOCK();
232                 a_cuse[n].size = 0;
233                 n++;
234         }
235         CUSE_UNLOCK();
236         return (NULL);                  /* failure */
237 }
238
239 int
240 cuse_is_vmalloc_addr(void *ptr)
241 {
242         int n;
243
244         if (f_cuse < 0 || ptr == NULL)
245                 return (0);             /* false */
246
247         CUSE_LOCK();
248         for (n = 0; n != CUSE_ALLOC_UNIT_MAX; n++) {
249                 if (a_cuse[n].ptr == ptr)
250                         break;
251         }
252         CUSE_UNLOCK();
253
254         return (n != CUSE_ALLOC_UNIT_MAX);
255 }
256
257 void
258 cuse_vmfree(void *ptr)
259 {
260         struct cuse_vm_allocation temp;
261         struct cuse_alloc_info info;
262         int error;
263         int n;
264
265         if (f_cuse < 0 || ptr == NULL)
266                 return;
267
268         CUSE_LOCK();
269         for (n = 0; n != CUSE_ALLOC_UNIT_MAX; n++) {
270                 if (a_cuse[n].ptr != ptr)
271                         continue;
272
273                 temp = a_cuse[n];
274
275                 CUSE_UNLOCK();
276
277                 munmap(temp.ptr, temp.size);
278
279                 memset(&info, 0, sizeof(info));
280
281                 info.alloc_nr = n;
282
283                 error = ioctl(f_cuse, CUSE_IOCTL_FREE_MEMORY, &info);
284
285                 if (error != 0) {
286                         /* ignore any errors */
287                         DPRINTF("Freeing memory failed: %d\n", errno);
288                 }
289                 CUSE_LOCK();
290
291                 a_cuse[n].ptr = NULL;
292                 a_cuse[n].size = 0;
293
294                 break;
295         }
296         CUSE_UNLOCK();
297 }
298
299 int
300 cuse_alloc_unit_number_by_id(int *pnum, int id)
301 {
302         int error;
303
304         if (f_cuse < 0)
305                 return (CUSE_ERR_INVALID);
306
307         *pnum = (id & CUSE_ID_MASK);
308
309         error = ioctl(f_cuse, CUSE_IOCTL_ALLOC_UNIT_BY_ID, pnum);
310         if (error)
311                 return (CUSE_ERR_NO_MEMORY);
312
313         return (0);
314
315 }
316
317 int
318 cuse_free_unit_number_by_id(int num, int id)
319 {
320         int error;
321
322         if (f_cuse < 0)
323                 return (CUSE_ERR_INVALID);
324
325         if (num != -1 || id != -1)
326                 num = (id & CUSE_ID_MASK) | (num & 0xFF);
327
328         error = ioctl(f_cuse, CUSE_IOCTL_FREE_UNIT_BY_ID, &num);
329         if (error)
330                 return (CUSE_ERR_NO_MEMORY);
331
332         return (0);
333 }
334
335 int
336 cuse_alloc_unit_number(int *pnum)
337 {
338         int error;
339
340         if (f_cuse < 0)
341                 return (CUSE_ERR_INVALID);
342
343         error = ioctl(f_cuse, CUSE_IOCTL_ALLOC_UNIT, pnum);
344         if (error)
345                 return (CUSE_ERR_NO_MEMORY);
346
347         return (0);
348 }
349
350 int
351 cuse_free_unit_number(int num)
352 {
353         int error;
354
355         if (f_cuse < 0)
356                 return (CUSE_ERR_INVALID);
357
358         error = ioctl(f_cuse, CUSE_IOCTL_FREE_UNIT, &num);
359         if (error)
360                 return (CUSE_ERR_NO_MEMORY);
361
362         return (0);
363 }
364
365 struct cuse_dev *
366 cuse_dev_create(const struct cuse_methods *mtod, void *priv0, void *priv1,
367     uid_t _uid, gid_t _gid, int _perms, const char *_fmt,...)
368 {
369         struct cuse_create_dev info;
370         struct cuse_dev *cdev;
371         va_list args;
372         int error;
373
374         if (f_cuse < 0)
375                 return (NULL);
376
377         cdev = malloc(sizeof(*cdev));
378         if (cdev == NULL)
379                 return (NULL);
380
381         memset(cdev, 0, sizeof(*cdev));
382
383         cdev->mtod = mtod;
384         cdev->priv0 = priv0;
385         cdev->priv1 = priv1;
386
387         memset(&info, 0, sizeof(info));
388
389         info.dev = cdev;
390         info.user_id = _uid;
391         info.group_id = _gid;
392         info.permissions = _perms;
393
394         va_start(args, _fmt);
395         vsnprintf(info.devname, sizeof(info.devname), _fmt, args);
396         va_end(args);
397
398         error = ioctl(f_cuse, CUSE_IOCTL_CREATE_DEV, &info);
399         if (error) {
400                 free(cdev);
401                 return (NULL);
402         }
403         CUSE_LOCK();
404         TAILQ_INSERT_TAIL(&h_cuse, cdev, entry);
405         CUSE_UNLOCK();
406
407         return (cdev);
408 }
409
410
411 void
412 cuse_dev_destroy(struct cuse_dev *cdev)
413 {
414         int error;
415
416         if (f_cuse < 0)
417                 return;
418
419         CUSE_LOCK();
420         TAILQ_REMOVE(&h_cuse, cdev, entry);
421         CUSE_UNLOCK();
422
423         error = ioctl(f_cuse, CUSE_IOCTL_DESTROY_DEV, &cdev);
424         if (error)
425                 return;
426
427         free(cdev);
428 }
429
430 void   *
431 cuse_dev_get_priv0(struct cuse_dev *cdev)
432 {
433         return (cdev->priv0);
434 }
435
436 void   *
437 cuse_dev_get_priv1(struct cuse_dev *cdev)
438 {
439         return (cdev->priv1);
440 }
441
442 void
443 cuse_dev_set_priv0(struct cuse_dev *cdev, void *priv)
444 {
445         cdev->priv0 = priv;
446 }
447
448 void
449 cuse_dev_set_priv1(struct cuse_dev *cdev, void *priv)
450 {
451         cdev->priv1 = priv;
452 }
453
454 int
455 cuse_wait_and_process(void)
456 {
457         pthread_t curr = pthread_self();
458         struct cuse_dev_entered *pe;
459         struct cuse_dev_entered enter;
460         struct cuse_command info;
461         struct cuse_dev *cdev;
462         int error;
463
464         if (f_cuse < 0)
465                 return (CUSE_ERR_INVALID);
466
467         error = ioctl(f_cuse, CUSE_IOCTL_GET_COMMAND, &info);
468         if (error)
469                 return (CUSE_ERR_OTHER);
470
471         cdev = info.dev;
472
473         CUSE_LOCK();
474         enter.thread = curr;
475         enter.per_file_handle = (void *)info.per_file_handle;
476         enter.cmd = info.command;
477         enter.is_local = 0;
478         enter.got_signal = 0;
479         enter.cdev = cdev;
480         TAILQ_INSERT_TAIL(&h_cuse_entered, &enter, entry);
481         CUSE_UNLOCK();
482
483         DPRINTF("cuse: Command = %d = %s, flags = %d, arg = 0x%08x, ptr = 0x%08x\n",
484             (int)info.command, cuse_cmd_str(info.command), (int)info.fflags,
485             (int)info.argument, (int)info.data_pointer);
486
487         switch (info.command) {
488         case CUSE_CMD_OPEN:
489                 if (cdev->mtod->cm_open != NULL)
490                         error = (cdev->mtod->cm_open) (cdev, (int)info.fflags);
491                 else
492                         error = 0;
493                 break;
494
495         case CUSE_CMD_CLOSE:
496
497                 /* wait for other threads to stop */
498
499                 while (1) {
500
501                         error = 0;
502
503                         CUSE_LOCK();
504                         TAILQ_FOREACH(pe, &h_cuse_entered, entry) {
505                                 if (pe->cdev != cdev)
506                                         continue;
507                                 if (pe->thread == curr)
508                                         continue;
509                                 if (pe->per_file_handle !=
510                                     enter.per_file_handle)
511                                         continue;
512                                 pe->got_signal = 1;
513                                 pthread_kill(pe->thread, SIGHUP);
514                                 error = CUSE_ERR_BUSY;
515                         }
516                         CUSE_UNLOCK();
517
518                         if (error == 0)
519                                 break;
520                         else
521                                 usleep(10000);
522                 }
523
524                 if (cdev->mtod->cm_close != NULL)
525                         error = (cdev->mtod->cm_close) (cdev, (int)info.fflags);
526                 else
527                         error = 0;
528                 break;
529
530         case CUSE_CMD_READ:
531                 if (cdev->mtod->cm_read != NULL) {
532                         error = (cdev->mtod->cm_read) (cdev, (int)info.fflags,
533                             (void *)info.data_pointer, (int)info.argument);
534                 } else {
535                         error = CUSE_ERR_INVALID;
536                 }
537                 break;
538
539         case CUSE_CMD_WRITE:
540                 if (cdev->mtod->cm_write != NULL) {
541                         error = (cdev->mtod->cm_write) (cdev, (int)info.fflags,
542                             (void *)info.data_pointer, (int)info.argument);
543                 } else {
544                         error = CUSE_ERR_INVALID;
545                 }
546                 break;
547
548         case CUSE_CMD_IOCTL:
549                 if (cdev->mtod->cm_ioctl != NULL) {
550                         error = (cdev->mtod->cm_ioctl) (cdev, (int)info.fflags,
551                             (unsigned int)info.argument, (void *)info.data_pointer);
552                 } else {
553                         error = CUSE_ERR_INVALID;
554                 }
555                 break;
556
557         case CUSE_CMD_POLL:
558                 if (cdev->mtod->cm_poll != NULL) {
559                         error = (cdev->mtod->cm_poll) (cdev, (int)info.fflags,
560                             (int)info.argument);
561                 } else {
562                         error = CUSE_POLL_ERROR;
563                 }
564                 break;
565
566         case CUSE_CMD_SIGNAL:
567                 CUSE_LOCK();
568                 TAILQ_FOREACH(pe, &h_cuse_entered, entry) {
569                         if (pe->cdev != cdev)
570                                 continue;
571                         if (pe->thread == curr)
572                                 continue;
573                         if (pe->per_file_handle !=
574                             enter.per_file_handle)
575                                 continue;
576                         pe->got_signal = 1;
577                         pthread_kill(pe->thread, SIGHUP);
578                 }
579                 CUSE_UNLOCK();
580                 break;
581
582         default:
583                 error = CUSE_ERR_INVALID;
584                 break;
585         }
586
587         DPRINTF("cuse: Command error = %d for %s\n",
588             error, cuse_cmd_str(info.command));
589
590         CUSE_LOCK();
591         TAILQ_REMOVE(&h_cuse_entered, &enter, entry);
592         CUSE_UNLOCK();
593
594         /* we ignore any sync command failures */
595         ioctl(f_cuse, CUSE_IOCTL_SYNC_COMMAND, &error);
596
597         return (0);
598 }
599
600 static struct cuse_dev_entered *
601 cuse_dev_get_entered(void)
602 {
603         struct cuse_dev_entered *pe;
604         pthread_t curr = pthread_self();
605
606         CUSE_LOCK();
607         TAILQ_FOREACH(pe, &h_cuse_entered, entry) {
608                 if (pe->thread == curr)
609                         break;
610         }
611         CUSE_UNLOCK();
612         return (pe);
613 }
614
615 void
616 cuse_dev_set_per_file_handle(struct cuse_dev *cdev, void *handle)
617 {
618         struct cuse_dev_entered *pe;
619
620         pe = cuse_dev_get_entered();
621         if (pe == NULL || pe->cdev != cdev)
622                 return;
623
624         pe->per_file_handle = handle;
625         ioctl(f_cuse, CUSE_IOCTL_SET_PFH, &handle);
626 }
627
628 void   *
629 cuse_dev_get_per_file_handle(struct cuse_dev *cdev)
630 {
631         struct cuse_dev_entered *pe;
632
633         pe = cuse_dev_get_entered();
634         if (pe == NULL || pe->cdev != cdev)
635                 return (NULL);
636
637         return (pe->per_file_handle);
638 }
639
640 void
641 cuse_set_local(int val)
642 {
643         struct cuse_dev_entered *pe;
644
645         pe = cuse_dev_get_entered();
646         if (pe == NULL)
647                 return;
648
649         pe->is_local = val;
650 }
651
652 #ifdef HAVE_DEBUG
653 static const char *
654 cuse_cmd_str(int cmd)
655 {
656         static const char *str[CUSE_CMD_MAX] = {
657                 [CUSE_CMD_NONE] = "none",
658                 [CUSE_CMD_OPEN] = "open",
659                 [CUSE_CMD_CLOSE] = "close",
660                 [CUSE_CMD_READ] = "read",
661                 [CUSE_CMD_WRITE] = "write",
662                 [CUSE_CMD_IOCTL] = "ioctl",
663                 [CUSE_CMD_POLL] = "poll",
664                 [CUSE_CMD_SIGNAL] = "signal",
665                 [CUSE_CMD_SYNC] = "sync",
666         };
667
668         if ((cmd >= 0) && (cmd < CUSE_CMD_MAX) &&
669             (str[cmd] != NULL))
670                 return (str[cmd]);
671         else
672                 return ("unknown");
673 }
674
675 #endif
676
677 int
678 cuse_get_local(void)
679 {
680         struct cuse_dev_entered *pe;
681
682         pe = cuse_dev_get_entered();
683         if (pe == NULL)
684                 return (0);
685
686         return (pe->is_local);
687 }
688
689 int
690 cuse_copy_out(const void *src, void *user_dst, int len)
691 {
692         struct cuse_data_chunk info;
693         struct cuse_dev_entered *pe;
694         int error;
695
696         if ((f_cuse < 0) || (len < 0))
697                 return (CUSE_ERR_INVALID);
698
699         pe = cuse_dev_get_entered();
700         if (pe == NULL)
701                 return (CUSE_ERR_INVALID);
702
703         DPRINTF("cuse: copy_out(%p,%p,%d), cmd = %d = %s\n",
704             src, user_dst, len, pe->cmd, cuse_cmd_str(pe->cmd));
705
706         if (pe->is_local) {
707                 memcpy(user_dst, src, len);
708         } else {
709                 info.local_ptr = (uintptr_t)src;
710                 info.peer_ptr = (uintptr_t)user_dst;
711                 info.length = len;
712
713                 error = ioctl(f_cuse, CUSE_IOCTL_WRITE_DATA, &info);
714                 if (error) {
715                         DPRINTF("cuse: copy_out() error = %d\n", errno);
716                         return (CUSE_ERR_FAULT);
717                 }
718         }
719         return (0);
720 }
721
722 int
723 cuse_copy_in(const void *user_src, void *dst, int len)
724 {
725         struct cuse_data_chunk info;
726         struct cuse_dev_entered *pe;
727         int error;
728
729         if ((f_cuse < 0) || (len < 0))
730                 return (CUSE_ERR_INVALID);
731
732         pe = cuse_dev_get_entered();
733         if (pe == NULL)
734                 return (CUSE_ERR_INVALID);
735
736         DPRINTF("cuse: copy_in(%p,%p,%d), cmd = %d = %s\n",
737             user_src, dst, len, pe->cmd, cuse_cmd_str(pe->cmd));
738
739         if (pe->is_local) {
740                 memcpy(dst, user_src, len);
741         } else {
742                 info.local_ptr = (uintptr_t)dst;
743                 info.peer_ptr = (uintptr_t)user_src;
744                 info.length = len;
745
746                 error = ioctl(f_cuse, CUSE_IOCTL_READ_DATA, &info);
747                 if (error) {
748                         DPRINTF("cuse: copy_in() error = %d\n", errno);
749                         return (CUSE_ERR_FAULT);
750                 }
751         }
752         return (0);
753 }
754
755 struct cuse_dev *
756 cuse_dev_get_current(int *pcmd)
757 {
758         struct cuse_dev_entered *pe;
759
760         pe = cuse_dev_get_entered();
761         if (pe == NULL) {
762                 if (pcmd != NULL)
763                         *pcmd = 0;
764                 return (NULL);
765         }
766         if (pcmd != NULL)
767                 *pcmd = pe->cmd;
768         return (pe->cdev);
769 }
770
771 int
772 cuse_got_peer_signal(void)
773 {
774         struct cuse_dev_entered *pe;
775
776         pe = cuse_dev_get_entered();
777         if (pe == NULL)
778                 return (CUSE_ERR_INVALID);
779
780         if (pe->got_signal)
781                 return (0);
782
783         return (CUSE_ERR_OTHER);
784 }
785
786 void
787 cuse_poll_wakeup(void)
788 {
789         int error = 0;
790
791         if (f_cuse < 0)
792                 return;
793
794         ioctl(f_cuse, CUSE_IOCTL_SELWAKEUP, &error);
795 }