Last active
April 19, 2021 18:06
-
-
Save tuklusan/bc4825acd6e4980ef2764e1b7bb3c4ff to your computer and use it in GitHub Desktop.
syslogd for remote logging OpenVMS Alpha and OpenVMS VAX system logger to unix/linux rsyslog syslog server daemon. Tweaked from Doug O'Neal's syslog.c. More: http://supratim-sanyal.blogspot.com/2016/11/openvms-log-files-remote-logging-to.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* syslogd.c | |
* Take OPCOM messages received over a set of pseduo-ttys and redirect | |
* them to a UNIX syslogd. Tested with Multinet and UCX software under | |
* VMS 1.5 & 6.1 (AXP) and VMS 5.5 & 6.0 (VAX). | |
* | |
* The chan structure defines the translation of the opcom classes to | |
* Unix facilities/priorities. The Unix server is defined via the | |
* logical name SYSLOGD_SERVER in the LNM$SYSTEM_TABLE logical name table. | |
* Either a host name or an IP address may be used. | |
* | |
* must be linked against either | |
* multinet:multinet_socket_library/share | |
* or | |
* sys$share:ucx$ipc_shr/share | |
* | |
* On an AXP system with UCX 3.1, /STANDARD=VAXC must be specified for CC. | |
* | |
* Doug O'Neal | |
* Homewood Academic Computing | |
* Johns Hopkins University | |
* [email protected] | |
* | |
* Modified by Supratim Sanyal (supratim at riseup.net): | |
* - 14-NOV-2016: Added logical name SYSLOGD_PORT to specify the port number of | |
* remote syslog server - required in addition to SYSLOGD_SERVER | |
* in the LNM$SYSTEM_TABLE logical name table. | |
* - 01-NOV-2017: Worked around ftname[retlen-1] which was crashing in EXE by | |
* HP C V7.3-009 on OpenVMS Alpha V8.3 | |
* http://supratim-sanyal.blogspot.com/2016/11/openvms-log-files-remote-logging-to.html | |
*/ | |
#define UCX 1 | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <time.h> | |
#include <ctype.h> | |
#include <ssdef.h> | |
#include <dvidef.h> | |
#include <descrip.h> | |
#include <stsdef.h> | |
#include <lnmdef.h> | |
#include <iodef.h> | |
#include <opcdef.h> | |
#ifdef MULTINET | |
#include "multinet_root:[multinet.include.sys]types.h" | |
#include "multinet_root:[multinet.include.sys]socket.h" | |
#include "multinet_root:[multinet.include.netinet]in.h" | |
#include "multinet_root:[multinet.include]netdb.h" | |
#endif | |
#ifdef UCX | |
#include <types.h> | |
#include <socket.h> | |
#include <in.h> | |
#include <netdb.h> | |
#include <ucx$inetdef.h> | |
#endif | |
unsigned int PTD$CREATE(); | |
unsigned int PTD$READ(); | |
unsigned int PTD$READW(); | |
unsigned int SYS$QIOW(); | |
unsigned int SYS$EXPREG(); | |
unsigned int SYS$GETDVIW(); | |
unsigned int SYS$SNDOPR(); | |
unsigned int SYS$TRNLNM(); | |
unsigned int write_syslog(); | |
int sockfd; | |
struct sockaddr_in cli_addr, serv_addr; | |
#define FT_DATA_MAX (unsigned short) 508 | |
struct ft_buffer { | |
unsigned short status, count; | |
unsigned char data[FT_DATA_MAX]; | |
}; | |
struct iosb { | |
unsigned short condition, transfer_count; | |
unsigned long info; | |
}; | |
// #define SERV_UDP_PORT 514 | |
// #define SERV_UDP_PORT 65514 | |
int SERV_UDP_PORT=514; | |
/* | |
* Facility codes | |
*/ | |
#define LOG_KERN (0<<3) /* kernel messages */ | |
#define LOG_USER (1<<3) /* random user-level messages */ | |
#define LOG_MAIL (2<<3) /* mail system */ | |
#define LOG_DAEMON (3<<3) /* system daemons */ | |
#define LOG_AUTH (4<<3) /* security/authorization messages */ | |
#define LOG_SYSLOG (5<<3) /* messages generated internally by syslogd */ | |
#define LOG_LPR (6<<3) /* line printer subsystem */ | |
#define LOG_NEWS (7<<3) /* netnews subsystem */ | |
#define LOG_UUCP (8<<3) /* uucp subsystem */ | |
#define LOG_CRON (15<<3) /* cron/at subsystem */ | |
#define LOG_LOCAL0 (16<<3) /* reserved for local use */ | |
#define LOG_LOCAL1 (17<<3) /* reserved for local use */ | |
#define LOG_LOCAL2 (18<<3) /* reserved for local use */ | |
#define LOG_LOCAL3 (19<<3) /* reserved for local use */ | |
#define LOG_LOCAL4 (20<<3) /* reserved for local use */ | |
#define LOG_LOCAL5 (21<<3) /* reserved for local use */ | |
#define LOG_LOCAL6 (22<<3) /* reserved for local use */ | |
#define LOG_LOCAL7 (23<<3) /* reserved for local use */ | |
/* | |
* Priorities (these are ordered) | |
*/ | |
#define LOG_EMERG 0 /* system is unusable */ | |
#define LOG_ALERT 1 /* action must be taken immediately */ | |
#define LOG_CRIT 2 /* critical conditions */ | |
#define LOG_ERR 3 /* error conditions */ | |
#define LOG_WARNING 4 /* warning conditions */ | |
#define LOG_NOTICE 5 /* normal but signification condition */ | |
#define LOG_INFO 6 /* informational */ | |
#define LOG_DEBUG 7 /* debug-level messages */ | |
struct { | |
unsigned short chan; | |
unsigned int class, priority; | |
struct ft_buffer *buffer; | |
} chan[] = | |
{ {0, OPC$M_NM_CENTRL|OPC$M_NM_REPLY, LOG_USER|LOG_NOTICE, 0}, | |
{0, OPC$M_NM_PRINT|OPC$M_NM_CARDS, LOG_LPR|LOG_INFO, 0}, | |
{0, OPC$M_NM_TAPES|OPC$M_NM_DISKS|OPC$M_NM_DEVICE, LOG_KERN|LOG_ERR, 0}, | |
{0, OPC$M_NM_NTWORK, LOG_DAEMON|LOG_INFO, 0}, | |
{0, OPC$M_NM_CLUSTER, LOG_KERN|LOG_CRIT, 0}, | |
{0, OPC$M_NM_SECURITY, LOG_AUTH|LOG_WARNING, 0}, | |
{0, OPC$M_NM_SOFTWARE|OPC$M_NM_LICENSE, LOG_KERN|LOG_WARNING, 0}, | |
{0, OPC$M_NM_OPER1|OPC$M_NM_OPER2|OPC$M_NM_OPER3|OPC$M_NM_OPER4| | |
OPC$M_NM_OPER5|OPC$M_NM_OPER6|OPC$M_NM_OPER7|OPC$M_NM_OPER8| | |
OPC$M_NM_OPER9|OPC$M_NM_OPER10|OPC$M_NM_OPER11|OPC$M_NM_OPER12, | |
LOG_LOCAL0|LOG_INFO, 0} | |
}; | |
#ifdef UCX | |
void bzero(c,length) | |
char *c; int length; | |
{ | |
char *c1; | |
for (c1=c; length--; ) *c1++=0; | |
} | |
void bcopy(c1, c2, length) | |
char *c1, *c2; int length; | |
{ | |
if (length==0 || c1==c2) return; | |
if (c1 > c2) { | |
for (;length--;) *c2++ = *c1++; | |
} else { | |
c1 += length; | |
c2 += length; | |
for (;length--;) *--c2 = *--c1; | |
} | |
} | |
#endif | |
main(argc, argv) | |
int argc; char *argv[]; | |
{ | |
unsigned int status, acmode, charbuff, buflen, astadr, astprm; | |
unsigned int ast_acmode, inadr[2], retlen; | |
unsigned short i; | |
unsigned int nchan, ichan; | |
struct { | |
unsigned short length, code; | |
unsigned long bufaddr, retlenaddr; | |
unsigned long zero; | |
} itemlist; | |
struct { | |
unsigned char class, type; | |
unsigned short width; | |
unsigned char basic[3], length; | |
unsigned int extended; | |
} term_char; | |
struct { | |
unsigned char type, enab[3]; | |
unsigned int mask; | |
unsigned short ounit; | |
unsigned char str_length, string[16]; | |
} msgbuf; | |
char ftname[64]; | |
struct dsc$descriptor_s enable; | |
struct iosb iosb; | |
$DESCRIPTOR(tabnam,"LNM$SYSTEM_TABLE"); | |
$DESCRIPTOR(syslog_host,"SYSLOGD_SERVER"); | |
$DESCRIPTOR(syslog_port,"SYSLOGD_PORT"); | |
char serv_host_name[255]; | |
char serv_port[255]; | |
struct hostent *serv_host_addr; | |
nchan = sizeof chan / sizeof chan[0]; | |
memset(ftname,0,sizeof(ftname)); | |
/* | |
* Set up the UDP connection to the syslog server | |
*/ | |
/* | |
* Fill in the structure "serv_addr" with the address of the | |
* server that we want to send to. | |
*/ | |
bzero((char *) &serv_addr, sizeof(serv_addr)); | |
serv_addr.sin_family = AF_INET; | |
/* | |
* first, check that we can get the IP address of the syslogd server | |
*/ | |
itemlist.length = sizeof(serv_host_name); | |
itemlist.code = LNM$_STRING; | |
itemlist.bufaddr = serv_host_name; | |
itemlist.retlenaddr = &retlen; | |
itemlist.zero = 0; | |
status = SYS$TRNLNM(0,&tabnam,&syslog_host,0,&itemlist); | |
if (!($VMS_STATUS_SUCCESS(status))) { | |
fprintf(stderr,"Cannot translate logical name %s in table %s\n",syslog_host.dsc$a_pointer,tabnam.dsc$a_pointer); | |
exit (status); | |
} | |
serv_host_addr=gethostbyname(serv_host_name); | |
if (!serv_host_addr) { | |
serv_addr.sin_addr.s_addr = inet_addr(serv_host_name); | |
if (serv_addr.sin_addr.s_addr == -1) { | |
fprintf(stderr,"Cannot resolve name %s\n",serv_host_name); | |
exit (1); | |
} | |
} else { | |
bcopy(serv_host_addr->h_addr, (char *) &serv_addr.sin_addr, | |
serv_host_addr->h_length); | |
} | |
/* | |
* then, check that we can get the port number of the syslogd server | |
*/ | |
itemlist.length = sizeof(serv_port); | |
itemlist.code = LNM$_STRING; | |
itemlist.bufaddr = serv_port; | |
itemlist.retlenaddr = &retlen; | |
itemlist.zero = 0; | |
status = SYS$TRNLNM(0,&tabnam,&syslog_port,0,&itemlist); | |
if (!($VMS_STATUS_SUCCESS(status))) { | |
fprintf(stderr,"Cannot translate logical name %s in table %s\n",syslog_port.dsc$a_pointer,tabnam.dsc$a_pointer); | |
exit (status); | |
} | |
SERV_UDP_PORT=atoi(serv_port); | |
if(0==SERV_UDP_PORT) { | |
fprintf(stderr,"Cannot translate port number from logical %s\n",syslog_host.dsc$a_pointer); | |
exit (1); | |
} | |
serv_addr.sin_port = htons(SERV_UDP_PORT); | |
/* | |
* Open a UDP socket (an Internet datagram socket). | |
*/ | |
if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { | |
perror("client: can't open datagram socket\n"); | |
exit (1); | |
} | |
/* | |
* Bind any local address for us. | |
*/ | |
bzero((char *) &cli_addr, sizeof(cli_addr)); /* zero out */ | |
cli_addr.sin_family = AF_INET; | |
cli_addr.sin_addr.s_addr = htonl(INADDR_ANY); | |
cli_addr.sin_port = htons(0); | |
if (bind(sockfd, (struct sockaddr *) &cli_addr, sizeof(cli_addr)) < 0) { | |
perror("client: can't bind local address\n"); | |
exit (1) ; | |
} | |
/* | |
* set up a pseudoterminal device for each operator class defined | |
* and enable that device through opcom | |
*/ | |
for (ichan=0; ichan<nchan; ichan++) { | |
/* set aside memory for the pty device */ | |
acmode = 0; | |
charbuff = 0; | |
buflen = 0; | |
astadr = 0; | |
astprm = 0; | |
ast_acmode = 0; | |
status = SYS$EXPREG(1,inadr,0,0); | |
if (!($VMS_STATUS_SUCCESS(status))) exit (status); | |
/* create the pty device */ | |
chan[ichan].buffer = inadr[0]; | |
status = PTD$CREATE(&chan[ichan].chan, acmode, charbuff, buflen, astadr, | |
astprm, ast_acmode, inadr); | |
if (!($VMS_STATUS_SUCCESS(status))) exit (status); | |
/* set the pty device to maximum page width, infinite page length */ | |
status = SYS$QIOW(0, chan[ichan].chan, IO$_SENSECHAR, &iosb, 0, 0, | |
&term_char, sizeof(term_char), 0, 0, 0, 0); | |
if (!($VMS_STATUS_SUCCESS(status))) exit (status); | |
term_char.width=511; | |
term_char.length=0; | |
status = SYS$QIOW(0, chan[ichan].chan, IO$_SETCHAR, &iosb, 0, 0, | |
&term_char, sizeof(term_char), 0, 0, 0, 0); | |
if (!($VMS_STATUS_SUCCESS(status))) exit (status); | |
/* get the pty device name */ | |
itemlist.length = sizeof(ftname); | |
itemlist.code = DVI$_FULLDEVNAM; | |
itemlist.bufaddr = ftname; | |
itemlist.retlenaddr = &retlen; | |
itemlist.zero = 0; | |
status = SYS$GETDVIW(0,chan[ichan].chan,0,&itemlist,0,0,0,0); | |
if (!($VMS_STATUS_SUCCESS(status))) exit (status); | |
/* ftname[retlen-1]='\0'; -- This crashes on OpenVMS 8.3 Alpha, memsetting this at declaration above - Supratim Sanyal 01-NOV-201 | |
7 */ | |
msgbuf.type = OPC$_RQ_TERME; | |
msgbuf.enab[0] = 1; | |
msgbuf.mask = chan[ichan].class; | |
for (i=retlen-2; i>0; i--) { | |
if ((ftname[i] >= 'A') && (ftname[i] <= 'Z')) { | |
msgbuf.ounit = (short) atoi(&ftname[i+1]); | |
ftname[i+1] = '\0'; | |
break; | |
} | |
} | |
msgbuf.str_length = strlen(ftname); | |
strncpy(msgbuf.string,ftname,msgbuf.str_length); | |
enable.dsc$w_length = sizeof(msgbuf); | |
enable.dsc$b_dtype = DSC$K_DTYPE_T; | |
enable.dsc$b_class = DSC$K_CLASS_S; | |
enable.dsc$a_pointer = &msgbuf; | |
status = SYS$SNDOPR(&enable,0); | |
if (!($VMS_STATUS_SUCCESS(status))) exit (status); | |
} | |
/* | |
* Now set up async reads to each channel. As various opcom messages come | |
* in, the appropriate ast will fire and the message logged. Another read | |
* will then be queued. | |
*/ | |
for (ichan=0; ichan<nchan; ichan++) { | |
status = PTD$READ(0, chan[ichan].chan, &write_syslog, ichan, | |
chan[ichan].buffer, FT_DATA_MAX); | |
if (!($VMS_STATUS_SUCCESS(status))) exit (status); | |
} | |
status = SYS$HIBER(); | |
exit(status); | |
} | |
unsigned int write_syslog(ichan) | |
unsigned int ichan; | |
{ | |
unsigned int i; | |
char header[1024], buffer[512], *c1; | |
time_t now; | |
(void) SYS$SETAST(0); /* block new ast's */ | |
time(&now); | |
c1 = buffer; | |
for (i=0; i<=chan[ichan].buffer->count; i++) { | |
if (chan[ichan].buffer->data[i]=='\015') { /* CR delimited */ | |
*c1 = '\0'; | |
sprintf(header,"<%d>%.15s [OPCOM] ", chan[ichan].priority, | |
(ctime(&now)+4)); | |
strcat(header,buffer); | |
sendto(sockfd, header, strlen(header), 0, &serv_addr, | |
sizeof serv_addr); | |
c1 = buffer; | |
} else if (isprint(chan[ichan].buffer->data[i])) { | |
*c1 = chan[ichan].buffer->data[i]; | |
c1++; | |
} | |
} | |
/* queue a new read */ | |
(void) PTD$READ(0, chan[ichan].chan, &write_syslog, ichan, | |
chan[ichan].buffer, FT_DATA_MAX); | |
(void) SYS$SETAST(1); /* re-enable ast's */ | |
return(0); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment