Merge branch 'pu'
[jungerl.git] / lib / posix_drv / c_src / posix_drv.c
blob3b7661558f1e607fb8d1cee14cd7f79c99c3fe30
1 /*
2 ** File : posix_drv.c
3 ** Summary : Simple POSIX system call driver
4 **
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
7 ** what you're doing!
8 **
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
25 ** than a dumb array.
27 ** QQQ cannot pass references from driver -> Erlang! Gah!
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <errno.h>
34 #include <sys/types.h>
35 #include <assert.h>
36 #ifdef DRIVER_USING_PTHREADS
37 #include <pthread.h>
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"> */
49 #include <stdio.h>
50 #include <string.h>
51 #include <unistd.h>
52 #include <pwd.h>
53 #include <grp.h>
54 #include <sys/types.h>
55 #include <sys/stat.h>
56 #include <signal.h>
57 /* BSD-specific? (for NGROUPS_MAX) #include <sys/syslimits.h> */
59 #ifndef NGROUPS_MAX
60 #define NGROUPS_MAX 64 /* Big, but we'll be safe */
61 #endif /* !NGROUPS_MAX */
63 #include <posix_drv.h>
64 #include <my-posix.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);
137 #if 0
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);
140 #endif /* 0 */
142 static ErlDrvEntry _driver_entry = {
143 _init, /* init */
144 _start, /* start */
145 _stop, /* stop */
146 _output, /* output */
147 NULL, /* ready_input */
148 NULL, /* ready_output */
149 "posix_drv", /* driver_name */
150 NULL, /* finish */
151 NULL, /* handle */
152 _control, /* control */
153 NULL, /* timeout */
154 _outputv, /* outputv */
155 _ready_async, /* ready_async */
156 NULL, /* flush */
157 NULL /* call */
161 ** All dynamically-loadable driver libraries must contain a driver_init().
164 ErlDrvEntry *
165 driver_init(void *handle)
167 edtk_debug_flag = 0;
168 _driver_entry.handle = handle;
169 return &_driver_entry;
172 static int
173 _init(void)
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 */
186 return 0;
189 static ErlDrvData
190 _start(ErlDrvPort port, char *args)
192 descriptor_t *desc;
193 int i = 0;
195 i = i;
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));
203 desc->port = port;
204 desc->nextxid = 1;
205 /* TODO: Finish initializing descriptor members */
207 /* TODO: Take care of other port initialization tasks */
209 return (ErlDrvData) desc;
212 static void
213 _stop(ErlDrvData drv_data)
215 descriptor_t *desc = (descriptor_t *) drv_data;
216 int i = 0;
217 ErlDrvPort port;
218 int still_in_use = 0;
220 i = i;
221 if (desc == NULL) {
222 edtk_debug("%s: drv_data == NULL", __FUNCTION__);
223 return;
225 edtk_debug("%s: port = %ld", __FUNCTION__, desc->port);
228 if (! still_in_use) {
229 port = desc->port;
230 sys_free(desc);
231 edtk_debug("%s: port = %ld finished", __FUNCTION__, port);
232 } else {
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
238 ** have two choices:
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
248 ** for now.
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 */
262 static void
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
270 ** happens....
272 edtk_debug("%s: XXX someone tried to call us, silly", __FUNCTION__);
275 static int
276 _control(ErlDrvData drv_data, unsigned int command,
277 char *buf, int len, char **rbuf, int rlen)
279 char *ret = *rbuf;
280 int retlen;
283 ** Nobody should be calling this function either.
285 ret[0] = 1;
286 retlen = 1;
287 edtk_debug("%s: XXX someone tried to call us, silly", __FUNCTION__);
288 return retlen;
291 static void
292 _outputv(ErlDrvData drv_data, ErlIOVec *ev)
294 descriptor_t *desc = (descriptor_t *) drv_data;
295 unsigned char cmd;
296 int p = 0, q = 1;
297 callstate_t *c = NULL;
298 int do_async_call = default_async_calls;
299 unsigned long binlen;
300 int index;
301 void *tmp = NULL;
303 binlen = binlen;
304 index = index;
305 tmp = tmp;
306 if (desc == NULL || ev == NULL || ev->size < 1) {
307 edtk_debug("%s: bad arg(s)", __FUNCTION__);
308 return;
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);
316 return;
318 c->cmd = cmd;
319 c->key = NULL;
320 c->free = sys_free;
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);
325 switch (cmd) {
326 case _DEBUG:
327 EV_GET_UINT32(ev, &edtk_debug_flag, &p, &q);
328 reply_ok_num(desc, edtk_debug_flag); /* Immediate reply */
329 sys_free(c);
330 c = NULL;
331 break;
332 case _GETGID:
333 c->invoke = invoke__getgid;
334 break;
335 case _GETEGID:
336 c->invoke = invoke__getegid;
337 break;
338 case _GETGRNAM:
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) {
343 goto error;
345 break;
346 case _GETGRGID:
347 c->invoke = invoke__getgrgid;
348 EV_GET_UINT32(ev, &c->i.gid, &p, &q);
349 break;
350 case _GETGROUPS:
351 c->invoke = invoke__getgroups;
352 break;
353 case _GETPWNAM:
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) {
358 goto error;
360 break;
361 case _GETPWUID:
362 c->invoke = invoke__getpwuid;
363 EV_GET_UINT32(ev, &c->i.uid, &p, &q);
364 break;
365 case _GETUID:
366 c->invoke = invoke__getuid;
367 break;
368 case _GETEUID:
369 c->invoke = invoke__geteuid;
370 break;
371 case _GETLOGIN:
372 c->invoke = invoke__getlogin;
373 break;
374 case _GETPGRP:
375 c->invoke = invoke__getpgrp;
376 break;
377 case _GETPPID:
378 c->invoke = invoke__getppid;
379 break;
380 case _GETSID:
381 c->invoke = invoke__getsid;
382 /* <hack place="post-deserialize" type="verbatim"> */
384 c->i.pid = 0;
386 /* </hack --place="post-deserialize" type="verbatim"--> */
387 break;
388 case _KILL:
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);
392 break;
393 case _LSTAT:
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) {
398 goto error;
400 break;
401 case _MKFIFO:
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) {
406 goto error;
408 EV_GET_UINT32(ev, &c->i.mode, &p, &q);
409 break;
410 case _MKNOD:
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) {
415 goto error;
417 EV_GET_UINT32(ev, &c->i.mode, &p, &q);
418 EV_GET_UINT32(ev, &c->i.dev, &p, &q);
419 break;
420 case _UMASK:
421 c->invoke = invoke__umask;
422 EV_GET_UINT32(ev, &c->i.numask, &p, &q);
423 break;
424 default:
425 edtk_debug("%s: invalid command %d", __FUNCTION__, cmd);
426 goto error;
427 break;
429 if (c != NULL) {
430 if (do_async_call) {
431 driver_async(desc->port, c->key, c->invoke, c, c->free);
432 } else {
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()
443 return;
445 error:
446 if (c != NULL) {
447 sys_free(c);
449 reply_error_atom(desc, am_badarg);
452 static void
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;
458 char *p = NULL;
459 unsigned long index = 0;
461 p = p;
462 bytes = bytes;
463 offset = offset;
464 i = i;
465 index = index;
466 edtk_debug("%s: cmd = %d", __FUNCTION__, c->cmd);
467 if (c == NULL) {
468 edtk_debug("%s: c == NULL", __FUNCTION__);
469 return;
471 switch (c->cmd) {
472 case _GETGID:
473 if (c->o.__expect) {
474 reply_ok_num(desc, c->o.ret_gid_t);
475 } else {
476 reply_error(desc, c->o.__expect_errval);
478 break;
479 case _GETEGID:
480 if (c->o.__expect) {
481 reply_ok_num(desc, c->o.ret_gid_t);
482 } else {
483 reply_error(desc, c->o.__expect_errval);
485 break;
486 case _GETGRNAM:
487 reply_xtra_group(desc, c);
488 break;
489 case _GETGRGID:
490 reply_xtra_group(desc, c);
491 break;
492 case _GETGROUPS:
493 reply_xtra_getgroups(desc, c);
494 break;
495 case _GETPWNAM:
496 reply_xtra_passwd(desc, c);
497 break;
498 case _GETPWUID:
499 reply_xtra_passwd(desc, c);
500 break;
501 case _GETUID:
502 if (c->o.__expect) {
503 reply_ok_num(desc, c->o.ret_uid_t);
504 } else {
505 reply_error(desc, c->o.__expect_errval);
507 break;
508 case _GETEUID:
509 if (c->o.__expect) {
510 reply_ok_num(desc, c->o.ret_uid_t);
511 } else {
512 reply_error(desc, c->o.__expect_errval);
514 break;
515 case _GETLOGIN:
516 bytes = strlen(c->o.ret_char_p);
517 offset = 0;
518 if ((p = edtk_driver_alloc_wrapper(bytes)) == NULL) {
519 reply_error(desc, ENOMEM);
520 } else {
521 memcpy(p, c->o.ret_char_p, bytes);
522 reply_ok_binary(desc, p, 0, bytes);
524 break;
525 case _GETPGRP:
526 if (c->o.__expect) {
527 reply_ok_num(desc, c->o.ret_pid_t);
528 } else {
529 reply_error(desc, c->o.__expect_errval);
531 break;
532 case _GETPPID:
533 if (c->o.__expect) {
534 reply_ok_num(desc, c->o.ret_pid_t);
535 } else {
536 reply_error(desc, c->o.__expect_errval);
538 break;
539 case _GETSID:
540 if (c->o.__expect) {
541 reply_ok_num(desc, c->o.ret_pid_t);
542 } else {
543 reply_error(desc, c->o.__expect_errval);
545 break;
546 case _KILL:
547 if (c->o.__expect) {
548 reply_ok_num(desc, c->o.ret_int);
549 } else {
550 reply_error(desc, c->o.__expect_errval);
552 break;
553 case _LSTAT:
554 reply_xtra_stat(desc, c);
555 break;
556 case _MKFIFO:
557 if (c->o.__expect) {
558 reply_ok_num(desc, c->o.ret_int);
559 } else {
560 reply_error(desc, c->o.__expect_errval);
562 break;
563 case _MKNOD:
564 if (c->o.__expect) {
565 reply_ok_num(desc, c->o.ret_int);
566 } else {
567 reply_error(desc, c->o.__expect_errval);
569 break;
570 case _UMASK:
571 if (c->o.__expect) {
572 reply_ok_num(desc, c->o.ret_int);
573 } else {
574 reply_error(desc, c->o.__expect_errval);
576 break;
577 default:
578 edtk_debug("%s: bogus command, should never happen", __FUNCTION__);
579 break;
581 sys_free(c);
584 static void
585 invoke__getgid(void *data)
587 callstate_t *c = (callstate_t *) data;
589 c = c;
590 edtk_debug("%s: threadid = %lx", __FUNCTION__, pthread_self());
591 c->o.ret_gid_t = getgid(
593 if (c->o.ret_gid_t >= 0) {
594 c->o.__expect = 1;
595 } else {
596 c->o.__expect = 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());
604 static void
605 invoke__getegid(void *data)
607 callstate_t *c = (callstate_t *) data;
609 c = c;
610 edtk_debug("%s: threadid = %lx", __FUNCTION__, pthread_self());
611 c->o.ret_gid_t = getegid(
613 if (c->o.ret_gid_t >= 0) {
614 c->o.__expect = 1;
615 } else {
616 c->o.__expect = 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());
624 static void
625 invoke__getgrnam(void *data)
627 callstate_t *c = (callstate_t *) data;
629 c = c;
630 edtk_debug("%s: threadid = %lx", __FUNCTION__, pthread_self());
631 c->o.ret_grptr = getgrnam(
632 c->i.name
634 if (c->o.ret_grptr != NULL) {
635 c->o.__expect = 1;
636 } else {
637 c->o.__expect = 0;
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());
645 static void
646 invoke__getgrgid(void *data)
648 callstate_t *c = (callstate_t *) data;
650 c = c;
651 edtk_debug("%s: threadid = %lx", __FUNCTION__, pthread_self());
652 c->o.ret_grptr = getgrgid(
653 c->i.gid
655 if (c->o.ret_grptr != NULL) {
656 c->o.__expect = 1;
657 } else {
658 c->o.__expect = 0;
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());
666 static void
667 invoke__getgroups(void *data)
669 callstate_t *c = (callstate_t *) data;
671 c = c;
672 edtk_debug("%s: threadid = %lx", __FUNCTION__, pthread_self());
673 c->o.ret_int = my_getgroups(
674 c->o.gidset
676 if (c->o.ret_int >= 0) {
677 c->o.__expect = 1;
678 } else {
679 c->o.__expect = 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());
687 static void
688 invoke__getpwnam(void *data)
690 callstate_t *c = (callstate_t *) data;
692 c = c;
693 edtk_debug("%s: threadid = %lx", __FUNCTION__, pthread_self());
694 c->o.ret_pwptr = getpwnam(
695 c->i.login
697 if (c->o.ret_pwptr != NULL) {
698 c->o.__expect = 1;
699 } else {
700 c->o.__expect = 0;
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());
708 static void
709 invoke__getpwuid(void *data)
711 callstate_t *c = (callstate_t *) data;
713 c = c;
714 edtk_debug("%s: threadid = %lx", __FUNCTION__, pthread_self());
715 c->o.ret_pwptr = getpwuid(
716 c->i.uid
718 if (c->o.ret_pwptr != NULL) {
719 c->o.__expect = 1;
720 } else {
721 c->o.__expect = 0;
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());
729 static void
730 invoke__getuid(void *data)
732 callstate_t *c = (callstate_t *) data;
734 c = c;
735 edtk_debug("%s: threadid = %lx", __FUNCTION__, pthread_self());
736 c->o.ret_uid_t = getuid(
738 if (c->o.ret_uid_t >= 0) {
739 c->o.__expect = 1;
740 } else {
741 c->o.__expect = 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());
749 static void
750 invoke__geteuid(void *data)
752 callstate_t *c = (callstate_t *) data;
754 c = c;
755 edtk_debug("%s: threadid = %lx", __FUNCTION__, pthread_self());
756 c->o.ret_uid_t = geteuid(
758 if (c->o.ret_uid_t >= 0) {
759 c->o.__expect = 1;
760 } else {
761 c->o.__expect = 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());
769 static void
770 invoke__getlogin(void *data)
772 callstate_t *c = (callstate_t *) data;
774 c = c;
775 edtk_debug("%s: threadid = %lx", __FUNCTION__, pthread_self());
776 c->o.ret_char_p = getlogin(
778 if (c->o.ret_char_p != NULL) {
779 c->o.__expect = 1;
780 } else {
781 c->o.__expect = 0;
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());
789 static void
790 invoke__getpgrp(void *data)
792 callstate_t *c = (callstate_t *) data;
794 c = c;
795 edtk_debug("%s: threadid = %lx", __FUNCTION__, pthread_self());
796 c->o.ret_pid_t = getpgrp(
798 if (c->o.ret_pid_t >= 0) {
799 c->o.__expect = 1;
800 } else {
801 c->o.__expect = 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());
809 static void
810 invoke__getppid(void *data)
812 callstate_t *c = (callstate_t *) data;
814 c = c;
815 edtk_debug("%s: threadid = %lx", __FUNCTION__, pthread_self());
816 c->o.ret_pid_t = getppid(
818 if (c->o.ret_pid_t >= 0) {
819 c->o.__expect = 1;
820 } else {
821 c->o.__expect = 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());
829 static void
830 invoke__getsid(void *data)
832 callstate_t *c = (callstate_t *) data;
834 c = c;
835 edtk_debug("%s: threadid = %lx", __FUNCTION__, pthread_self());
836 c->o.ret_pid_t = getsid(
837 c->i.pid
839 if (c->o.ret_pid_t >= 0) {
840 c->o.__expect = 1;
841 } else {
842 c->o.__expect = 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());
850 static void
851 invoke__kill(void *data)
853 callstate_t *c = (callstate_t *) data;
855 c = c;
856 edtk_debug("%s: threadid = %lx", __FUNCTION__, pthread_self());
857 c->o.ret_int = kill(
858 c->i.pid,
859 c->i.sig
861 if (c->o.ret_int >= 0) {
862 c->o.__expect = 1;
863 } else {
864 c->o.__expect = 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());
872 static void
873 invoke__lstat(void *data)
875 callstate_t *c = (callstate_t *) data;
877 c = c;
878 edtk_debug("%s: threadid = %lx", __FUNCTION__, pthread_self());
879 c->o.ret_int = lstat(
880 c->i.path,
881 & c->o.sb
883 if (c->o.ret_int >= 0) {
884 c->o.__expect = 1;
885 } else {
886 c->o.__expect = 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());
894 static void
895 invoke__mkfifo(void *data)
897 callstate_t *c = (callstate_t *) data;
899 c = c;
900 edtk_debug("%s: threadid = %lx", __FUNCTION__, pthread_self());
901 c->o.ret_int = mkfifo(
902 c->i.path,
903 c->i.mode
905 if (c->o.ret_int >= 0) {
906 c->o.__expect = 1;
907 } else {
908 c->o.__expect = 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());
916 static void
917 invoke__mknod(void *data)
919 callstate_t *c = (callstate_t *) data;
921 c = c;
922 edtk_debug("%s: threadid = %lx", __FUNCTION__, pthread_self());
923 c->o.ret_int = mknod(
924 c->i.path,
925 c->i.mode,
926 c->i.dev
928 if (c->o.ret_int >= 0) {
929 c->o.__expect = 1;
930 } else {
931 c->o.__expect = 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());
939 static void
940 invoke__umask(void *data)
942 callstate_t *c = (callstate_t *) data;
944 c = c;
945 edtk_debug("%s: threadid = %lx", __FUNCTION__, pthread_self());
946 c->o.ret_int = umask(
947 c->i.numask
949 if (c->o.ret_int >= 0) {
950 c->o.__expect = 1;
951 } else {
952 c->o.__expect = 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());
961 static int
962 reply_ok(descriptor_t *desc)
964 ErlDrvTermData msg[15]; /* XXX too big */
965 int i = 0;
966 int res;
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);
974 return res;
977 static int
978 reply_ok_num(descriptor_t *desc, unsigned long num)
980 ErlDrvTermData msg[15]; /* XXX too big */
981 int i = 0;
982 int res;
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);
991 return res;
994 static int
995 reply_ok_binary(descriptor_t *desc, char *ptr, int beg_offset, int length)
997 ErlDrvTermData msg[15]; /* XXX too big */
998 int i = 0;
999 int res;
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);
1019 return res;
1022 static int
1023 reply_ok_valmap(descriptor_t *desc, ErlDrvTermData valmap_atom,
1024 unsigned long valmap_index)
1026 ErlDrvTermData msg[15];
1027 int i = 0;
1028 int res;
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);
1039 return res;
1042 static int
1043 reply_error(descriptor_t *desc, int errnum)
1045 ErlDrvTermData msg[15]; /* XXX too big */
1046 int i = 0;
1047 int res;
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);
1057 return res;
1060 static int
1061 reply_error_atom(descriptor_t *desc, ErlDrvTermData atom)
1063 ErlDrvTermData msg[15]; /* XXX too big */
1064 int i = 0;
1065 int res;
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);
1074 return res;
1077 #if 0 /* QQQ These are unused right now */
1078 static int
1079 reply_tag_ok(descriptor_t *desc, unsigned short tag)
1081 ErlDrvTermData msg[15]; /* XXX too big */
1082 int i = 0;
1083 int res;
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);
1092 return res;
1095 static int
1096 reply_tag_error(descriptor_t *desc, unsigned short tag, int errnum)
1098 ErlDrvTermData msg[15]; /* XXX too big */
1099 int i = 0;
1100 int res;
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);
1111 return res;
1113 #endif /* 0 */
1116 static int
1117 reply_xtra_stat(descriptor_t *desc, callstate_t *c)
1119 ErlDrvTermData msg[64];
1120 int msgcount = 0;
1121 int res;
1122 int members = 0;
1123 char *tmp = NULL;
1124 ErlDrvBinary *tofree[64];
1125 int num_tofree = 0;
1126 int i;
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);
1135 int members = 0;
1137 int members = 0;
1139 msgcount = LOAD_ATOM(msg, msgcount, am_stat);
1140 members++;
1141 msgcount = LOAD_INT(msg, msgcount, c->o.sb.st_dev);
1142 members++;
1143 msgcount = LOAD_INT(msg, msgcount, c->o.sb.st_ino);
1144 members++;
1145 msgcount = LOAD_INT(msg, msgcount, c->o.sb.st_mode);
1146 members++;
1147 msgcount = LOAD_INT(msg, msgcount, c->o.sb.st_nlink);
1148 members++;
1149 msgcount = LOAD_INT(msg, msgcount, c->o.sb.st_uid);
1150 members++;
1151 msgcount = LOAD_INT(msg, msgcount, c->o.sb.st_gid);
1152 members++;
1153 msgcount = LOAD_INT(msg, msgcount, c->o.sb.st_rdev);
1154 members++;
1155 msgcount = LOAD_INT(msg, msgcount, c->o.sb.st_atime);
1156 members++;
1157 msgcount = LOAD_INT(msg, msgcount, c->o.sb.st_mtime);
1158 members++;
1159 msgcount = LOAD_INT(msg, msgcount, c->o.sb.st_ctime);
1160 members++;
1161 msgcount = LOAD_INT(msg, msgcount, c->o.sb.st_size);
1162 members++;
1163 msgcount = LOAD_INT(msg, msgcount, c->o.sb.st_blocks);
1164 members++;
1165 msgcount = LOAD_INT(msg, msgcount, c->o.sb.st_blksize);
1166 members++;
1167 msgcount = LOAD_TUPLE(msg, msgcount, members); /* XXX */
1169 members++;
1170 msgcount = LOAD_TUPLE(msg, msgcount, members);
1172 } else {
1173 msgcount = LOAD_ATOM(msg, msgcount, am_error);
1175 int members = 0;
1176 msgcount = LOAD_INT(msg, msgcount, errno);
1177 members++;
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);
1185 if (res < 0) {
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]);
1192 return res;
1195 static int
1196 reply_xtra_passwd(descriptor_t *desc, callstate_t *c)
1198 ErlDrvTermData msg[64];
1199 int msgcount = 0;
1200 int res;
1201 int members = 0;
1202 char *tmp = NULL;
1203 ErlDrvBinary *tofree[64];
1204 int num_tofree = 0;
1205 int i;
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);
1214 int members = 0;
1216 int members = 0;
1218 msgcount = LOAD_ATOM(msg, msgcount, am_passwd);
1219 members++;
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;
1228 members++;
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;
1237 members++;
1238 msgcount = LOAD_INT(msg, msgcount, c->o.ret_pwptr->pw_uid);
1239 members++;
1240 msgcount = LOAD_INT(msg, msgcount, c->o.ret_pwptr->pw_gid);
1241 members++;
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;
1250 members++;
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;
1259 members++;
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;
1268 members++;
1269 msgcount = LOAD_TUPLE(msg, msgcount, members); /* XXX */
1271 members++;
1272 msgcount = LOAD_TUPLE(msg, msgcount, members);
1274 } else {
1275 msgcount = LOAD_ATOM(msg, msgcount, am_error);
1277 int members = 0;
1278 msgcount = LOAD_INT(msg, msgcount, c->o.__expect_errval);
1279 members++;
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);
1287 if (res < 0) {
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]);
1294 return res;
1297 static int
1298 reply_xtra_group(descriptor_t *desc, callstate_t *c)
1300 ErlDrvTermData msg[64];
1301 int msgcount = 0;
1302 int res;
1303 int members = 0;
1304 char *tmp = NULL;
1305 ErlDrvBinary *tofree[64];
1306 int num_tofree = 0;
1307 int i;
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);
1316 int members = 0;
1318 int members = 0;
1320 msgcount = LOAD_ATOM(msg, msgcount, am_group);
1321 members++;
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;
1330 members++;
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;
1339 members++;
1340 msgcount = LOAD_INT(msg, msgcount, c->o.ret_grptr->gr_gid);
1341 members++;
1343 int members = 0;
1345 make_groups_list(desc, c, msg, &members, &msgcount);
1346 msgcount = LOAD_LIST(msg, msgcount, members); /* XXX */
1348 members++;
1349 msgcount = LOAD_TUPLE(msg, msgcount, members); /* XXX */
1351 members++;
1352 msgcount = LOAD_TUPLE(msg, msgcount, members);
1354 } else {
1355 msgcount = LOAD_ATOM(msg, msgcount, am_error);
1357 int members = 0;
1358 msgcount = LOAD_INT(msg, msgcount, c->o.__expect_errval);
1359 members++;
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);
1367 if (res < 0) {
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]);
1374 return res;
1377 static int
1378 reply_xtra_getgroups(descriptor_t *desc, callstate_t *c)
1380 ErlDrvTermData msg[64];
1381 int msgcount = 0;
1382 int res;
1383 int members = 0;
1384 char *tmp = NULL;
1385 ErlDrvBinary *tofree[64];
1386 int num_tofree = 0;
1387 int i;
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);
1396 int members = 0;
1398 int members = 0;
1400 msgcount = LOAD_INT(msg, msgcount, c->o.ret_int);
1401 members++;
1403 int members = 0;
1405 make_getgroups_list(desc, c, msg, &members, &msgcount);
1406 msgcount = LOAD_LIST(msg, msgcount, members); /* XXX */
1408 members++;
1409 msgcount = LOAD_TUPLE(msg, msgcount, members); /* XXX */
1411 members++;
1412 msgcount = LOAD_TUPLE(msg, msgcount, members);
1414 } else {
1415 msgcount = LOAD_ATOM(msg, msgcount, am_error);
1417 int members = 0;
1418 msgcount = LOAD_INT(msg, msgcount, errno);
1419 members++;
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);
1427 if (res < 0) {
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]);
1434 return res;