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 + -
显示快捷键?