?? serial.c
字號:
/* $Id: serial.c,v 1.29.2.4 2004/05/12 02:04:38 alan Exp $ *//* * Linux-HA serial heartbeat code * * The basic facilities for round-robin (ring) heartbeats are * contained within. * * Copyright (C) 1999, 2000, 2001 Alan Robertson <alanr@unix.sh> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */#include <portability.h>#include <unistd.h>#include <errno.h>#include <stdio.h>#include <stdlib.h>#include <ctype.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h>#include <time.h>#include <fcntl.h>#include <sys/wait.h>#include <sys/utsname.h>#include <sys/stat.h>#include <sys/param.h>#include <heartbeat.h>#include <HBcomm.h>#include <clplumbing/longclock.h>#include <clplumbing/timers.h>#define PIL_PLUGINTYPE HB_COMM_TYPE#define PIL_PLUGINTYPE_S HB_COMM_TYPE_S#define PIL_PLUGIN serial#define PIL_PLUGIN_S "serial"#define PIL_PLUGINLICENSE LICENSE_LGPL#define PIL_PLUGINLICENSEURL URL_LGPL#include <pils/plugin.h>struct serial_private { char * ttyname; int ttyfd; /* For direct TTY i/o */ int consecutive_errors; struct hb_media* next;};static int serial_baud = 0;static const char * baudstring;/* Used to maintain a list of our serial ports in the ring */static struct hb_media* lastserialport;static struct hb_media* serial_new(const char * value);static void* serial_read(struct hb_media *mp, int* lenp);static char * ttygets(char * inbuf, int length, struct serial_private *tty);static int serial_write(struct hb_media*mp, void *msg , int len);static int serial_open(struct hb_media* mp);static int ttysetup(int fd, const char * ourtty);static int opentty(char * serial_device);static int serial_close(struct hb_media* mp);static int serial_init(void);static void serial_localdie(void);static int serial_mtype(char **buffer);static int serial_descr(char **buffer);static int serial_isping(void);/* * serialclosepi is called as part of unloading the serial HBcomm plugin. * If there was any global data allocated, or file descriptors opened, etc. * which is associated with the plugin, and not a single interface * in particular, here's our chance to clean it up. */static voidserialclosepi(PILPlugin*pi){ serial_localdie();}/* * serialcloseintf called as part of shutting down the serial HBcomm interface. * If there was any global data allocated, or file descriptors opened, etc. * which is associated with the serial implementation, here's our chance * to clean it up. */static PIL_rcserialcloseintf(PILInterface* pi, void* pd){ return PIL_OK;}static struct hb_media_fns serialOps ={ serial_new, /* Create single object function */ NULL, /* whole-line parse function */ serial_open, serial_close, serial_read, serial_write, serial_mtype, serial_descr, serial_isping,};PIL_PLUGIN_BOILERPLATE("1.0", Debug, serialclosepi);static const PILPluginImports* PluginImports;static PILPlugin* OurPlugin;static PILInterface* OurInterface;static struct hb_media_imports* OurImports;static void* interfprivate;#define LOG PluginImports->log#define MALLOC PluginImports->alloc#define STRDUP PluginImports->mstrdup#define FREE PluginImports->mfreePIL_rcPIL_PLUGIN_INIT(PILPlugin*us, const PILPluginImports* imports);PIL_rcPIL_PLUGIN_INIT(PILPlugin*us, const PILPluginImports* imports){ PIL_rc rc; /* Force the compiler to do a little type checking */ (void)(PILPluginInitFun)PIL_PLUGIN_INIT; PluginImports = imports; OurPlugin = us; /* Register ourself as a plugin */ imports->register_plugin(us, &OurPIExports); /* Register our interface implementation */ rc = imports->register_interface(us, PIL_PLUGINTYPE_S , PIL_PLUGIN_S , &serialOps , serialcloseintf /*close */ , &OurInterface , (void*)&OurImports , interfprivate); serial_init(); return rc;}#define IsTTYOBJECT(mp) ((mp) && ((mp)->vf == (void*)&serial_media_fns))/*#define TTYASSERT(mp) ASSERT(IsTTYOBJECT(mp))*/#define TTYASSERT(mp)#define RTS_WARNTIME 3600static intserial_mtype (char **buffer) { *buffer = STRDUP("serial"); if (!*buffer) { return 0; } return strlen(*buffer);}static intserial_descr (char **buffer) { *buffer = STRDUP("serial ring"); if (!*buffer) { return 0; } return strlen(*buffer);}static intserial_isping (void) { return 0;}/* Initialize global serial data structures */static intserial_init (void){ lastserialport = NULL; /* This eventually ought be done through the configuration API */ if (serial_baud <= 0) { if ((baudstring = OurImports->ParamValue("baud")) != NULL) { serial_baud = OurImports->StrToBaud(baudstring); } } if (serial_baud <= 0 || baudstring == NULL) { serial_baud = DEFAULTBAUD; baudstring = DEFAULTBAUDSTR; } if (ANYDEBUG) { PILCallLog(LOG, PIL_DEBUG, "serial_init: serial_baud = 0x%x" , serial_baud); } return(HA_OK);}/* Process a serial port declaration */static struct hb_media *serial_new (const char * port){ struct stat sbuf; struct hb_media * ret; /* Let's see if this looks like it might be a serial port... */ if (*port != '/') { PILCallLog(LOG, PIL_CRIT , "Serial port not full pathname [%s] in config file" , port); return(NULL); } if (stat(port, &sbuf) < 0) { PILCallLog(LOG, PIL_CRIT, "Nonexistent serial port [%s] in config file" , port); return(NULL); } if (!S_ISCHR(sbuf.st_mode)) { PILCallLog(LOG, PIL_CRIT , "Serial port [%s] not a char device in config file" , port); return(NULL); } ret = (struct hb_media*)MALLOC(sizeof(struct hb_media)); if (ret != NULL) { struct serial_private * sp; sp = (struct serial_private*) MALLOC(sizeof(struct serial_private)); if (sp != NULL) { /* * This implies we have to process the "new" * for this object in the parent process of us all... * otherwise we can't do this linking stuff... */ sp->next = lastserialport; lastserialport=ret; sp->ttyname = STRDUP(port); if (sp->ttyname != NULL) { sp->consecutive_errors = 0; ret->name = sp->ttyname; ret->pd = sp; }else{ FREE(sp); sp = NULL; } } if (sp == NULL) { FREE(ret); ret = NULL; PILCallLog(LOG, PIL_CRIT, "Out of memory (private serial data)"); } }else{ PILCallLog(LOG, PIL_CRIT, "Out of memory (serial data)"); } return(ret);}static intserial_open (struct hb_media* mp){ struct serial_private* sp; TTYASSERT(mp); sp = (struct serial_private*)mp->pd; if (OurImports->devlock(sp->ttyname) < 0) { PILCallLog(LOG, PIL_CRIT, "cannot lock line %s", sp->ttyname); return(HA_FAIL); } if ((sp->ttyfd = opentty(sp->ttyname)) < 0) { return(HA_FAIL); } PILCallLog(LOG, PIL_INFO, "Starting serial heartbeat on tty %s (%s baud)" , sp->ttyname, baudstring); return(HA_OK);}static intserial_close (struct hb_media* mp){ struct serial_private* sp; int rc; TTYASSERT(mp); sp = (struct serial_private*)mp->pd; rc = close(sp->ttyfd) < 0 ? HA_FAIL : HA_OK; OurImports->devunlock(sp->ttyname); return rc;}/* Set up a serial line the way we want it be done */static intttysetup(int fd, const char * ourtty){ struct TERMIOS ti; if (GETATTR(fd, &ti) < 0) { PILCallLog(LOG, PIL_CRIT, "cannot get tty attributes: %s", strerror(errno)); return(HA_FAIL); }#ifndef IUCLC# define IUCLC 0 /* Ignore it if not supported */#endif#ifndef CBAUD# define CBAUD 0#endif ti.c_iflag &= ~(IGNBRK|IUCLC|IXANY|IXOFF|IXON|ICRNL|PARMRK); /* Unsure if I want PARMRK or not... It may not matter much */ ti.c_iflag |= (INPCK|ISTRIP|IGNCR|BRKINT); ti.c_oflag &= ~(OPOST); ti.c_cflag &= ~(CBAUD|CSIZE|PARENB);#ifndef CRTSCTS# define CRTSCTS 0 /* AIX and others don't have this */#endif/* * Make a silly Linux/Gcc -Wtraditional warning go away * This is not my fault, you understand... ;-) * Suggestions on how to better work around it would be welcome. */#if CRTSCTS == 020000000000# undef CRTSCTS# define CRTSCTS 020000000000U#endif ti.c_cflag |= (serial_baud|(unsigned)CS8|(unsigned)CREAD | (unsigned)CLOCAL|(unsigned)CRTSCTS); ti.c_lflag &= ~(ICANON|ECHO|ISIG);#ifdef HAVE_TERMIOS_C_LINE ti.c_line = 0;#endif ti.c_cc[VMIN] = 1; ti.c_cc[VTIME] = 1; if (SETATTR(fd, &ti) < 0) { PILCallLog(LOG, PIL_CRIT, "cannot set tty attributes: %s" , strerror(errno)); return(HA_FAIL); } if (ANYDEBUG) { PILCallLog(LOG, PIL_DEBUG, "tty setup on %s complete.", ourtty); PILCallLog(LOG, PIL_DEBUG, "Baud rate set to: 0x%x", serial_baud); PILCallLog(LOG, PIL_DEBUG, "ti.c_iflag = 0x%x", ti.c_iflag); PILCallLog(LOG, PIL_DEBUG, "ti.c_oflag = 0x%x", ti.c_oflag); PILCallLog(LOG, PIL_DEBUG, "ti.c_cflag = 0x%x", ti.c_cflag); PILCallLog(LOG, PIL_DEBUG, "ti.c_lflag = 0x%x", ti.c_lflag); } /* For good measure */ FLUSH(fd); tcsetpgrp(fd, getsid(getpid())); return(HA_OK);}#ifndef O_NOCTTY# define O_NOCTTY 0 /* Ignore it if not supported */#endif/* Open a tty and set it's line parameters */static intopentty(char * serial_device){ int fd; if ((fd=open(serial_device, O_RDWR|O_NOCTTY)) < 0 ) { PILCallLog(LOG, PIL_CRIT, "cannot open %s: %s", serial_device , strerror(errno)); return(fd); } if (!ttysetup(fd, serial_device)) { close(fd); return(-1); } if (fcntl(fd, F_SETFD, FD_CLOEXEC)) { PILCallLog(LOG, PIL_WARN,"Error setting the close-on-exec flag: %s" , strerror(errno)); } /* Cause the other guy to flush his I/O */ tcsendbreak(fd, 0); return(fd);}static struct hb_media* ourmedia = NULL;static voidserial_localdie(void){ int ourtty; if (!ourmedia || !ourmedia->pd) { return; } ourtty = ((struct serial_private*)(ourmedia->pd))->ttyfd; if (ourtty >= 0) { if (ANYDEBUG) { PILCallLog(LOG, PIL_DEBUG, "serial_localdie: Flushing tty"); } tcflush(ourtty, TCIOFLUSH); }}/* This function does all the reading from our tty ports */static void *serial_read(struct hb_media* mp, int *lenp){ char buf[MAXLINE]; struct serial_private* thissp; int startlen; const char * start = MSG_START; const char * end = MSG_END; int endlen; char *msgstring; char *p; int len = 0; int tmplen; TTYASSERT(mp); thissp = (struct serial_private*)mp->pd; startlen = strlen(start); if (start[startlen-1] == '\n') { --startlen; } endlen = strlen(end); if (end[endlen-1] == '\n') { --endlen; } msgstring = ha_calloc(MAXMSG,1 ); if(!msgstring){ PILCallLog(LOG, PIL_CRIT, "serial_read: cannot allocate memory to msgstring "); return(NULL); } msgstring[0] = 0; p = msgstring; /* Skip until we find a MSG_START (hopefully we skip nothing) */ while (ttygets(buf, MAXLINE, thissp) != NULL && strncmp(buf, start, startlen) != 0) { /*nothing*/ } len = strnlen(buf, MAXLINE) + 1; if(len >= MAXMSG){ PILCallLog(LOG, PIL_CRIT, "serial_read:MSG_START exceeds MAXMSG"); ha_free(msgstring); return(NULL); } tmplen = strnlen(buf, MAXLINE); strcat(p, buf); p += tmplen; strcat(p, "\n"); p++; while (ttygets(buf, MAXLINE, thissp) != NULL && strncmp(buf, MSG_END, endlen) != 0) { len += strnlen(buf, MAXLINE) + 1; if(len >= MAXMSG){ PILCallLog(LOG, PIL_CRIT, "serial_read:msgstring exceeds MAXMSG"); ha_free(msgstring); return(NULL); } tmplen = strnlen(buf, MAXLINE); memcpy(p, buf, tmplen); p += tmplen; strcat(p, "\n"); p++;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -