3 ** Summary : Simple POSIX system call driver
5 ** NOTICE: This file was generated by the tools of the Erlang Driver
6 ** toolkit. Do not edit this file by hand unless you know
9 ** Copyright (c) 2003, Scott Lystig Fritchie. All rights reserved.
10 ** See the file "../LICENSE" for license details.
14 ** QQQ Before I forget yet again to write this down...
16 ** ... the valmap ID assignment has a weakness that should be fixed
17 ** sometime in the future. The weakness is that reusing the array
18 ** indexes could result in Erlang being able to access a later
19 ** incarnation of a valmap table entry by simply remembering a
20 ** previous valmap {valmap_blah, Integer} and resending it to the
21 ** driver, hoping to get (un)lucky.
23 ** The solution would be to choose a valmap index from a larger, very
24 ** unlikely to repeat set, and use a mapping data structure less naive
27 ** QQQ cannot pass references from driver -> Erlang! Gah!
34 #include <sys/types.h>
36 #ifdef DRIVER_USING_PTHREADS
38 #else /* DRIVER_USING_PTHREADS */
39 #define pthread_self() 0
40 #endif /* DRIVER_USING_PTHREADS */
42 /* TODO: Add additional system & local header file #includes */
44 #include <erl_driver.h>
45 #include <erl_driver_tk.h>
47 /* <verbatim place="top_cpp_stuff"> */
54 #include <sys/types.h>
57 /* BSD-specific? (for NGROUPS_MAX) #include <sys/syslimits.h> */
60 #define NGROUPS_MAX 64 /* Big, but we'll be safe */
61 #endif /* !NGROUPS_MAX */
63 #include <posix_drv.h>
67 /* </verbatim --place="top_cpp_stuff"--> */
69 /* Last, but not least.... */
70 #include <posix_drv.h>
73 static ErlDrvTermData am_ok
;
74 static ErlDrvTermData am_error
;
75 static ErlDrvTermData am_badarg
;
76 static ErlDrvTermData am_enomem
;
77 static ErlDrvTermData am_unknown
;
78 static ErlDrvTermData am_stat
;
79 static ErlDrvTermData am_passwd
;
80 static ErlDrvTermData am_group
;
82 static int default_async_calls
= 0;
84 /* This variable may be set only by pipe-main! */
85 int pipe_driver_p
= 0;
88 ** TODO: Define any other Erlang terms this driver may return.
91 /* Function prototypes */
93 ErlDrvEntry
*driver_init(void *); /* Do not change name! */
94 static int _init(void);
95 static ErlDrvData
_start(ErlDrvPort port
, char *command
);
96 static void _stop(ErlDrvData drv_data
);
97 static void _output(ErlDrvData drv_data
, char *buf
, int len
);
98 static int _control(ErlDrvData drv_data
, unsigned int command
, char *buf
, int len
, char **rbuf
, int rlen
);
99 static void _outputv(ErlDrvData drv_data
, ErlIOVec
*ev
);
100 static void _ready_async(ErlDrvData drv_data
, ErlDrvThreadData thread_data
);
102 void *sys_alloc(size_t);
103 void *sys_realloc(void *, size_t);
104 void sys_free(void *);
106 static void invoke__getgid(void *data
);
107 static void invoke__getegid(void *data
);
108 static void invoke__getgrnam(void *data
);
109 static void invoke__getgrgid(void *data
);
110 static void invoke__getgroups(void *data
);
111 static void invoke__getpwnam(void *data
);
112 static void invoke__getpwuid(void *data
);
113 static void invoke__getuid(void *data
);
114 static void invoke__geteuid(void *data
);
115 static void invoke__getlogin(void *data
);
116 static void invoke__getpgrp(void *data
);
117 static void invoke__getppid(void *data
);
118 static void invoke__getsid(void *data
);
119 static void invoke__kill(void *data
);
120 static void invoke__lstat(void *data
);
121 static void invoke__mkfifo(void *data
);
122 static void invoke__mknod(void *data
);
123 static void invoke__umask(void *data
);
125 static int reply_xtra_stat(descriptor_t
*, callstate_t
*);
126 static int reply_xtra_passwd(descriptor_t
*, callstate_t
*);
127 static int reply_xtra_group(descriptor_t
*, callstate_t
*);
128 static int reply_xtra_getgroups(descriptor_t
*, callstate_t
*);
131 static int reply_ok(descriptor_t
*desc
);
132 static int reply_ok_num(descriptor_t
*desc
, unsigned long num
);
133 static int reply_ok_binary(descriptor_t
*desc
, char *p
, int, int);
134 static int reply_ok_valmap(descriptor_t
*, ErlDrvTermData
, unsigned long);
135 static int reply_error(descriptor_t
*desc
, int errnum
);
136 static int reply_error_atom(descriptor_t
*, ErlDrvTermData
);
138 static int reply_tag_ok(descriptor_t
*desc
, unsigned short tag
);
139 static int reply_tag_error(descriptor_t
*desc
, unsigned short tag
, int errnum
);
142 static ErlDrvEntry _driver_entry
= {
146 _output
, /* output */
147 NULL
, /* ready_input */
148 NULL
, /* ready_output */
149 "posix_drv", /* driver_name */
152 _control
, /* control */
154 _outputv
, /* outputv */
155 _ready_async
, /* ready_async */
161 ** All dynamically-loadable driver libraries must contain a driver_init().
165 driver_init(void *handle
)
168 _driver_entry
.handle
= handle
;
169 return &_driver_entry
;
175 am_ok
= driver_mk_atom("ok");
176 am_error
= driver_mk_atom("error");
177 am_badarg
= driver_mk_atom("badarg");
178 am_enomem
= driver_mk_atom("enomem");
179 am_unknown
= driver_mk_atom("unknown");
180 am_stat
= driver_mk_atom("stat");
181 am_passwd
= driver_mk_atom("passwd");
182 am_group
= driver_mk_atom("group");
184 /* TODO: Take care of other first-time initialization tasks */
190 _start(ErlDrvPort port
, char *args
)
196 edtk_debug("%s: starting, port = %ld, args = 0x%lx, %s", __FUNCTION__
,
197 port
, (unsigned long) args
, args
);
199 if ((desc
= (descriptor_t
*) sys_alloc(sizeof(descriptor_t
))) == NULL
) {
200 return ERL_DRV_ERROR_GENERAL
;
202 memset(desc
, 0, sizeof(descriptor_t
));
205 /* TODO: Finish initializing descriptor members */
207 /* TODO: Take care of other port initialization tasks */
209 return (ErlDrvData
) desc
;
213 _stop(ErlDrvData drv_data
)
215 descriptor_t
*desc
= (descriptor_t
*) drv_data
;
218 int still_in_use
= 0;
222 edtk_debug("%s: drv_data == NULL", __FUNCTION__
);
225 edtk_debug("%s: port = %ld", __FUNCTION__
, desc
->port
);
228 if (! still_in_use
) {
231 edtk_debug("%s: port = %ld finished", __FUNCTION__
, port
);
234 ** QQQ Oi, this is a sticky problem. This port is being shut
235 ** down, but we've still got some valmaps in use. We have no
236 ** way to tell the VM that we cannot be shut down safely right
237 ** now, so what in the heck do we do? It seems to me that we
239 ** 1. Block the entire VM until all valmaps are idle, then
240 ** clean them up and then return.
241 ** 2. Create a new thread that will take care of monitoring
242 ** the valmaps & doing their final cleanup. This stop
243 ** function, executing in the main thread, can return
244 ** to the VM right away.
245 ** For the sake of simplicity, I'm going to implement #1
246 ** for now. This will get more complicated once EDTK supports
247 ** private worker threads, so we won't bother getting fancy
250 edtk_debug("%s: port = %ld has %d valmaps still in use!", __FUNCTION__
, desc
->port
, still_in_use
);
253 ** QQQ Perhaps an alternative would be to create another
254 ** thread to (slowly) spin-wait on still-in-use valmap, and
255 ** when it's idle, have that thread free "desc" then exit?
257 sleep(1); /* QQQ Ouch, this is brute force, but hey, it's simple */
258 _stop(drv_data
); /* Hope we don't run out of stack */
263 _output(ErlDrvData drv_data
, char *buf
, int len
)
266 ** Nobody should be calling this function because we've
267 ** defined the "outputv" driver method, which BEAM will always
268 ** used if it's available. I just put a debug statement in
269 ** here so that I might actually notice if the impossible ever
272 edtk_debug("%s: XXX someone tried to call us, silly", __FUNCTION__
);
276 _control(ErlDrvData drv_data
, unsigned int command
,
277 char *buf
, int len
, char **rbuf
, int rlen
)
283 ** Nobody should be calling this function either.
287 edtk_debug("%s: XXX someone tried to call us, silly", __FUNCTION__
);
292 _outputv(ErlDrvData drv_data
, ErlIOVec
*ev
)
294 descriptor_t
*desc
= (descriptor_t
*) drv_data
;
297 callstate_t
*c
= NULL
;
298 int do_async_call
= default_async_calls
;
299 unsigned long binlen
;
306 if (desc
== NULL
|| ev
== NULL
|| ev
->size
< 1) {
307 edtk_debug("%s: bad arg(s)", __FUNCTION__
);
310 if (! EV_GET_CHAR(ev
, &cmd
, &p
, &q
)) {
311 edtk_debug("%s: empty command", __FUNCTION__
);
312 reply_error(desc
, EINVAL
);
314 if ((c
= sys_alloc(sizeof(callstate_t
))) == NULL
) {
315 reply_error(desc
, ENOMEM
);
321 c
->xid
= 0; /* QQQ unused right now */
322 c
->o
.__expect
= 1; /* Default is that expectation is always met */
324 edtk_debug("%s: my threadid = %lx, cmd = %d", __FUNCTION__
, pthread_self(), cmd
);
327 EV_GET_UINT32(ev
, &edtk_debug_flag
, &p
, &q
);
328 reply_ok_num(desc
, edtk_debug_flag
); /* Immediate reply */
333 c
->invoke
= invoke__getgid
;
336 c
->invoke
= invoke__getegid
;
339 c
->invoke
= invoke__getgrnam
;
340 EV_GET_UINT32(ev
, &binlen
, &p
, &q
);
341 c
->i
.name
= (char *) EV_GETPOS(ev
, p
, q
);
342 if (edtk_ev_forward_N(ev
, binlen
, &p
, &q
, 1) < 0) {
347 c
->invoke
= invoke__getgrgid
;
348 EV_GET_UINT32(ev
, &c
->i
.gid
, &p
, &q
);
351 c
->invoke
= invoke__getgroups
;
354 c
->invoke
= invoke__getpwnam
;
355 EV_GET_UINT32(ev
, &binlen
, &p
, &q
);
356 c
->i
.login
= (char *) EV_GETPOS(ev
, p
, q
);
357 if (edtk_ev_forward_N(ev
, binlen
, &p
, &q
, 1) < 0) {
362 c
->invoke
= invoke__getpwuid
;
363 EV_GET_UINT32(ev
, &c
->i
.uid
, &p
, &q
);
366 c
->invoke
= invoke__getuid
;
369 c
->invoke
= invoke__geteuid
;
372 c
->invoke
= invoke__getlogin
;
375 c
->invoke
= invoke__getpgrp
;
378 c
->invoke
= invoke__getppid
;
381 c
->invoke
= invoke__getsid
;
382 /* <hack place="post-deserialize" type="verbatim"> */
386 /* </hack --place="post-deserialize" type="verbatim"--> */
389 c
->invoke
= invoke__kill
;
390 EV_GET_UINT32(ev
, &c
->i
.pid
, &p
, &q
);
391 EV_GET_UINT32(ev
, &c
->i
.sig
, &p
, &q
);
394 c
->invoke
= invoke__lstat
;
395 EV_GET_UINT32(ev
, &binlen
, &p
, &q
);
396 c
->i
.path
= (char *) EV_GETPOS(ev
, p
, q
);
397 if (edtk_ev_forward_N(ev
, binlen
, &p
, &q
, 1) < 0) {
402 c
->invoke
= invoke__mkfifo
;
403 EV_GET_UINT32(ev
, &binlen
, &p
, &q
);
404 c
->i
.path
= (char *) EV_GETPOS(ev
, p
, q
);
405 if (edtk_ev_forward_N(ev
, binlen
, &p
, &q
, 1) < 0) {
408 EV_GET_UINT32(ev
, &c
->i
.mode
, &p
, &q
);
411 c
->invoke
= invoke__mknod
;
412 EV_GET_UINT32(ev
, &binlen
, &p
, &q
);
413 c
->i
.path
= (char *) EV_GETPOS(ev
, p
, q
);
414 if (edtk_ev_forward_N(ev
, binlen
, &p
, &q
, 1) < 0) {
417 EV_GET_UINT32(ev
, &c
->i
.mode
, &p
, &q
);
418 EV_GET_UINT32(ev
, &c
->i
.dev
, &p
, &q
);
421 c
->invoke
= invoke__umask
;
422 EV_GET_UINT32(ev
, &c
->i
.numask
, &p
, &q
);
425 edtk_debug("%s: invalid command %d", __FUNCTION__
, cmd
);
431 driver_async(desc
->port
, c
->key
, c
->invoke
, c
, c
->free
);
434 ** Execute the bottom half right away, then send the result.
436 (*(c
->invoke
))((void *) c
);
437 _ready_async((ErlDrvData
) desc
, (ErlDrvThreadData
) c
);
439 ** c is already freed for us by _ready_async()
449 reply_error_atom(desc
, am_badarg
);
453 _ready_async(ErlDrvData drv_data
, ErlDrvThreadData thread_data
)
455 descriptor_t
*desc
= (descriptor_t
*) drv_data
;
456 callstate_t
*c
= (callstate_t
*) thread_data
;
457 int bytes
, offset
, i
;
459 unsigned long index
= 0;
466 edtk_debug("%s: cmd = %d", __FUNCTION__
, c
->cmd
);
468 edtk_debug("%s: c == NULL", __FUNCTION__
);
474 reply_ok_num(desc
, c
->o
.ret_gid_t
);
476 reply_error(desc
, c
->o
.__expect_errval
);
481 reply_ok_num(desc
, c
->o
.ret_gid_t
);
483 reply_error(desc
, c
->o
.__expect_errval
);
487 reply_xtra_group(desc
, c
);
490 reply_xtra_group(desc
, c
);
493 reply_xtra_getgroups(desc
, c
);
496 reply_xtra_passwd(desc
, c
);
499 reply_xtra_passwd(desc
, c
);
503 reply_ok_num(desc
, c
->o
.ret_uid_t
);
505 reply_error(desc
, c
->o
.__expect_errval
);
510 reply_ok_num(desc
, c
->o
.ret_uid_t
);
512 reply_error(desc
, c
->o
.__expect_errval
);
516 bytes
= strlen(c
->o
.ret_char_p
);
518 if ((p
= edtk_driver_alloc_wrapper(bytes
)) == NULL
) {
519 reply_error(desc
, ENOMEM
);
521 memcpy(p
, c
->o
.ret_char_p
, bytes
);
522 reply_ok_binary(desc
, p
, 0, bytes
);
527 reply_ok_num(desc
, c
->o
.ret_pid_t
);
529 reply_error(desc
, c
->o
.__expect_errval
);
534 reply_ok_num(desc
, c
->o
.ret_pid_t
);
536 reply_error(desc
, c
->o
.__expect_errval
);
541 reply_ok_num(desc
, c
->o
.ret_pid_t
);
543 reply_error(desc
, c
->o
.__expect_errval
);
548 reply_ok_num(desc
, c
->o
.ret_int
);
550 reply_error(desc
, c
->o
.__expect_errval
);
554 reply_xtra_stat(desc
, c
);
558 reply_ok_num(desc
, c
->o
.ret_int
);
560 reply_error(desc
, c
->o
.__expect_errval
);
565 reply_ok_num(desc
, c
->o
.ret_int
);
567 reply_error(desc
, c
->o
.__expect_errval
);
572 reply_ok_num(desc
, c
->o
.ret_int
);
574 reply_error(desc
, c
->o
.__expect_errval
);
578 edtk_debug("%s: bogus command, should never happen", __FUNCTION__
);
585 invoke__getgid(void *data
)
587 callstate_t
*c
= (callstate_t
*) data
;
590 edtk_debug("%s: threadid = %lx", __FUNCTION__
, pthread_self());
591 c
->o
.ret_gid_t
= getgid(
593 if (c
->o
.ret_gid_t
>= 0) {
597 c
->o
.__expect_errval
= errno
;
598 /* Danger! Do not put debugging statement before saving error val! */
599 edtk_debug("%s: threadid = %lx expectation failed!", __FUNCTION__
, pthread_self());
601 edtk_debug("%s: threadid = %lx done", __FUNCTION__
, pthread_self());
605 invoke__getegid(void *data
)
607 callstate_t
*c
= (callstate_t
*) data
;
610 edtk_debug("%s: threadid = %lx", __FUNCTION__
, pthread_self());
611 c
->o
.ret_gid_t
= getegid(
613 if (c
->o
.ret_gid_t
>= 0) {
617 c
->o
.__expect_errval
= errno
;
618 /* Danger! Do not put debugging statement before saving error val! */
619 edtk_debug("%s: threadid = %lx expectation failed!", __FUNCTION__
, pthread_self());
621 edtk_debug("%s: threadid = %lx done", __FUNCTION__
, pthread_self());
625 invoke__getgrnam(void *data
)
627 callstate_t
*c
= (callstate_t
*) data
;
630 edtk_debug("%s: threadid = %lx", __FUNCTION__
, pthread_self());
631 c
->o
.ret_grptr
= getgrnam(
634 if (c
->o
.ret_grptr
!= NULL
) {
638 c
->o
.__expect_errval
= 0;
639 /* Danger! Do not put debugging statement before saving error val! */
640 edtk_debug("%s: threadid = %lx expectation failed!", __FUNCTION__
, pthread_self());
642 edtk_debug("%s: threadid = %lx done", __FUNCTION__
, pthread_self());
646 invoke__getgrgid(void *data
)
648 callstate_t
*c
= (callstate_t
*) data
;
651 edtk_debug("%s: threadid = %lx", __FUNCTION__
, pthread_self());
652 c
->o
.ret_grptr
= getgrgid(
655 if (c
->o
.ret_grptr
!= NULL
) {
659 c
->o
.__expect_errval
= 0;
660 /* Danger! Do not put debugging statement before saving error val! */
661 edtk_debug("%s: threadid = %lx expectation failed!", __FUNCTION__
, pthread_self());
663 edtk_debug("%s: threadid = %lx done", __FUNCTION__
, pthread_self());
667 invoke__getgroups(void *data
)
669 callstate_t
*c
= (callstate_t
*) data
;
672 edtk_debug("%s: threadid = %lx", __FUNCTION__
, pthread_self());
673 c
->o
.ret_int
= my_getgroups(
676 if (c
->o
.ret_int
>= 0) {
680 c
->o
.__expect_errval
= errno
;
681 /* Danger! Do not put debugging statement before saving error val! */
682 edtk_debug("%s: threadid = %lx expectation failed!", __FUNCTION__
, pthread_self());
684 edtk_debug("%s: threadid = %lx done", __FUNCTION__
, pthread_self());
688 invoke__getpwnam(void *data
)
690 callstate_t
*c
= (callstate_t
*) data
;
693 edtk_debug("%s: threadid = %lx", __FUNCTION__
, pthread_self());
694 c
->o
.ret_pwptr
= getpwnam(
697 if (c
->o
.ret_pwptr
!= NULL
) {
701 c
->o
.__expect_errval
= 0;
702 /* Danger! Do not put debugging statement before saving error val! */
703 edtk_debug("%s: threadid = %lx expectation failed!", __FUNCTION__
, pthread_self());
705 edtk_debug("%s: threadid = %lx done", __FUNCTION__
, pthread_self());
709 invoke__getpwuid(void *data
)
711 callstate_t
*c
= (callstate_t
*) data
;
714 edtk_debug("%s: threadid = %lx", __FUNCTION__
, pthread_self());
715 c
->o
.ret_pwptr
= getpwuid(
718 if (c
->o
.ret_pwptr
!= NULL
) {
722 c
->o
.__expect_errval
= 0;
723 /* Danger! Do not put debugging statement before saving error val! */
724 edtk_debug("%s: threadid = %lx expectation failed!", __FUNCTION__
, pthread_self());
726 edtk_debug("%s: threadid = %lx done", __FUNCTION__
, pthread_self());
730 invoke__getuid(void *data
)
732 callstate_t
*c
= (callstate_t
*) data
;
735 edtk_debug("%s: threadid = %lx", __FUNCTION__
, pthread_self());
736 c
->o
.ret_uid_t
= getuid(
738 if (c
->o
.ret_uid_t
>= 0) {
742 c
->o
.__expect_errval
= errno
;
743 /* Danger! Do not put debugging statement before saving error val! */
744 edtk_debug("%s: threadid = %lx expectation failed!", __FUNCTION__
, pthread_self());
746 edtk_debug("%s: threadid = %lx done", __FUNCTION__
, pthread_self());
750 invoke__geteuid(void *data
)
752 callstate_t
*c
= (callstate_t
*) data
;
755 edtk_debug("%s: threadid = %lx", __FUNCTION__
, pthread_self());
756 c
->o
.ret_uid_t
= geteuid(
758 if (c
->o
.ret_uid_t
>= 0) {
762 c
->o
.__expect_errval
= errno
;
763 /* Danger! Do not put debugging statement before saving error val! */
764 edtk_debug("%s: threadid = %lx expectation failed!", __FUNCTION__
, pthread_self());
766 edtk_debug("%s: threadid = %lx done", __FUNCTION__
, pthread_self());
770 invoke__getlogin(void *data
)
772 callstate_t
*c
= (callstate_t
*) data
;
775 edtk_debug("%s: threadid = %lx", __FUNCTION__
, pthread_self());
776 c
->o
.ret_char_p
= getlogin(
778 if (c
->o
.ret_char_p
!= NULL
) {
782 c
->o
.__expect_errval
= 0;
783 /* Danger! Do not put debugging statement before saving error val! */
784 edtk_debug("%s: threadid = %lx expectation failed!", __FUNCTION__
, pthread_self());
786 edtk_debug("%s: threadid = %lx done", __FUNCTION__
, pthread_self());
790 invoke__getpgrp(void *data
)
792 callstate_t
*c
= (callstate_t
*) data
;
795 edtk_debug("%s: threadid = %lx", __FUNCTION__
, pthread_self());
796 c
->o
.ret_pid_t
= getpgrp(
798 if (c
->o
.ret_pid_t
>= 0) {
802 c
->o
.__expect_errval
= errno
;
803 /* Danger! Do not put debugging statement before saving error val! */
804 edtk_debug("%s: threadid = %lx expectation failed!", __FUNCTION__
, pthread_self());
806 edtk_debug("%s: threadid = %lx done", __FUNCTION__
, pthread_self());
810 invoke__getppid(void *data
)
812 callstate_t
*c
= (callstate_t
*) data
;
815 edtk_debug("%s: threadid = %lx", __FUNCTION__
, pthread_self());
816 c
->o
.ret_pid_t
= getppid(
818 if (c
->o
.ret_pid_t
>= 0) {
822 c
->o
.__expect_errval
= errno
;
823 /* Danger! Do not put debugging statement before saving error val! */
824 edtk_debug("%s: threadid = %lx expectation failed!", __FUNCTION__
, pthread_self());
826 edtk_debug("%s: threadid = %lx done", __FUNCTION__
, pthread_self());
830 invoke__getsid(void *data
)
832 callstate_t
*c
= (callstate_t
*) data
;
835 edtk_debug("%s: threadid = %lx", __FUNCTION__
, pthread_self());
836 c
->o
.ret_pid_t
= getsid(
839 if (c
->o
.ret_pid_t
>= 0) {
843 c
->o
.__expect_errval
= errno
;
844 /* Danger! Do not put debugging statement before saving error val! */
845 edtk_debug("%s: threadid = %lx expectation failed!", __FUNCTION__
, pthread_self());
847 edtk_debug("%s: threadid = %lx done", __FUNCTION__
, pthread_self());
851 invoke__kill(void *data
)
853 callstate_t
*c
= (callstate_t
*) data
;
856 edtk_debug("%s: threadid = %lx", __FUNCTION__
, pthread_self());
861 if (c
->o
.ret_int
>= 0) {
865 c
->o
.__expect_errval
= errno
;
866 /* Danger! Do not put debugging statement before saving error val! */
867 edtk_debug("%s: threadid = %lx expectation failed!", __FUNCTION__
, pthread_self());
869 edtk_debug("%s: threadid = %lx done", __FUNCTION__
, pthread_self());
873 invoke__lstat(void *data
)
875 callstate_t
*c
= (callstate_t
*) data
;
878 edtk_debug("%s: threadid = %lx", __FUNCTION__
, pthread_self());
879 c
->o
.ret_int
= lstat(
883 if (c
->o
.ret_int
>= 0) {
887 c
->o
.__expect_errval
= c
->o
.ret_int
;
888 /* Danger! Do not put debugging statement before saving error val! */
889 edtk_debug("%s: threadid = %lx expectation failed!", __FUNCTION__
, pthread_self());
891 edtk_debug("%s: threadid = %lx done", __FUNCTION__
, pthread_self());
895 invoke__mkfifo(void *data
)
897 callstate_t
*c
= (callstate_t
*) data
;
900 edtk_debug("%s: threadid = %lx", __FUNCTION__
, pthread_self());
901 c
->o
.ret_int
= mkfifo(
905 if (c
->o
.ret_int
>= 0) {
909 c
->o
.__expect_errval
= errno
;
910 /* Danger! Do not put debugging statement before saving error val! */
911 edtk_debug("%s: threadid = %lx expectation failed!", __FUNCTION__
, pthread_self());
913 edtk_debug("%s: threadid = %lx done", __FUNCTION__
, pthread_self());
917 invoke__mknod(void *data
)
919 callstate_t
*c
= (callstate_t
*) data
;
922 edtk_debug("%s: threadid = %lx", __FUNCTION__
, pthread_self());
923 c
->o
.ret_int
= mknod(
928 if (c
->o
.ret_int
>= 0) {
932 c
->o
.__expect_errval
= errno
;
933 /* Danger! Do not put debugging statement before saving error val! */
934 edtk_debug("%s: threadid = %lx expectation failed!", __FUNCTION__
, pthread_self());
936 edtk_debug("%s: threadid = %lx done", __FUNCTION__
, pthread_self());
940 invoke__umask(void *data
)
942 callstate_t
*c
= (callstate_t
*) data
;
945 edtk_debug("%s: threadid = %lx", __FUNCTION__
, pthread_self());
946 c
->o
.ret_int
= umask(
949 if (c
->o
.ret_int
>= 0) {
953 c
->o
.__expect_errval
= errno
;
954 /* Danger! Do not put debugging statement before saving error val! */
955 edtk_debug("%s: threadid = %lx expectation failed!", __FUNCTION__
, pthread_self());
957 edtk_debug("%s: threadid = %lx done", __FUNCTION__
, pthread_self());
962 reply_ok(descriptor_t
*desc
)
964 ErlDrvTermData msg
[15]; /* XXX too big */
968 i
= LOAD_PORT(msg
, i
, driver_mk_port(desc
->port
));
969 i
= LOAD_ATOM(msg
, i
, am_ok
);
970 i
= LOAD_TUPLE(msg
, i
, 2);
971 edtk_debug("reply_ok: i = %d", i
);
972 res
= driver_output_term(desc
->port
, msg
, i
);
973 edtk_debug("reply_ok: res = %d", res
);
978 reply_ok_num(descriptor_t
*desc
, unsigned long num
)
980 ErlDrvTermData msg
[15]; /* XXX too big */
984 i
= LOAD_PORT(msg
, i
, driver_mk_port(desc
->port
));
985 i
= LOAD_ATOM(msg
, i
, am_ok
);
986 i
= LOAD_INT(msg
, i
, num
);
987 i
= LOAD_TUPLE(msg
, i
, 3);
988 edtk_debug("%s: i = %d, num = %lu", __FUNCTION__
, i
, num
);
989 res
= driver_output_term(desc
->port
, msg
, i
);
990 edtk_debug("%s: res = %d", __FUNCTION__
, res
);
995 reply_ok_binary(descriptor_t
*desc
, char *ptr
, int beg_offset
, int length
)
997 ErlDrvTermData msg
[15]; /* XXX too big */
1001 i
= LOAD_PORT(msg
, i
, driver_mk_port(desc
->port
));
1002 i
= LOAD_ATOM(msg
, i
, am_ok
);
1003 i
= LOAD_BINARY(msg
, i
, edtk_alloced_ptr2ErlDrvBinary(ptr
),
1004 beg_offset
, length
);
1005 i
= LOAD_TUPLE(msg
, i
, 3);
1006 edtk_debug("%s: i = %d, ptr = 0x%lx, start = %d, end = %d",
1007 __FUNCTION__
, i
, ptr
, beg_offset
, length
);
1008 res
= driver_output_term(desc
->port
, msg
, i
);
1009 /* driver_output_term() incrs refc, and we're done, so decr refc */
1011 ** We _know_ that "ptr" points to memory allocated by
1012 ** edtk_driver_alloc_wrapper(), so edtk_alloced_ptr2ErlDrvBinary()
1013 ** is safe in this case. If it weren't safe, then the binary
1014 ** must be returned by an xtra_return, which means we
1015 ** reply_ok_binary()) are never called!
1017 driver_free_binary(edtk_alloced_ptr2ErlDrvBinary(ptr
));
1018 edtk_debug("%s: res = %d", __FUNCTION__
, res
);
1023 reply_ok_valmap(descriptor_t
*desc
, ErlDrvTermData valmap_atom
,
1024 unsigned long valmap_index
)
1026 ErlDrvTermData msg
[15];
1030 i
= LOAD_PORT(msg
, i
, driver_mk_port(desc
->port
));
1031 i
= LOAD_ATOM(msg
, i
, am_ok
);
1032 i
= LOAD_ATOM(msg
, i
, valmap_atom
);
1033 i
= LOAD_INT(msg
, i
, valmap_index
);
1034 i
= LOAD_TUPLE(msg
, i
, 2);
1035 i
= LOAD_TUPLE(msg
, i
, 3);
1036 edtk_debug("reply_ok_valmap: i = %d", i
);
1037 res
= driver_output_term(desc
->port
, msg
, i
);
1038 edtk_debug("reply_ok_valmap: res = %d", res
);
1043 reply_error(descriptor_t
*desc
, int errnum
)
1045 ErlDrvTermData msg
[15]; /* XXX too big */
1049 edtk_debug("reply_error: errnum = %d", errnum
);
1050 i
= LOAD_PORT(msg
, i
, driver_mk_port(desc
->port
));
1051 i
= LOAD_ATOM(msg
, i
, am_error
);
1052 i
= LOAD_INT(msg
, i
, errnum
);
1053 i
= LOAD_TUPLE(msg
, i
, 3);
1054 edtk_debug("reply_error: i = %d", i
);
1055 res
= driver_output_term(desc
->port
, msg
, i
);
1056 edtk_debug("reply_error: res = %d", res
);
1061 reply_error_atom(descriptor_t
*desc
, ErlDrvTermData atom
)
1063 ErlDrvTermData msg
[15]; /* XXX too big */
1067 i
= LOAD_PORT(msg
, i
, driver_mk_port(desc
->port
));
1068 i
= LOAD_ATOM(msg
, i
, am_error
);
1069 i
= LOAD_ATOM(msg
, i
, atom
);
1070 i
= LOAD_TUPLE(msg
, i
, 3);
1071 edtk_debug("%s: i = %d", __FUNCTION__
, i
);
1072 res
= driver_output_term(desc
->port
, msg
, i
);
1073 edtk_debug("%s: res = %d", __FUNCTION__
, res
);
1077 #if 0 /* QQQ These are unused right now */
1079 reply_tag_ok(descriptor_t
*desc
, unsigned short tag
)
1081 ErlDrvTermData msg
[15]; /* XXX too big */
1085 i
= LOAD_PORT(msg
, i
, driver_mk_port(desc
->port
));
1086 i
= LOAD_INT(msg
, i
, tag
);
1087 i
= LOAD_ATOM(msg
, i
, am_ok
);
1088 i
= LOAD_TUPLE(msg
, i
, 3);
1089 edtk_debug("reply_ok: i = %d", i
);
1090 res
= driver_output_term(desc
->port
, msg
, i
);
1091 edtk_debug("reply_ok: res = %d", res
);
1096 reply_tag_error(descriptor_t
*desc
, unsigned short tag
, int errnum
)
1098 ErlDrvTermData msg
[15]; /* XXX too big */
1102 edtk_debug("reply_error: errnum = %d", errnum
);
1103 i
= LOAD_PORT(msg
, i
, driver_mk_port(desc
->port
));
1104 i
= LOAD_INT(msg
, i
, tag
);
1105 i
= LOAD_INT(msg
, i
, errnum
);
1106 i
= LOAD_ATOM(msg
, i
, am_error
);
1107 i
= LOAD_TUPLE(msg
, i
, 4);
1108 edtk_debug("reply_error: i = %d", i
);
1109 res
= driver_output_term(desc
->port
, msg
, i
);
1110 edtk_debug("reply_error: res = %d", res
);
1117 reply_xtra_stat(descriptor_t
*desc
, callstate_t
*c
)
1119 ErlDrvTermData msg
[64];
1124 ErlDrvBinary
*tofree
[64];
1127 ErlDrvBinary
*tmpbin
= NULL
;
1129 tmp
= tmp
; tmpbin
= tmpbin
;
1130 msgcount
= LOAD_PORT(msg
, msgcount
, driver_mk_port(desc
->port
));
1131 members
= 2; /* Rather, members will be 2 very shortly */
1132 if (c
->o
.__expect
) {
1133 msgcount
= LOAD_ATOM(msg
, msgcount
, am_ok
);
1139 msgcount
= LOAD_ATOM(msg
, msgcount
, am_stat
);
1141 msgcount
= LOAD_INT(msg
, msgcount
, c
->o
.sb
.st_dev
);
1143 msgcount
= LOAD_INT(msg
, msgcount
, c
->o
.sb
.st_ino
);
1145 msgcount
= LOAD_INT(msg
, msgcount
, c
->o
.sb
.st_mode
);
1147 msgcount
= LOAD_INT(msg
, msgcount
, c
->o
.sb
.st_nlink
);
1149 msgcount
= LOAD_INT(msg
, msgcount
, c
->o
.sb
.st_uid
);
1151 msgcount
= LOAD_INT(msg
, msgcount
, c
->o
.sb
.st_gid
);
1153 msgcount
= LOAD_INT(msg
, msgcount
, c
->o
.sb
.st_rdev
);
1155 msgcount
= LOAD_INT(msg
, msgcount
, c
->o
.sb
.st_atime
);
1157 msgcount
= LOAD_INT(msg
, msgcount
, c
->o
.sb
.st_mtime
);
1159 msgcount
= LOAD_INT(msg
, msgcount
, c
->o
.sb
.st_ctime
);
1161 msgcount
= LOAD_INT(msg
, msgcount
, c
->o
.sb
.st_size
);
1163 msgcount
= LOAD_INT(msg
, msgcount
, c
->o
.sb
.st_blocks
);
1165 msgcount
= LOAD_INT(msg
, msgcount
, c
->o
.sb
.st_blksize
);
1167 msgcount
= LOAD_TUPLE(msg
, msgcount
, members
); /* XXX */
1170 msgcount
= LOAD_TUPLE(msg
, msgcount
, members
);
1173 msgcount
= LOAD_ATOM(msg
, msgcount
, am_error
);
1176 msgcount
= LOAD_INT(msg
, msgcount
, errno
);
1178 msgcount
= LOAD_TUPLE(msg
, msgcount
, members
);
1181 msgcount
= LOAD_TUPLE(msg
, msgcount
, 3);
1182 edtk_debug("reply_xtra_stat: i = %d", msgcount
);
1183 res
= driver_output_term(desc
->port
, msg
, msgcount
);
1184 edtk_debug("reply_xtra_stat: res = %d", res
);
1186 fprintf(stderr
, "\r\n\r\nreply_xtra_stat: driver_output_term() failed! This should never happen!\r\n\r\n");
1189 for (i
= 0; i
< num_tofree
; i
++) {
1190 driver_free_binary(tofree
[i
]);
1196 reply_xtra_passwd(descriptor_t
*desc
, callstate_t
*c
)
1198 ErlDrvTermData msg
[64];
1203 ErlDrvBinary
*tofree
[64];
1206 ErlDrvBinary
*tmpbin
= NULL
;
1208 tmp
= tmp
; tmpbin
= tmpbin
;
1209 msgcount
= LOAD_PORT(msg
, msgcount
, driver_mk_port(desc
->port
));
1210 members
= 2; /* Rather, members will be 2 very shortly */
1211 if (c
->o
.__expect
) {
1212 msgcount
= LOAD_ATOM(msg
, msgcount
, am_ok
);
1218 msgcount
= LOAD_ATOM(msg
, msgcount
, am_passwd
);
1220 if ((tmp
= edtk_driver_alloc_wrapper(strlen(c
->o
.ret_pwptr
->pw_name
))) == NULL
) {
1221 return reply_error(desc
, ENOMEM
);
1223 memcpy(tmp
, c
->o
.ret_pwptr
->pw_name
, strlen(c
->o
.ret_pwptr
->pw_name
));
1224 tmpbin
= edtk_alloced_ptr2ErlDrvBinary(tmp
);
1225 msgcount
= LOAD_BINARY(msg
, msgcount
, tmpbin
, 0, strlen(c
->o
.ret_pwptr
->pw_name
));
1226 /* driver_output_term() incrs refc, and we're done, so decr refc LATER */
1227 tofree
[num_tofree
++] = tmpbin
;
1229 if ((tmp
= edtk_driver_alloc_wrapper(strlen(c
->o
.ret_pwptr
->pw_passwd
))) == NULL
) {
1230 return reply_error(desc
, ENOMEM
);
1232 memcpy(tmp
, c
->o
.ret_pwptr
->pw_passwd
, strlen(c
->o
.ret_pwptr
->pw_passwd
));
1233 tmpbin
= edtk_alloced_ptr2ErlDrvBinary(tmp
);
1234 msgcount
= LOAD_BINARY(msg
, msgcount
, tmpbin
, 0, strlen(c
->o
.ret_pwptr
->pw_passwd
));
1235 /* driver_output_term() incrs refc, and we're done, so decr refc LATER */
1236 tofree
[num_tofree
++] = tmpbin
;
1238 msgcount
= LOAD_INT(msg
, msgcount
, c
->o
.ret_pwptr
->pw_uid
);
1240 msgcount
= LOAD_INT(msg
, msgcount
, c
->o
.ret_pwptr
->pw_gid
);
1242 if ((tmp
= edtk_driver_alloc_wrapper(strlen(c
->o
.ret_pwptr
->pw_gecos
))) == NULL
) {
1243 return reply_error(desc
, ENOMEM
);
1245 memcpy(tmp
, c
->o
.ret_pwptr
->pw_gecos
, strlen(c
->o
.ret_pwptr
->pw_gecos
));
1246 tmpbin
= edtk_alloced_ptr2ErlDrvBinary(tmp
);
1247 msgcount
= LOAD_BINARY(msg
, msgcount
, tmpbin
, 0, strlen(c
->o
.ret_pwptr
->pw_gecos
));
1248 /* driver_output_term() incrs refc, and we're done, so decr refc LATER */
1249 tofree
[num_tofree
++] = tmpbin
;
1251 if ((tmp
= edtk_driver_alloc_wrapper(strlen(c
->o
.ret_pwptr
->pw_dir
))) == NULL
) {
1252 return reply_error(desc
, ENOMEM
);
1254 memcpy(tmp
, c
->o
.ret_pwptr
->pw_dir
, strlen(c
->o
.ret_pwptr
->pw_dir
));
1255 tmpbin
= edtk_alloced_ptr2ErlDrvBinary(tmp
);
1256 msgcount
= LOAD_BINARY(msg
, msgcount
, tmpbin
, 0, strlen(c
->o
.ret_pwptr
->pw_dir
));
1257 /* driver_output_term() incrs refc, and we're done, so decr refc LATER */
1258 tofree
[num_tofree
++] = tmpbin
;
1260 if ((tmp
= edtk_driver_alloc_wrapper(strlen(c
->o
.ret_pwptr
->pw_shell
))) == NULL
) {
1261 return reply_error(desc
, ENOMEM
);
1263 memcpy(tmp
, c
->o
.ret_pwptr
->pw_shell
, strlen(c
->o
.ret_pwptr
->pw_shell
));
1264 tmpbin
= edtk_alloced_ptr2ErlDrvBinary(tmp
);
1265 msgcount
= LOAD_BINARY(msg
, msgcount
, tmpbin
, 0, strlen(c
->o
.ret_pwptr
->pw_shell
));
1266 /* driver_output_term() incrs refc, and we're done, so decr refc LATER */
1267 tofree
[num_tofree
++] = tmpbin
;
1269 msgcount
= LOAD_TUPLE(msg
, msgcount
, members
); /* XXX */
1272 msgcount
= LOAD_TUPLE(msg
, msgcount
, members
);
1275 msgcount
= LOAD_ATOM(msg
, msgcount
, am_error
);
1278 msgcount
= LOAD_INT(msg
, msgcount
, c
->o
.__expect_errval
);
1280 msgcount
= LOAD_TUPLE(msg
, msgcount
, members
);
1283 msgcount
= LOAD_TUPLE(msg
, msgcount
, 3);
1284 edtk_debug("reply_xtra_passwd: i = %d", msgcount
);
1285 res
= driver_output_term(desc
->port
, msg
, msgcount
);
1286 edtk_debug("reply_xtra_passwd: res = %d", res
);
1288 fprintf(stderr
, "\r\n\r\nreply_xtra_passwd: driver_output_term() failed! This should never happen!\r\n\r\n");
1291 for (i
= 0; i
< num_tofree
; i
++) {
1292 driver_free_binary(tofree
[i
]);
1298 reply_xtra_group(descriptor_t
*desc
, callstate_t
*c
)
1300 ErlDrvTermData msg
[64];
1305 ErlDrvBinary
*tofree
[64];
1308 ErlDrvBinary
*tmpbin
= NULL
;
1310 tmp
= tmp
; tmpbin
= tmpbin
;
1311 msgcount
= LOAD_PORT(msg
, msgcount
, driver_mk_port(desc
->port
));
1312 members
= 2; /* Rather, members will be 2 very shortly */
1313 if (c
->o
.__expect
) {
1314 msgcount
= LOAD_ATOM(msg
, msgcount
, am_ok
);
1320 msgcount
= LOAD_ATOM(msg
, msgcount
, am_group
);
1322 if ((tmp
= edtk_driver_alloc_wrapper(strlen(c
->o
.ret_grptr
->gr_name
))) == NULL
) {
1323 return reply_error(desc
, ENOMEM
);
1325 memcpy(tmp
, c
->o
.ret_grptr
->gr_name
, strlen(c
->o
.ret_grptr
->gr_name
));
1326 tmpbin
= edtk_alloced_ptr2ErlDrvBinary(tmp
);
1327 msgcount
= LOAD_BINARY(msg
, msgcount
, tmpbin
, 0, strlen(c
->o
.ret_grptr
->gr_name
));
1328 /* driver_output_term() incrs refc, and we're done, so decr refc LATER */
1329 tofree
[num_tofree
++] = tmpbin
;
1331 if ((tmp
= edtk_driver_alloc_wrapper(strlen(c
->o
.ret_grptr
->gr_passwd
))) == NULL
) {
1332 return reply_error(desc
, ENOMEM
);
1334 memcpy(tmp
, c
->o
.ret_grptr
->gr_passwd
, strlen(c
->o
.ret_grptr
->gr_passwd
));
1335 tmpbin
= edtk_alloced_ptr2ErlDrvBinary(tmp
);
1336 msgcount
= LOAD_BINARY(msg
, msgcount
, tmpbin
, 0, strlen(c
->o
.ret_grptr
->gr_passwd
));
1337 /* driver_output_term() incrs refc, and we're done, so decr refc LATER */
1338 tofree
[num_tofree
++] = tmpbin
;
1340 msgcount
= LOAD_INT(msg
, msgcount
, c
->o
.ret_grptr
->gr_gid
);
1345 make_groups_list(desc
, c
, msg
, &members
, &msgcount
);
1346 msgcount
= LOAD_LIST(msg
, msgcount
, members
); /* XXX */
1349 msgcount
= LOAD_TUPLE(msg
, msgcount
, members
); /* XXX */
1352 msgcount
= LOAD_TUPLE(msg
, msgcount
, members
);
1355 msgcount
= LOAD_ATOM(msg
, msgcount
, am_error
);
1358 msgcount
= LOAD_INT(msg
, msgcount
, c
->o
.__expect_errval
);
1360 msgcount
= LOAD_TUPLE(msg
, msgcount
, members
);
1363 msgcount
= LOAD_TUPLE(msg
, msgcount
, 3);
1364 edtk_debug("reply_xtra_group: i = %d", msgcount
);
1365 res
= driver_output_term(desc
->port
, msg
, msgcount
);
1366 edtk_debug("reply_xtra_group: res = %d", res
);
1368 fprintf(stderr
, "\r\n\r\nreply_xtra_group: driver_output_term() failed! This should never happen!\r\n\r\n");
1371 for (i
= 0; i
< num_tofree
; i
++) {
1372 driver_free_binary(tofree
[i
]);
1378 reply_xtra_getgroups(descriptor_t
*desc
, callstate_t
*c
)
1380 ErlDrvTermData msg
[64];
1385 ErlDrvBinary
*tofree
[64];
1388 ErlDrvBinary
*tmpbin
= NULL
;
1390 tmp
= tmp
; tmpbin
= tmpbin
;
1391 msgcount
= LOAD_PORT(msg
, msgcount
, driver_mk_port(desc
->port
));
1392 members
= 2; /* Rather, members will be 2 very shortly */
1393 if (c
->o
.__expect
) {
1394 msgcount
= LOAD_ATOM(msg
, msgcount
, am_ok
);
1400 msgcount
= LOAD_INT(msg
, msgcount
, c
->o
.ret_int
);
1405 make_getgroups_list(desc
, c
, msg
, &members
, &msgcount
);
1406 msgcount
= LOAD_LIST(msg
, msgcount
, members
); /* XXX */
1409 msgcount
= LOAD_TUPLE(msg
, msgcount
, members
); /* XXX */
1412 msgcount
= LOAD_TUPLE(msg
, msgcount
, members
);
1415 msgcount
= LOAD_ATOM(msg
, msgcount
, am_error
);
1418 msgcount
= LOAD_INT(msg
, msgcount
, errno
);
1420 msgcount
= LOAD_TUPLE(msg
, msgcount
, members
);
1423 msgcount
= LOAD_TUPLE(msg
, msgcount
, 3);
1424 edtk_debug("reply_xtra_getgroups: i = %d", msgcount
);
1425 res
= driver_output_term(desc
->port
, msg
, msgcount
);
1426 edtk_debug("reply_xtra_getgroups: res = %d", res
);
1428 fprintf(stderr
, "\r\n\r\nreply_xtra_getgroups: driver_output_term() failed! This should never happen!\r\n\r\n");
1431 for (i
= 0; i
< num_tofree
; i
++) {
1432 driver_free_binary(tofree
[i
]);