static ErlDrvData start(ErlDrvPort port, char *command) { mcd_data_t *mcd = driver_alloc(sizeof(mcd_data_t)); if (!mcd) goto error; mcd->ofd = -1; mcd->ifd = -1; #ifdef UNIX mcd->ofd = open("/dev/null", O_WRONLY); if (mcd->ofd < 0) goto error; if (driver_select(port, (ErlDrvEvent) (long) mcd->ofd, DO_WRITE, 1) != 0) goto error; mcd->ifd = open("/dev/zero", O_RDONLY); if (mcd->ifd < 0) goto error; if (driver_select(port, (ErlDrvEvent) (long) mcd->ifd, DO_READ, 1) != 0) goto error; #endif driver_set_timer(port, 0); return (ErlDrvData) mcd; error: stop((ErlDrvData) mcd); return ERL_DRV_ERROR_GENERAL; }
/* ** Timeout from driver_set_timer. */ static void trace_file_timeout(ErlDrvData handle) { TraceFileData *data = (TraceFileData *) handle; if (data->wrap) { if (wrap_file(data) < 0) { driver_failure_posix(data->port, errno); /* XXX */ return; } else { driver_set_timer(data->port, data->wrap->time); } } }
/* set the timer, this is monitored from erlang measuring the time */ static void timer_read(ErlDrvData p, char *buf, ErlDrvSizeT len) { ErlDrvPort port = (ErlDrvPort) p; char reply[1]; if (buf[0] == START_TIMER) { /* fprintf(stderr, "[timer_drv] Setting timeout: %i\n", get_int32(buf + 1)); */ driver_set_timer(port, get_int32(buf + 1)); } else if (buf[0] == CANCEL_TIMER) { /* fprintf(stderr, "[timer_drv] Timer cancelled\n"); */ driver_cancel_timer(port); reply[0] = CANCELLED; driver_output(port, reply, 1); } }
/* ** Open a port */ static ErlDrvData trace_file_start(ErlDrvPort port, char *buff) { unsigned size, cnt, time, tail, len; char *p; TraceFileData *data; TraceFileWrapData *wrap; FILETYPE fd; int n, w; static const char name[] = "trace_file_drv"; #ifdef HARDDEBUG fprintf(stderr,"hello (%s)\r\n", buff); #endif w = 0; /* Index of where sscanf gave up */ size = 0; /* Warning elimination */ cnt = 0; /* -""- */ time = 0; /* -""- */ tail = 0; /* -""- */ n = sscanf(buff, "trace_file_drv %n w %u %u %u %u %n", &w, &size, &cnt, &time, &tail, &w); if (w < sizeof(name) || (n != 0 && n != 4)) return ERL_DRV_ERROR_BADARG; /* Search for "n <Filename>" in the rest of the string */ p = buff + w; for (p = buff + w; *p == ' '; p++); /* Skip space (necessary?) */ if (*p++ != 'n') return ERL_DRV_ERROR_BADARG; if (*p++ != ' ') return ERL_DRV_ERROR_BADARG; /* Here we are at the start of the filename; p */ len = strlen(p); if (tail >= len) /* Tail must start within filename */ return ERL_DRV_ERROR_BADARG; data = my_alloc(sizeof(TraceFileData) - 1 + BUFFER_SIZE); /* We have to check the length in case we are running on * VxWorks since too long pathnames may cause bus errors * instead of error return from file operations. */ if (n == 4) { /* Size limited wrapping log */ unsigned d = digits(cnt); /* Nof digits in filename counter */ if (len+d >= MAXPATHLEN) { errno = ENAMETOOLONG; return ERL_DRV_ERROR_ERRNO; } wrap = my_alloc(sizeof(TraceFileWrapData)); wrap->size = size; wrap->cnt = cnt; wrap->time = time; wrap->len = 0; strcpy(wrap->cur.name, p); wrap->cur.suffix = tail; wrap->cur.tail = tail; wrap->cur.len = len; wrap->cur.cnt = cnt; wrap->cur.n = cnt; next_name(&wrap->cur); /* Incr to suffix "0" */ wrap->del = wrap->cur; /* Struct copy! */ p = wrap->cur.name; /* Use new name for open */ } else { /* Regular log */ if (len >= MAXPATHLEN) { errno = ENAMETOOLONG; return ERL_DRV_ERROR_ERRNO; } wrap = NULL; } if ((fd = open(p, O_WRONLY | O_TRUNC | O_CREAT #ifdef O_BINARY | O_BINARY #endif , 0777)) < 0) { if (wrap) driver_free(wrap); driver_free(data); return ERL_DRV_ERROR_ERRNO; } data->fd = fd; data->port = port; data->buff_siz = BUFFER_SIZE; data->buff_pos = 0; data->wrap = wrap; if (first_data) { data->prev = first_data->prev; first_data->prev = data; } else data->prev = NULL; data->next = first_data; first_data = data; if (wrap && wrap->time > 0) driver_set_timer(port, wrap->time); return (ErlDrvData) data; }
static void echo_drv_output(ErlDrvData drv_data, char *buf, ErlDrvSizeT len) { EchoDrvData* data_p = (EchoDrvData *) drv_data; ErlDrvPort port = data_p->erlang_port; switch (buf[0]) { case ECHO_DRV_OUTPUT: { driver_output(port, buf+1, len-1); break; } case ECHO_DRV_OUTPUT2: { driver_output2(port, "a", 1, buf+1, len-1); break; } case ECHO_DRV_OUTPUT_BINARY: { ErlDrvBinary *bin = driver_alloc_binary(len-1); memcpy(&bin->orig_bytes, buf+1, len-1); driver_output_binary(port, "a", 1, bin, 1, len - 2); driver_free_binary(bin); break; } case ECHO_DRV_OUTPUTV: { ErlIOVec iov; ErlDrvSizeT sz; driver_enq(port, buf + 1, len - 1); sz = driver_peekqv(port, &iov); driver_outputv(port, "a", 1, &iov, 0); driver_deq(port, sz); break; } case ECHO_DRV_SET_TIMER: { driver_set_timer(port, 10); break; } case ECHO_DRV_FAILURE_EOF: { driver_failure_eof(port); break; } case ECHO_DRV_FAILURE_ATOM: { driver_failure_atom(port, buf+1); break; } case ECHO_DRV_FAILURE_POSIX: { driver_failure_posix(port, EAGAIN); break; } case ECHO_DRV_FAILURE: { driver_failure(port, buf[1]); break; } case ECHO_DRV_OUTPUT_TERM: case ECHO_DRV_DRIVER_OUTPUT_TERM: case ECHO_DRV_SEND_TERM: case ECHO_DRV_DRIVER_SEND_TERM: { ErlDrvTermData term[] = { ERL_DRV_ATOM, driver_mk_atom("echo"), ERL_DRV_PORT, driver_mk_port(port), ERL_DRV_BUF2BINARY, (ErlDrvTermData)(buf+1), (ErlDrvTermData)(len - 1), ERL_DRV_TUPLE, 3}; switch (buf[0]) { case ECHO_DRV_OUTPUT_TERM: erl_drv_output_term(driver_mk_port(port), term, sizeof(term) / sizeof(ErlDrvTermData)); break; case ECHO_DRV_DRIVER_OUTPUT_TERM: driver_output_term(port, term, sizeof(term) / sizeof(ErlDrvTermData)); break; case ECHO_DRV_SEND_TERM: driver_send_term(port, data_p->caller, term, sizeof(term) / sizeof(ErlDrvTermData)); break; case ECHO_DRV_DRIVER_SEND_TERM: erl_drv_send_term(driver_mk_port(port), data_p->caller, term, sizeof(term) / sizeof(ErlDrvTermData)); break; } break; } case ECHO_DRV_SAVE_CALLER: data_p->caller = driver_caller(port); break; default: break; } }