trace_file_drv.c
来自「OTP是开放电信平台的简称」· C语言 代码 · 共 638 行 · 第 1/2 页
C
638 行
/* ``The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved via the world wide web at http://www.erlang.org/. * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. * * The Initial Developer of the Original Code is Ericsson Utvecklings AB. * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings * AB. All Rights Reserved.'' * * $Id$ *//* * Purpose: Send trace messages to a file. */#ifdef HAVE_CONFIG_H# include "config.h"#endif#include <limits.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#ifdef __WIN32__# include <io.h># define write _write# define open _open# define close _close# define unlink _unlink#else# include <unistd.h>#endif#include <errno.h>#include <sys/types.h>#include <fcntl.h>#ifdef VXWORKS# include "reclaim.h"#endif/* * Deduce MAXPATHLEN, which is the one to use in this file, * from any available definition. */#ifndef MAXPATHLEN# ifdef PATH_MAX /* Posix */# define MAXPATHLEN PATH_MAX# else# ifdef _POSIX_PATH_MAX /* Posix */# define MAXPATHLEN _POSIX_PATH_MAX# else# ifdef MAXPATH# define MAXPATHLEN MAXPATH# else# ifdef MAX_PATH# define MAXPATHLEN MAX_PATH# else# ifdef _MAX_PATH# define MAXPATHLEN _MAX_PATH# else# error Could not define MAXPATHLEN# endif# endif# endif# endif# endif#endif#ifdef DEBUG#ifndef __WIN32__#define ASSERT(X) do {if (!(X)) {erl_exit(1,"%s",#X);} } while(0)#else#include <assert.h>#define ASSERT(X) assert(X)#endif#else#define ASSERT(X)#endif#include "erl_driver.h"/*** Protocol from driver:** '\0' -> ok** '\1' ++ String -> {error, Atom}**** Protocol when opening (arguments to start):** ["w <WrapSize> <WrapCnt> <TailIndex> "] "n <Filename>"** Where...** <Filename>, a string ('\0' terminated):** The filename where the trace output is to be written.** "w ...", if present orders a size limited wrapping log.** <WrapSize>, an unsigned integer:** The size limit of each log file.** <WrapCnt>, an unsigned integer:** The number of log files.** <TailIndex>, an unsigned integer:** The (zero based) index of where to insert the filename** sequence count "a".."z","aa".."az","ba".."zz","aaa"...**** Port control messages handled:** 'f' -> '\0' (ok) | '\1' ++ String (error) : Flush file.**** The package written to the file looks like this:** +--+--------+-----------------------------------+** |Op|Size NBO|Term in external format or empty |** +--+--------+-----------------------------------+** Op, a char, for conformance with the IP driver:** 0 = binary, 1 = drop** If Op is 1, then Size reflects the number of dropped messages. The ** op 1 is never used in this driver.** Size, a 32 bit interger in network byte order:** Either the size of the binary term, or the number of packet's dropped.** Term, an array of bytes:** An erlang term in the external format or simply empty if Op == 1, the** term is Size long.*/ typedef int FILETYPE;#define BUFFER_SIZE (BUFSIZ*8)#define OP_BINARY 0#define OP_DROP 1/*** State structures*/typedef struct trace_file_name { char name[MAXPATHLEN+1]; /* Incl. space for terminating '\0' */ unsigned suffix; /* Index of suffix start */ unsigned tail; /* Index of tail start */ unsigned len; /* Total length (strlen) */ unsigned cnt; /* Current file count 0 <= cnt <= n */ unsigned n; /* Number of files */} TraceFileName;typedef struct trace_file_wrap_data { TraceFileName cur; /* Current trace file */ TraceFileName del; /* Next file to delete when wrapping */ unsigned size; /* File max size */ int cnt; /* How many remains before starting to wrap */ unsigned long time; /* Time to pass until starting to delete old files */ unsigned len; /* Current file len */} TraceFileWrapData;typedef struct trace_file_data { FILETYPE fd; ErlDrvPort port; struct trace_file_data *next, *prev; TraceFileWrapData *wrap; /* == NULL => no wrap */ int buff_siz; int buff_pos; unsigned char buff[1]; /* You guessed it, will be longer... */} TraceFileData;static TraceFileData *first_data; /*** Interface routines*/static ErlDrvData trace_file_start(ErlDrvPort port, char *buff);static void trace_file_stop(ErlDrvData handle);static void trace_file_output(ErlDrvData handle, char *buff, int bufflen);static void trace_file_finish(void);static int trace_file_control(ErlDrvData handle, unsigned int command, char* buff, int count, char** res, int res_size);static void trace_file_timeout(ErlDrvData handle);/*** Internal routines*/static unsigned digits(unsigned n);static void next_name(TraceFileName *tfn);static void *my_alloc(size_t size);static int my_write(TraceFileData *data, unsigned char *buff, int siz);static int my_flush(TraceFileData *data);static void put_be(unsigned n, unsigned char *s);static void close_unlink_port(TraceFileData *data); static int wrap_file(TraceFileData *data);/*** The driver struct*/ErlDrvEntry trace_file_driver_entry = { NULL, /* F_PTR init, N/A */ trace_file_start, /* L_PTR start, called when port is opened */ trace_file_stop, /* F_PTR stop, called when port is closed */ trace_file_output, /* F_PTR output, called when erlang has sent */ NULL, /* F_PTR ready_input, called when input descriptor ready */ NULL, /* F_PTR ready_output, called when output descriptor ready */ "trace_file_drv", /* char *driver_name, the argument to open_port */ trace_file_finish, /* F_PTR finish, called when unloaded */ NULL, /* void * that is not used (BC) */ trace_file_control, /* F_PTR control, port_control callback */ trace_file_timeout, /* F_PTR timeout, driver_set_timer callback */ NULL /* F_PTR outputv, reserved */};/*** Driver initialization routine*/DRIVER_INIT(trace_file_drv){ first_data = NULL; return &trace_file_driver_entry;}/*** Driver interface routines*//*** 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;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?