Skip to content

Instantly share code, notes, and snippets.

@countingpine
Last active June 3, 2025 09:26
Show Gist options
  • Save countingpine/10d41a924ea930406ef0553f9d6f5801 to your computer and use it in GitHub Desktop.
Save countingpine/10d41a924ea930406ef0553f9d6f5801 to your computer and use it in GitHub Desktop.
pfSense clog for Linux
#!/bin/bash
rm clog.{h,c}
for i in clog.{h,c} #Makefile clog.8
do
wget "https://raw.githubusercontent.com/billm/pfsense-tools-centipede-slbd/ca8f30632588a7273a124e2fb82b808bb35d7e77/pfPorts/clog/files/$i"
done
gcc --include=stdint.h -o ./clog clog.c
.\" Copyright (c) 2001
.\" Jeffrey D. Wheelhouse. All rights reserved.
.\"
.\" This code was originally developed by Jeff Wheelhouse ([email protected]).
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY JEFF WHEELHOUSE ``AS IS'' AND ANY EXPRESS OR
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
.\" NO EVENT SHALL JEFF WHEELHOUSE BE LIABLE FOR ANY DIRECT, INDIRECT,
.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING BUT NOT
.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
.\" OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
.\" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
.\" NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
.\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\" $Id$
.\"
.Dd October 1, 2001
.Dt CLOG 8
.Os BSD 4
.Sh NAME
.Nm clog
.Nd "display or initialize a circular system log"
.Sh SYNOPSIS
.Nm
.Op Fl f
.Op Fl i Fl s Ar size
.Ar logfile
.Sh DESCRIPTION
.Nm Clog
displays or initializes a circular log file.
.Pp
The options are as follows:
.Bl -tag -width indent
.It Fl f
Display the contents of the circular logfile
.Ar logfile ,
then go into a loop waiting for
new material to arrive. This is essentially the same as using the
.Fl f
option of the
.Xr tail 1
command on a standard syslog file.
.It Fl i
Initialize
.Ar logfile
rather than reading it. This option requires the
.Fl s
option. If
.Ar logfile
already exists, it will be truncated and recreated by this command.
.It Fl s
This option specifies the size in bytes of the circular logfile that should
be created. This option requires the
.Fl i
option.
.El
.Sh ABOUT CIRCULAR LOGFILES
The
.Nm
command supports circular logfiles for
.Xr syslogd 8 .
A circular logfile differs from a standard syslog file in that is has a fixed
size. It does not grow, and does not need to be rotated. When
.Xr syslogd 8
reaches the end of a circular logfile, it simply begins again at the beginning,
overwriting the oldest data. The circular logfile also contains information
allowing
.Nm
to establish what parts of the file are valid, and in what order they should
be displayed.
.Pp
Circular logfiles are primarily useful for their ability to control the amount
of storage devoted to logfiles. This may be valuable when storage space is
at a premium or when the consequences of running out of storage space are
unacceptable. Circular logfiles can safely be used on a memory disk (see
.Xr md 4 ).
.Pp
Circular logfiles are also useful to catch messages that are generated rapidly
but soon lose relevance, such as messages logged at debug priority.
.Sh SEE ALSO
.Xr syslogd 8 ,
.Xr syslog.conf 5
.Sh HISTORY
The
.Nm
command was written for FreeBSD 4.3 but is not yet part of a BSD distribution.
<!-- Creator : groff version 1.22.4 -->
<!-- CreationDate: Mon Jun 2 10:33:06 2025 -->
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta name="generator" content="groff -Thtml, see www.gnu.org">
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<meta name="Content-Style" content="text/css">
<style type="text/css">
p { margin-top: 0; margin-bottom: 0; vertical-align: top }
pre { margin-top: 0; margin-bottom: 0; vertical-align: top }
table { margin-top: 0; margin-bottom: 0; vertical-align: top }
h1 { text-align: center }
</style>
<title></title>
</head>
<body>
<hr>
<p>CLOG(8) BSD System Manager&rsquo;s Manual CLOG(8)</p>
<p style="margin-top: 1em"><b>NAME</b></p>
<p style="margin-left:6%;"><b>clog</b> &mdash; display or
initialize a circular system log</p>
<p style="margin-top: 1em"><b>SYNOPSIS</b></p>
<p style="margin-left:13%;"><b>clog</b> [<b>-f</b>]
[<b>-i&nbsp;-s&nbsp;</b><i>size</i>] <i>logfile</i></p>
<p style="margin-top: 1em"><b>DESCRIPTION</b></p>
<p style="margin-left:6%;"><b>Clog</b> displays or
initializes a circular log file.</p>
<p style="margin-left:6%; margin-top: 1em">The options are
as follows:</p>
<p style="margin-top: 1em"><b>-f</b></p>
<p style="margin-left:17%; margin-top: 1em">Display the
contents of the circular logfile <i>logfile</i>, then go
into a loop waiting for new material to arrive. This is
essentially the same as using the <b>-f</b> option of the
tail(1) command on a standard syslog file.</p>
<p style="margin-top: 1em"><b>-i</b></p>
<p style="margin-left:17%; margin-top: 1em">Initialize
<i>logfile</i> rather than reading it. This option requires
the <b>-s</b> option. If <i>logfile</i> already exists, it
will be truncated and recreated by this command.</p>
<p style="margin-top: 1em"><b>-s</b></p>
<p style="margin-left:17%; margin-top: 1em">This option
specifies the size in bytes of the circular logfile that
should be created. This option requires the <b>-i</b>
option.</p>
<p style="margin-top: 1em"><b>ABOUT CIRCULAR
LOGFILES</b></p>
<p style="margin-left:6%;">The <b>clog</b> command supports
circular logfiles for syslogd(8). A circular logfile differs
from a standard syslog file in that is has a fixed size. It
does not grow, and does not need to be rotated. When
syslogd(8) reaches the end of a circular logfile, it simply
begins again at the beginning, overwriting the oldest data.
The circular logfile also contains information allowing
<b>clog</b> to establish what parts of the file are valid,
and in what order they should be displayed.</p>
<p style="margin-left:6%; margin-top: 1em">Circular
logfiles are primarily useful for their ability to control
the amount of storage devoted to logfiles. This may be
valuable when storage space is at a premium or when the
consequences of running out of storage space are
unacceptable. Circular logfiles can safely be used on a
memory disk (see md(4) ).</p>
<p style="margin-left:6%; margin-top: 1em">Circular
logfiles are also useful to catch messages that are
generated rapidly but soon lose relevance, such as messages
logged at debug priority.</p>
<p style="margin-top: 1em"><b>SEE ALSO</b></p>
<p style="margin-left:6%;">syslogd(8), syslog.conf(5)</p>
<p style="margin-top: 1em"><b>HISTORY</b></p>
<p style="margin-left:6%;">The <b>clog</b> command was
written for FreeBSD 4.3 but is not yet part of a BSD
distribution.</p>
<p style="margin-left:6%; margin-top: 1em">4th&nbsp;Berkeley
Distribution October&nbsp;1, 2001 4th&nbsp;Berkeley
Distribution</p>
<hr>
</body>
</html>

CLOG(8) BSD System Manager’s Manual CLOG(8)

NAME

clog — display or initialize a circular system log

SYNOPSIS

clog [-f] [-i -s size] logfile

DESCRIPTION

Clog displays or initializes a circular log file.

The options are as follows:

-f

Display the contents of the circular logfile logfile, then go into a loop waiting for new material to arrive. This is essentially the same as using the -f option of the tail(1) command on a standard syslog file.

-i

Initialize logfile rather than reading it. This option requires the -s option. If logfile already exists, it will be truncated and recreated by this command.

-s

This option specifies the size in bytes of the circular logfile that should be created. This option requires the -i option.

ABOUT CIRCULAR LOGFILES

The clog command supports circular logfiles for syslogd(8). A circular logfile differs from a standard syslog file in that is has a fixed size. It does not grow, and does not need to be rotated. When syslogd(8) reaches the end of a circular logfile, it simply begins again at the beginning, overwriting the oldest data. The circular logfile also contains information allowing clog to establish what parts of the file are valid, and in what order they should be displayed.

Circular logfiles are primarily useful for their ability to control the amount of storage devoted to logfiles. This may be valuable when storage space is at a premium or when the consequences of running out of storage space are unacceptable. Circular logfiles can safely be used on a memory disk (see md(4) ).

Circular logfiles are also useful to catch messages that are generated rapidly but soon lose relevance, such as messages logged at debug priority.

SEE ALSO

syslogd(8), syslog.conf(5)

HISTORY

The clog command was written for FreeBSD 4.3 but is not yet part of a BSD distribution.

4th Berkeley Distribution October 1, 2001 4th Berkeley Distribution


/*-
* Copyright (c) 2001
* Jeff Wheelhouse ([email protected])
*
* This code was originally developed by Jeff Wheelhouse ([email protected]).
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistribution of source code must retail the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY JEFF WHEELHOUSE ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL JEFF WHEELHOUSE BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id$
*/
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <sched.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include "clog.h"
/*
* The BUFFER_SIZE value is just used to allocate a buffer full of NULLs
* so that a new logfile can be extended to its full size.
*
* Compiling with -pedantic complains when the buffer array is declared
* if I declare this as a const instead of a #define.
*/
#define BUFFER_SIZE 16384
void init_log __P((const char *lname, size_t size));
void read_log __P((const char *lname, int optf));
void usage __P((void));
const char *pname;
int main(int argc, char **argv) {
int ch;
int init = 0;
int size = 0;
int optf = 0;
pname = argv[0];
while ((ch = getopt(argc, argv, "fis:")) != -1)
switch(ch) {
case 'i':
init = 1;
break;
case 's':
size = atol(optarg);
if (size==0) usage();
break;
case 'f':
optf = 1;
}
if ((size>0)&&(init==0)) {
fprintf(stderr,"%s: WARNING: -s argument ignored without -i.\n",pname);
size = 0;
}
if (argv[optind]==NULL) {
fprintf(stderr,"%s: ERROR: log_file argument must be specified.\n",pname);
usage();
}
if ((init==1)&&(size==0)) {
fprintf(stderr,"%s: ERROR: -i argument requires -s.\n",pname);
usage();
}
if ((init==1)&&(optf==1)) {
fprintf(stderr,"%s: ERROR: flags -f and -i are incompatible.\n",pname);
usage();
}
if (init==1) init_log(argv[optind],size);
/* if (optf==1) follow_log(artv[optind]); */
read_log(argv[optind],optf);
return 0;
}
void usage() {
fprintf(stderr,"usage: %s [-i -s log_size] [ -f ] log_file\n",pname);
exit(1);
}
void read_log(const char *lname, int optf) {
int fd;
struct stat sb;
struct clog_footer *pcf;
char *pbuffer;
struct iovec iov[2];
int iovcnt = 0;
uint32_t start = 0;
uint32_t next;
struct pollfd pfd;
pfd.fd = -1;
fd = open(lname,O_RDONLY);
if (fd==-1) {
fprintf(stderr,"%s: ERROR: could not open %s (%s)\n",pname,lname,strerror(errno));
exit(11);
}
if (fstat(fd,&sb)==-1) {
fprintf(stderr,"%s: ERROR: could not stat %s (%s)\n",pname,lname,strerror(errno));
exit(13);
}
pbuffer = mmap(NULL,sb.st_size,PROT_READ,MAP_SHARED,fd,0);
if (pbuffer==NULL) {
fprintf(stderr,"%s: ERROR: could not mmap %s body (%s)\n",pname,lname,strerror(errno));
exit(14);
}
pcf = (struct clog_footer*)(pbuffer + sb.st_size - sizeof(struct clog_footer));
if (pcf->cf_wrap==1) start = pcf->cf_next + 1;
while(1) {
while(pcf->cf_lock==1) sched_yield();
next = pcf->cf_next;
iovcnt = 0;
if (start>next) {
iov[iovcnt].iov_base = pbuffer + start;
iov[iovcnt++].iov_len = pcf->cf_max - start;
start = 0;
}
iov[iovcnt].iov_base = pbuffer + start;
iov[iovcnt++].iov_len = next - start;
if (writev(1,iov,iovcnt)==-1) {
fprintf(stderr,"%s: ERROR: could not write output (%s)\n",pname,strerror(errno));
exit(15);
}
start = next;
if (optf==0) break;
if (poll(&pfd,1,50)==-1) {
fprintf(stderr,"%s: ERROR: could not poll (%s)\n",pname,strerror(errno));
exit(16);
}
}
(void)munmap(pbuffer,sb.st_size);
(void)close(fd);
exit(0);
}
void init_log(const char *lname, size_t size) {
int fd;
size_t fill = size;
char buffer[BUFFER_SIZE];
struct clog_footer cf;
memcpy(&cf.cf_magic,MAGIC_CONST,4);
cf.cf_max = size - sizeof(struct clog_footer);
(void)memset(buffer,0,BUFFER_SIZE);
fd = open(lname,O_RDWR|O_CREAT,0666);
if (fd==-1) {
fprintf(stderr,"%s: ERROR: could not open %s (%s)\n",pname,lname,strerror(errno));
exit(2);
}
if (ftruncate(fd,(off_t)0)==-1) {
fprintf(stderr,"%s: ERROR: could not truncate %s (%s)\n",pname,lname,strerror(errno));
exit(3);
}
while(fill>BUFFER_SIZE) {
if (write(fd,buffer,BUFFER_SIZE)==-1){
fprintf(stderr,"%s: ERROR: could not write %s (%s)\n",pname,lname,strerror(errno));
exit(4);
}
fill -= BUFFER_SIZE;
}
assert(fill<=BUFFER_SIZE);
if (fill>0) {
if (write(fd,buffer,fill)==-1) {
fprintf(stderr,"%s: ERROR: could not write %s (%s)\n",pname,lname,strerror(errno));
exit(5);
}
}
if (lseek(fd,-(off_t)(sizeof(struct clog_footer)),SEEK_END)==-1) {
fprintf(stderr,"%s: ERROR: could not seek in %s (%s)\n",pname,lname,strerror(errno));
exit(6);
}
if (write(fd,&cf,sizeof(cf))==-1) {
fprintf(stderr,"%s: ERROR: could not write magic in %s (%s)\n",pname,lname,strerror(errno));
exit(7);
}
(void)close(fd);
exit(0);
}
/*-
* Copyright (c) 2001
* Jeff Wheelhouse ([email protected])
*
* This code was originally developed by Jeff Wheelhouse ([email protected]).
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistribution of source code must retail the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY JEFF WHEELHOUSE ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL JEFF WHEELHOUSE BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id$
*/
#ifndef _CLOG_H_
#define _CLOG_H_
/*
* This magic constant is used to identify a valid circular log file.
* syslogd will ignore any circular log file that doesn't have this constant.
*/
const char MAGIC_CONST[4] = "CLOG";
struct clog_footer {
uint32_t cf_magic;
uint32_t cf_wrap;
uint32_t cf_next;
uint32_t cf_max;
uint32_t cf_lock;
};
#endif /* _CLOG_H_ */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment