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