xref: /freebsd/lib/libcuse/cuse_lib.c (revision d4eeb02986980bf33dd56c41ceb9fc5f180c0d47)
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 }
796