mirror of
https://github.com/jrbrtsn/ban2fail
synced 2024-06-16 11:58:01 +00:00
Add files via upload
This commit is contained in:
parent
bed4b5166e
commit
a433b972c5
109
README.md
Normal file
109
README.md
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
# ban2fail
|
||||||
|
|
||||||
|
(C) 2019 John D. Robertson <john@rrci.com>
|
||||||
|
|
||||||
|
**ban2fail** is a simple and efficient tool to coordinate log file scanning and
|
||||||
|
iptables filtering. As the name implies, *ban2fail* was inspired by the popular
|
||||||
|
*fail2ban* project (http://fail2ban.org).
|
||||||
|
|
||||||
|
*ban2fail* started with a few hours of C hacking after my mail server was
|
||||||
|
exploited to deliver spam by others who had cracked a user's SMTP send password.
|
||||||
|
After inspecting the log files I realized that crackers are now using widely
|
||||||
|
distributed attacks, and that I would need an app that could run several times a
|
||||||
|
minute on my rather modest Linode virtual server to have a chance of stopping
|
||||||
|
them. I hope you find this code useful.
|
||||||
|
|
||||||
|
##Configuration
|
||||||
|
*ban2fail* works from a configuration file found at
|
||||||
|
"/etc/ban2fail/ban2fail.cfg". The overarching premise is that if any REGEX
|
||||||
|
appearing in a LOGTYPE clause matches a line in an associated log file, then by
|
||||||
|
default that IP will be blocked.
|
||||||
|
|
||||||
|
>LOGTYPE auth {
|
||||||
|
> DIR= /var/log
|
||||||
|
> PREFIX= auth.log
|
||||||
|
>
|
||||||
|
> REGEX= imapd.*Login failed.*\[([0-9.]+)\]$
|
||||||
|
>
|
||||||
|
> REGEX= sshd.*Failed password.*from ([0-9.]+) port [0-9]+ ssh2$
|
||||||
|
>
|
||||||
|
> REGEX= Unable to negotiate with ([0-9.]+) port
|
||||||
|
>
|
||||||
|
> REGEX= in\.qpopper.*authentication failure.*tty=([0-9.]+)
|
||||||
|
>
|
||||||
|
>}
|
||||||
|
|
||||||
|
Syntax in the config file is pretty much the same as the nftables syntax. All
|
||||||
|
keywords must be in upper case. Any values in the key-\>value pairs have
|
||||||
|
whitespace stripped from the beginning and end of the line. Since there is no
|
||||||
|
escaping of characters going on, regular expressions are WYSIWYG.
|
||||||
|
|
||||||
|
The only way to alter the default blocking behavior is with a MAX\_OFFENSES
|
||||||
|
clause. This clause allows you specify how many offenses are tolerated before an
|
||||||
|
IP is blocked. Offenses will naturally disappear as old logfiles are deleted by
|
||||||
|
*logrotate*.
|
||||||
|
|
||||||
|
># Take it easy on home boys
|
||||||
|
>MAX_OFFENSES 5 {
|
||||||
|
> COUNTRY= US
|
||||||
|
>}
|
||||||
|
>
|
||||||
|
># GeoIP doesn't know the location of every IP address
|
||||||
|
>MAX_OFFENSES 3 {
|
||||||
|
> COUNTRY= unknown
|
||||||
|
>}
|
||||||
|
>
|
||||||
|
># This is your whitelist: -1 means no limit.
|
||||||
|
>MAX_OFFENSES -1 {
|
||||||
|
>
|
||||||
|
># me from home
|
||||||
|
> IP= 205.144.171.37
|
||||||
|
>
|
||||||
|
># Some user
|
||||||
|
> IP= 173.236.196.36
|
||||||
|
>}
|
||||||
|
|
||||||
|
If you recieve a complaint about an address unjustly getting blocked, place it
|
||||||
|
in one of the MAX\_OFFENSES blocks, and the IP will be unblocked the next time
|
||||||
|
*ban2fail* runs.
|
||||||
|
|
||||||
|
##Working with *ban2fail*
|
||||||
|
There are two primary modes in which *ban2fail* is used:
|
||||||
|
|
||||||
|
* Production mode, where iptables rules are modified.
|
||||||
|
|
||||||
|
* Testing mode, where modifications to blocking rules are indicated.
|
||||||
|
|
||||||
|
###Production
|
||||||
|
In production mode it is expected that *ban2fail* is running from a cron job,
|
||||||
|
and no output is printed unless addresses are (un)blocked. It is also possible
|
||||||
|
to generate a listing of addresses, offense counts, and status with the -a
|
||||||
|
command flag. Likewise, a listing of countries and offense counts is available
|
||||||
|
with the -c flag.
|
||||||
|
|
||||||
|
###Testing
|
||||||
|
In test mode (-t flags) the presumption is that you are testing a modified
|
||||||
|
configuration which is not yet in place, and that you don't want to disturb the
|
||||||
|
production setup. This is how you might do that:
|
||||||
|
|
||||||
|
>ban2fail -t myNew.cfg -a
|
||||||
|
|
||||||
|
No iptables rules will be modified. You will shown in the listing which
|
||||||
|
addresses would be (un)blocked if *ban2fail* was running in production mode, and
|
||||||
|
the contents of "myNew.cfg" was placed into "/etc/ban2fail/ban2fail.cfg".
|
||||||
|
|
||||||
|
When you are happy with the new configuration, copy it into place, and the the
|
||||||
|
iptable rule changes will be realized the next time *ban2fail* runs.
|
||||||
|
|
||||||
|
##Building the Project
|
||||||
|
I've tested *ban2fail* on Debian Buster, but it should compile on just about any
|
||||||
|
modern Linux distro. It uses the GeoIP package to identify the country of origin
|
||||||
|
for IP addresses. Build and install like so:
|
||||||
|
|
||||||
|
>make release
|
||||||
|
>sudo make install
|
||||||
|
|
||||||
|
The executable will be placed in "/usr/local/bin".
|
||||||
|
|
||||||
|
|
||||||
|
|
566
ban2fail.c
Normal file
566
ban2fail.c
Normal file
@ -0,0 +1,566 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2019 by John D. Robertson *
|
||||||
|
* john@rrci.com *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program 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 *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#include <assert.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/file.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include "ban2fail.h"
|
||||||
|
#include "cntry.h"
|
||||||
|
#include "ez_dirent.h"
|
||||||
|
#include "ez_gzfile.h"
|
||||||
|
#include "ez_stdio.h"
|
||||||
|
#include "ez_stdlib.h"
|
||||||
|
#include "iptables.h"
|
||||||
|
#include "logEntry.h"
|
||||||
|
#include "logFile.h"
|
||||||
|
#include "logType.h"
|
||||||
|
#include "map.h"
|
||||||
|
#include "maxoff.h"
|
||||||
|
#include "str.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
enum {
|
||||||
|
BLOCKED_FLG =1<<0,
|
||||||
|
WOULD_BLOCK_FLG =1<<1,
|
||||||
|
UNJUST_BLOCK_FLG =1<<2,
|
||||||
|
WHITELIST_FLG =1<<3
|
||||||
|
};
|
||||||
|
|
||||||
|
/*==================================================================*/
|
||||||
|
/*=================== Support structs ==============================*/
|
||||||
|
/*==================================================================*/
|
||||||
|
struct cntryStat {
|
||||||
|
char *cntry;
|
||||||
|
unsigned count;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Need this for initialization from configuration file */
|
||||||
|
struct initInfo {
|
||||||
|
const char *symStr;
|
||||||
|
int (*init_f)(CFGMAP *map, char *symStr);
|
||||||
|
};
|
||||||
|
|
||||||
|
/*==================================================================*/
|
||||||
|
/*================= Forward declarations ===========================*/
|
||||||
|
/*==================================================================*/
|
||||||
|
|
||||||
|
static int cntryStat_count_qsort(const void *p1, const void *p2);
|
||||||
|
static int configure(CFGMAP *h_cfgmap, const char *pfix);
|
||||||
|
static int logentry_count_qsort(const void *p1, const void *p2);
|
||||||
|
static int map_byCountries(LOGENTRY *e, MAP *h_map);
|
||||||
|
static int stub_init(CFGMAP *map, char *symStr);
|
||||||
|
static int whitelist_init(CFGMAP *h_cfgmap, char *symStr);
|
||||||
|
|
||||||
|
|
||||||
|
/*==================================================================*/
|
||||||
|
/*========================= static data ============================*/
|
||||||
|
/*==================================================================*/
|
||||||
|
struct Global G= {
|
||||||
|
.cacheDir= CACHEDIR,
|
||||||
|
.lockPath= LOCKPATH,
|
||||||
|
|
||||||
|
.version= {
|
||||||
|
.major= 0,
|
||||||
|
.minor= 9,
|
||||||
|
.patch= 4
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const static struct initInfo S_initInfo_arr[] = {
|
||||||
|
{.symStr= "MAX_OFFENSES", .init_f= MAXOFF_init},
|
||||||
|
{.symStr= "LOGTYPE", .init_f= LOGTYPE_init},
|
||||||
|
{/* Terminating member */}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static const struct bitTuple BlockBitTuples[]= {
|
||||||
|
{.name= "BLOCKED", .bit= BLOCKED_FLG},
|
||||||
|
{.name= "+WouldBLOCK+", .bit= WOULD_BLOCK_FLG},
|
||||||
|
{.name= "-UnjustBLOCK-", .bit= UNJUST_BLOCK_FLG},
|
||||||
|
{.name= "Whitelisted", .bit= WHITELIST_FLG},
|
||||||
|
{/* Terminating member */}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*================ Local only static struct ======================*/
|
||||||
|
static struct {
|
||||||
|
|
||||||
|
MAP addr_map;
|
||||||
|
|
||||||
|
CFGMAP cfgmap;
|
||||||
|
|
||||||
|
PTRVEC toBlock_vec,
|
||||||
|
toUnblock_vec;
|
||||||
|
|
||||||
|
} S;
|
||||||
|
|
||||||
|
/*==================================================================*/
|
||||||
|
/*======================== main() ==================================*/
|
||||||
|
/*==================================================================*/
|
||||||
|
|
||||||
|
/* Enums for long options */
|
||||||
|
enum {
|
||||||
|
VERSION_OPT_ENUM=128, /* Larger than any printable character */
|
||||||
|
HELP_OPT_ENUM
|
||||||
|
};
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
/***************************************************************
|
||||||
|
* Program execution begins here.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
int rtn= EXIT_FAILURE,
|
||||||
|
lock_fd= -1;
|
||||||
|
|
||||||
|
char *confFile= CONFIGFILE;
|
||||||
|
|
||||||
|
/* Prepare static data */
|
||||||
|
// global
|
||||||
|
MAP_constructor(&G.logType_map, 10, 10);
|
||||||
|
|
||||||
|
// local
|
||||||
|
MAP_constructor(&S.addr_map, 1000, 200);
|
||||||
|
|
||||||
|
PTRVEC_constructor(&S.toBlock_vec, 100000);
|
||||||
|
PTRVEC_constructor(&S.toUnblock_vec, 100000);
|
||||||
|
|
||||||
|
{ /*=== Parse command line arguments ===*/
|
||||||
|
int c, errflg= 0;
|
||||||
|
extern char *optarg;
|
||||||
|
extern int optind, optopt;
|
||||||
|
|
||||||
|
for(;;) {
|
||||||
|
|
||||||
|
static const struct option long_options[]= {
|
||||||
|
{"help", no_argument, 0, HELP_OPT_ENUM},
|
||||||
|
{"version", no_argument, 0, VERSION_OPT_ENUM},
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
int c, option_ndx= 0;
|
||||||
|
|
||||||
|
c= getopt_long(argc, argv, ":act:v", long_options, &option_ndx);
|
||||||
|
|
||||||
|
if(-1 == c) break;
|
||||||
|
|
||||||
|
switch(c) {
|
||||||
|
|
||||||
|
/* print usage help */
|
||||||
|
case HELP_OPT_ENUM:
|
||||||
|
++errflg;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'c':
|
||||||
|
G.flags |= GLB_LIST_CNTRY_FLG;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'a':
|
||||||
|
G.flags |= GLB_LIST_ADDR_FLG;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 't':
|
||||||
|
G.flags |= GLB_DONT_IPTABLE_FLG;
|
||||||
|
G.cacheDir= CACHEDIR "-test";
|
||||||
|
G.lockPath= LOCKPATH "-test";
|
||||||
|
confFile= optarg;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'v':
|
||||||
|
G.flags |= GLB_VERBOSE_FLG;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VERSION_OPT_ENUM:
|
||||||
|
ez_fprintf(stderr, "ban2fail v%d.%d.%d\n", G.version.major, G.version.minor, G.version.patch);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case '?':
|
||||||
|
ez_fprintf(stderr, "Unrecognized option: -%c\n", optopt);
|
||||||
|
++errflg;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(errflg) {
|
||||||
|
ez_fprintf(stderr,
|
||||||
|
"Usage:\n"
|
||||||
|
"%s [options] [-t confFile]\n"
|
||||||
|
" --help\tprint this usage message.\n"
|
||||||
|
" -a\t\tList results by Address\n"
|
||||||
|
" -c\t\tlist results by Country\n"
|
||||||
|
" -t confFile\tTest confFile, do not apply iptables rules\n"
|
||||||
|
" --version\tprint the version number and exit.\n"
|
||||||
|
, argv[0]
|
||||||
|
);
|
||||||
|
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
} /* Done with command line arguments */
|
||||||
|
|
||||||
|
/* Make sure we will be able to run iptables */
|
||||||
|
if(getuid()) {
|
||||||
|
eprintf("ERROR: You must be root to run iptables!");
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
|
||||||
|
{ /*============== Read the configuration file ==============*/
|
||||||
|
if(!CFGMAP_file_constructor(&S.cfgmap, confFile)) {
|
||||||
|
eprintf("ERROR: failed to read configuration from \"%s\"", confFile);
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Just leave the S.cfgmap in place, so all the value strings
|
||||||
|
* don't need to be copied.
|
||||||
|
*/
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
{ /*============== Obtain a lock on our lockfile ==============*/
|
||||||
|
/* Make sure the file exists by open()'ing */
|
||||||
|
lock_fd= open(G.lockPath, O_CREAT|O_WRONLY|O_CLOEXEC, 0640);
|
||||||
|
if(-1 == lock_fd) {
|
||||||
|
sys_eprintf("ERROR: open(\"%s\") failed");
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Let's get a exclusive lock */
|
||||||
|
int rc= flock(lock_fd, LOCK_EX|LOCK_NB);
|
||||||
|
if(-1 == rc) {
|
||||||
|
sys_eprintf("ERROR: flock(\"%s\") failed", G.lockPath);
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{ /*============== Open our cache, instantiate LOGTYPE objects ==============*/
|
||||||
|
|
||||||
|
/* Make the directory if needed */
|
||||||
|
if(access(G.cacheDir, F_OK)) {
|
||||||
|
/* errno will be set if access() fails */
|
||||||
|
errno= 0;
|
||||||
|
|
||||||
|
ez_mkdir(G.cacheDir, 0700);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(G.flags & GLB_PRINT_MASK) {
|
||||||
|
ez_fprintf(stdout, "=============== ban2fail v%d.%d.%d =============\n"
|
||||||
|
, G.version.major
|
||||||
|
, G.version.minor
|
||||||
|
, G.version.patch
|
||||||
|
);
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ /*============== Implement configuration ==============*/
|
||||||
|
|
||||||
|
if(configure(&S.cfgmap, NULL)) {
|
||||||
|
eprintf("ERROR: failed to realize configuration in \"%s\"", confFile);
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(G.flags & GLB_VERBOSE_FLG) { /* Warn about unused symbols */
|
||||||
|
CFGMAP_print_unused_symbols(&S.cfgmap, stdout);
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Just leave the S.cfgmap in place, so all the value strings
|
||||||
|
* don't need to be copied.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* We're done with disk I/O, so release lock */
|
||||||
|
flock(lock_fd, LOCK_UN);
|
||||||
|
ez_close(lock_fd);
|
||||||
|
lock_fd= -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
{ /* Check cache for logType directories not in our current map */
|
||||||
|
DIR *dir= ez_opendir(G.cacheDir);
|
||||||
|
struct dirent *entry;
|
||||||
|
|
||||||
|
while((entry= ez_readdir(dir))) {
|
||||||
|
|
||||||
|
/* Skip uninteresting entries */
|
||||||
|
if('.' == *entry->d_name) continue;
|
||||||
|
|
||||||
|
LOGTYPE *t= MAP_findStrItem(&G.logType_map, entry->d_name);
|
||||||
|
/* If there is a matching entry, then do not delete results */
|
||||||
|
if(t)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Make the path with filename */
|
||||||
|
static char pathBuf[PATH_MAX];
|
||||||
|
snprintf(pathBuf, sizeof(pathBuf), "%s/%s", G.cacheDir, entry->d_name);
|
||||||
|
|
||||||
|
/* Remove unused directory & contents. */
|
||||||
|
ez_rmdir_recursive(pathBuf);
|
||||||
|
|
||||||
|
}
|
||||||
|
ez_closedir(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned nFound= 0;
|
||||||
|
MAP_visitAllEntries(&G.logType_map, (int(*)(void*,void*))LOGTYPE_offenseCount, &nFound);
|
||||||
|
|
||||||
|
if(G.flags & GLB_PRINT_MASK) {
|
||||||
|
ez_fprintf(stdout, "===== Found %u total offenses =====\n", nFound);
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ /******* Now get a map of LOGENTRY objects that have combined counts ****/
|
||||||
|
|
||||||
|
/* List by address. Make a addr_map of LOGENTRY objects with composite counts */
|
||||||
|
MAP_visitAllEntries(&G.logType_map, (int(*)(void*,void*))LOGTYPE_map_addr, &S.addr_map);
|
||||||
|
unsigned nItems= MAP_numItems(&S.addr_map);
|
||||||
|
|
||||||
|
{
|
||||||
|
LOGENTRY *leArr[nItems];
|
||||||
|
MAP_fetchAllItems(&S.addr_map, (void**)leArr);
|
||||||
|
qsort(leArr, nItems, sizeof(LOGENTRY*), logentry_count_qsort);
|
||||||
|
|
||||||
|
/* Process each LOGENTRY item */
|
||||||
|
for(unsigned i= 0; i < nItems; ++i) {
|
||||||
|
int flags=0;
|
||||||
|
|
||||||
|
LOGENTRY *e= leArr[i];
|
||||||
|
|
||||||
|
if(IPTABLES_is_currently_blocked(e->addr))
|
||||||
|
flags |= BLOCKED_FLG;
|
||||||
|
|
||||||
|
int nAllowed= MAXOFF_allowed(e->addr);
|
||||||
|
|
||||||
|
if(-1 == nAllowed)
|
||||||
|
flags |= WHITELIST_FLG;
|
||||||
|
|
||||||
|
if((-1 == nAllowed || e->count <= nAllowed) &&
|
||||||
|
(flags & BLOCKED_FLG)) {
|
||||||
|
|
||||||
|
flags |= UNJUST_BLOCK_FLG;
|
||||||
|
PTRVEC_addTail(&S.toUnblock_vec, e->addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!(flags & BLOCKED_FLG) &&
|
||||||
|
-1 != nAllowed &&
|
||||||
|
e->count > nAllowed)
|
||||||
|
{
|
||||||
|
|
||||||
|
flags |= WOULD_BLOCK_FLG;
|
||||||
|
PTRVEC_addTail(&S.toBlock_vec, e->addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Print out only for list option */
|
||||||
|
if(G.flags & GLB_LIST_ADDR_FLG) {
|
||||||
|
|
||||||
|
ez_fprintf(stdout, "%-15s: %5u offenses %s (%s)\n"
|
||||||
|
, e->addr
|
||||||
|
, e->count
|
||||||
|
, e->cntry[0] ? e->cntry : "--"
|
||||||
|
, bits2str(flags, BlockBitTuples)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
} /*--- End of LOGENTRY processing ---*/
|
||||||
|
|
||||||
|
/* Take care of summary blocking and reporting */
|
||||||
|
unsigned n2Block= PTRVEC_numItems(&S.toBlock_vec);
|
||||||
|
unsigned n2Unblock= PTRVEC_numItems(&S.toUnblock_vec);
|
||||||
|
|
||||||
|
if(!(G.flags & GLB_DONT_IPTABLE_FLG)) {
|
||||||
|
|
||||||
|
if(n2Block) {
|
||||||
|
|
||||||
|
if(IPTABLES_block_addresses(&S.toBlock_vec, 10)) {
|
||||||
|
eprintf("ERROR: cannot block addresses!");
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
printf("Blocked %u new hosts\n", n2Block);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(n2Unblock) {
|
||||||
|
|
||||||
|
if(IPTABLES_unblock_addresses(&S.toUnblock_vec, 10)) {
|
||||||
|
eprintf("ERROR: cannot unblock addresses!");
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
printf("Unblocked %u hosts\n", n2Unblock);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if(n2Block)
|
||||||
|
printf("Would block %u new hosts\n", n2Block);
|
||||||
|
|
||||||
|
if(n2Unblock)
|
||||||
|
printf("Would unblock %u new hosts\n", n2Unblock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* List offenses by country if directed to do so */
|
||||||
|
if(G.flags & GLB_LIST_CNTRY_FLG) {
|
||||||
|
|
||||||
|
/* Map for indexing cntryStat objects */
|
||||||
|
static MAP byCntry_map;
|
||||||
|
MAP_sinit(&byCntry_map, 100, 100);
|
||||||
|
|
||||||
|
/* Build index by trawling existing by-address map */
|
||||||
|
MAP_visitAllEntries(&S.addr_map, (int(*)(void*,void*))map_byCountries, &byCntry_map);
|
||||||
|
|
||||||
|
/* Now get all cntStat handles in a vector */
|
||||||
|
unsigned vec_sz= MAP_numItems(&byCntry_map);
|
||||||
|
struct cntryStat *rtn_vec[vec_sz];
|
||||||
|
|
||||||
|
MAP_fetchAllItems(&byCntry_map, (void**)rtn_vec);
|
||||||
|
|
||||||
|
/* Sort high to low */
|
||||||
|
qsort(rtn_vec, vec_sz, sizeof(struct cntryStat*), cntryStat_count_qsort);
|
||||||
|
|
||||||
|
/* Print results */
|
||||||
|
for(unsigned i= 0; i < vec_sz; ++i) {
|
||||||
|
|
||||||
|
struct cntryStat *cs= rtn_vec[i];
|
||||||
|
ez_fprintf(stdout, "%2s %5u offenses\n"
|
||||||
|
, cs->cntry[0] ? cs->cntry : "--"
|
||||||
|
, cs->count
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rtn= EXIT_SUCCESS;
|
||||||
|
abort:
|
||||||
|
|
||||||
|
/* Make sure lock file is unlocked */
|
||||||
|
if(-1 != lock_fd) {
|
||||||
|
flock(lock_fd, LOCK_UN);
|
||||||
|
ez_close(lock_fd);
|
||||||
|
}
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*==================================================================*/
|
||||||
|
/*============== Supporting functions ==============================*/
|
||||||
|
/*==================================================================*/
|
||||||
|
|
||||||
|
static int
|
||||||
|
logentry_count_qsort(const void *p1, const void *p2)
|
||||||
|
/***************************************************************
|
||||||
|
* qsort functor puts large counts on top.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
const LOGENTRY *le1= *(const LOGENTRY *const*)p1,
|
||||||
|
*le2= *(const LOGENTRY *const*)p2;
|
||||||
|
|
||||||
|
if(le1->count > le2->count) return -1;
|
||||||
|
if(le1->count < le2->count) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
cntryStat_count_qsort(const void *p1, const void *p2)
|
||||||
|
/***************************************************************
|
||||||
|
* qsort functor puts large counts on top.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
const struct cntryStat
|
||||||
|
*cs1= *(const struct cntryStat *const*)p1,
|
||||||
|
*cs2= *(const struct cntryStat *const*)p2;
|
||||||
|
|
||||||
|
if(cs1->count > cs2->count) return -1;
|
||||||
|
if(cs1->count < cs2->count) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
configure(CFGMAP *h_cfgmap, const char *pfix)
|
||||||
|
/*****************************************************************
|
||||||
|
* dynamic initialization from contents of configuration
|
||||||
|
* dictionary.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
int rtn= 1;
|
||||||
|
const CFGMAP_ENTRY *pCde;
|
||||||
|
const struct initInfo *pIi;
|
||||||
|
|
||||||
|
for(pIi= S_initInfo_arr; pIi->symStr; ++pIi) {
|
||||||
|
char buf[1024];
|
||||||
|
/* Create the symbol we will look for */
|
||||||
|
snprintf(buf, sizeof(buf), "%s\\%s", pfix ? pfix : "", pIi->symStr);
|
||||||
|
|
||||||
|
if((pCde= CFGMAP_find(h_cfgmap, buf))) {
|
||||||
|
unsigned i;
|
||||||
|
for(i= 0; i < CFGMAP_ENTRY_numValues(pCde); ++i) {
|
||||||
|
/* Create the name for this object */
|
||||||
|
snprintf(buf, sizeof(buf), "%s\\%s", pfix ? pfix : "", CFGMAP_ENTRY_value(pCde, i));
|
||||||
|
/* Call the initialization function */
|
||||||
|
if((*pIi->init_f)(h_cfgmap, buf)) goto abort;
|
||||||
|
/* recurse with longer pfix */
|
||||||
|
if(configure(h_cfgmap, buf)) {
|
||||||
|
eprintf("ERROR: initialization function failed.");
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rtn= 0;
|
||||||
|
|
||||||
|
abort:
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
static int
|
||||||
|
stub_init(CFGMAP *map, char *symStr)
|
||||||
|
/*****************************************************************
|
||||||
|
* Stand-in xxx_init() function until a proper one is implemented.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
eprintf("HERE, symStr= \"%s\"", symStr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int
|
||||||
|
map_byCountries(LOGENTRY *e, MAP *h_map)
|
||||||
|
/**************************************************************
|
||||||
|
* Generate a "by country" map of cntryStat objects.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
struct cntryStat *cs= MAP_findStrItem(h_map, e->cntry);
|
||||||
|
if(!cs) {
|
||||||
|
cs= calloc(1, sizeof(*cs));
|
||||||
|
cs->cntry= e->cntry;
|
||||||
|
MAP_addStrKey(h_map, cs->cntry, cs);
|
||||||
|
}
|
||||||
|
|
||||||
|
cs->count += e->count;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
60
ban2fail.cfg
Normal file
60
ban2fail.cfg
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
# By default, no number of offenses are allowable
|
||||||
|
|
||||||
|
# Lighten up a little for home boys
|
||||||
|
MAX_OFFENSES 5 {
|
||||||
|
COUNTRY= US
|
||||||
|
}
|
||||||
|
|
||||||
|
# GeoIP doesn't know the location of every IP address
|
||||||
|
MAX_OFFENSES 3 {
|
||||||
|
COUNTRY= unknown
|
||||||
|
IP= 46.20.2.158
|
||||||
|
}
|
||||||
|
|
||||||
|
# This is your whitelist
|
||||||
|
MAX_OFFENSES -1 {
|
||||||
|
|
||||||
|
# me from home
|
||||||
|
IP= 205.144.171.37
|
||||||
|
|
||||||
|
# Some user
|
||||||
|
IP= 173.236.196.36
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LOGTYPE auth {
|
||||||
|
DIR= /var/log
|
||||||
|
PREFIX= auth.log
|
||||||
|
|
||||||
|
# imapd[20193]= Login failed user=hollingsworth@robertsonoptical.com auth=hollingsworth@robertsonoptical.com host=[186.179.170.12]
|
||||||
|
REGEX= imapd.*Login failed.*\[([0-9.]+)\]$
|
||||||
|
|
||||||
|
# sshd[6165]= Failed password for invalid user user from 185.224.137.201 port 44865 ssh2
|
||||||
|
REGEX= sshd.*Failed password.*from ([0-9.]+) port [0-9]+ ssh2$
|
||||||
|
|
||||||
|
# Unable to negotiate with 193.188.22.188 port ...
|
||||||
|
REGEX= Unable to negotiate with ([0-9.]+) port
|
||||||
|
|
||||||
|
# in.qpopper[14962]= pam_unix(qpopper=auth)= authentication failure; logname= uid=0 euid=0 tty=96.89.83.1
|
||||||
|
REGEX= in\.qpopper.*authentication failure.*tty=([0-9.]+)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGTYPE exim4 {
|
||||||
|
|
||||||
|
DIR= /var/log/exim4
|
||||||
|
PREFIX= mainlog
|
||||||
|
|
||||||
|
# cram_md5_server authenticator failed for ([78.128.113.121]) [78.128.113.121]
|
||||||
|
# cram_md5_server authenticator failed for (swim.diverseenvironment.com.) [185.211.245.198]
|
||||||
|
REGEX= [[:alnum:]_]+ authenticator failed for .*\[([0-9.]+)\]
|
||||||
|
|
||||||
|
# 2019-11-15 00:08:25 SMTP protocol error in "AUTH LOGIN" H=(User) [193.56.28.176] LOGIN authentication mechanism not supported
|
||||||
|
REGEX= \[([0-9.]+)\] [[:alnum:]_]+ authentication mechanism not supported
|
||||||
|
|
||||||
|
# 2019-11-20 03:44:51 1iXLbX-0000ZX-F8 <= kirsten@rrci.com H=(rrci.com) [171.244.140.160] P=esmtpa A=cram_md5_server:kirsten S=2742 id=9857581066.20191120084450@rrci.com
|
||||||
|
# 2019-11-20 18:21:15 1iXZHe-0002fZ-W8 <= kirsten@rrci.com H=035-133-139-132.res.spectrum.com ([192.168.1.29]) [35.133.139.132] P=esmtpsa X=TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128 CV=no A=plain_server:kirsten S=703 id=e8478681-4fc5-75d8-7328-52f534956d65@rrci.com
|
||||||
|
REGEX= \[([0-9.]+)\].*A=[[:alnum:]_]+_server:
|
||||||
|
|
||||||
|
}
|
||||||
|
|
71
ban2fail.h
Normal file
71
ban2fail.h
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2019 by John D. Robertson *
|
||||||
|
* john@rrci.com *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program 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 *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
/***************************************************************************************
|
||||||
|
* ban2fail global process declarations and data.
|
||||||
|
***************************************************************************************/
|
||||||
|
|
||||||
|
#ifndef BAN2FAIL_H
|
||||||
|
#define BAN2FAIL_H
|
||||||
|
|
||||||
|
#include <regex.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "cfgmap.h"
|
||||||
|
|
||||||
|
/* Maximum number of source ip addresses per iptables command.
|
||||||
|
* I have not tested larger numbers, and it would probably
|
||||||
|
* work with a much larger number. The command line maximum
|
||||||
|
* is something like 200K characters.
|
||||||
|
*/
|
||||||
|
#define IPTABLES_BATCH_SZ 10
|
||||||
|
|
||||||
|
/* Where to find stuff */
|
||||||
|
#define CONFIGFILE "/etc/ban2fail/ban2fail.cfg"
|
||||||
|
#define LOCKPATH "/var/run/lock/ban2fail"
|
||||||
|
#define CACHEDIR "/var/cache/ban2fail"
|
||||||
|
#define IPTABLES "/usr/sbin/iptables"
|
||||||
|
#define GEOIP_DB "/usr/share/GeoIP/GeoIP.dat"
|
||||||
|
|
||||||
|
|
||||||
|
/* Singleton static object with global visibility */
|
||||||
|
extern struct Global {
|
||||||
|
enum {
|
||||||
|
GLB_VERBOSE_FLG =1<<0,
|
||||||
|
GLB_LIST_ADDR_FLG =1<<1,
|
||||||
|
GLB_LIST_CNTRY_FLG =1<<2,
|
||||||
|
GLB_DONT_IPTABLE_FLG =1<<3,
|
||||||
|
GLB_PRINT_MASK = GLB_LIST_CNTRY_FLG|GLB_LIST_ADDR_FLG
|
||||||
|
} flags;
|
||||||
|
|
||||||
|
MAP logType_map;
|
||||||
|
|
||||||
|
char *cacheDir,
|
||||||
|
*lockPath;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
int major,
|
||||||
|
minor,
|
||||||
|
patch;
|
||||||
|
} version;
|
||||||
|
|
||||||
|
} G;
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
268
cfgmap.h
Normal file
268
cfgmap.h
Normal file
@ -0,0 +1,268 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2019 by John D. Robertson *
|
||||||
|
* john@rrci.com *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program 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 *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef CFGMAP_H
|
||||||
|
#define CFGMAP_H
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "map.h"
|
||||||
|
#include "ptrvec.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*===================== CFGMAP_ENTRY ========================*/
|
||||||
|
typedef struct {
|
||||||
|
char *symbol;
|
||||||
|
PTRVEC value_lst; /* Possible multiple values for a given symbol */
|
||||||
|
unsigned nLookups;/* How many times this symbol has been looked up */
|
||||||
|
unsigned symLen;
|
||||||
|
} CFGMAP_ENTRY;
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
CFGMAP_ENTRY_numValues(const CFGMAP_ENTRY * self);
|
||||||
|
/******************************************************************
|
||||||
|
* Return the number of values stored for a given entry.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const char*
|
||||||
|
CFGMAP_ENTRY_symbol(const CFGMAP_ENTRY * self);
|
||||||
|
/******************************************************************
|
||||||
|
* Return the string for a the symbol.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const char*
|
||||||
|
CFGMAP_ENTRY_value(const CFGMAP_ENTRY * self, unsigned ndx);
|
||||||
|
/******************************************************************
|
||||||
|
* Return the string for a the value indicated by ndx.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const char*
|
||||||
|
CFGMAP_ENTRY_value_sn(const CFGMAP_ENTRY * self, unsigned *sn_buf, unsigned ndx);
|
||||||
|
/******************************************************************
|
||||||
|
* Return the string *and* serial number for a the value indicated by ndx.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
CFGMAP_ENTRY_print(const CFGMAP_ENTRY * self, FILE * fh);
|
||||||
|
/************************************************************************
|
||||||
|
* Print information for debugging.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*================== CFGMAP =================================*/
|
||||||
|
typedef struct {
|
||||||
|
enum {
|
||||||
|
CFGMAP_NTUPLES_KNOWN_FLG = 1 << 0
|
||||||
|
} flags;
|
||||||
|
unsigned recurs_lvl;
|
||||||
|
MAP entry_tbl; /* Table of all entries in map */
|
||||||
|
PTRVEC curlyBlock_lst; /* Stack of curly brace block symbols */
|
||||||
|
unsigned serial_no_seq,/* For assigning serial number to values */
|
||||||
|
nTuples;
|
||||||
|
} CFGMAP;
|
||||||
|
|
||||||
|
#define CFGMAP_file_create(p, fname) \
|
||||||
|
(CFGMAP_file_constructor((p)=malloc(sizeof(CFGMAP)), fname) ? (p) : ( p ? realloc(CFGMAP_destructor(p),0) : 0 ))
|
||||||
|
CFGMAP*
|
||||||
|
CFGMAP_file_constructor(CFGMAP * self, const char *fname);
|
||||||
|
/******************************************************************
|
||||||
|
* Create a map from a configuration file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CFGMAP_create(p) \
|
||||||
|
((p)= (CFGMAP_constructor((p)=malloc(sizeof(CFGMAP))) ? (p) : ( p ? realloc(CFGMAP_destructor(p),0) : 0 )))
|
||||||
|
CFGMAP*
|
||||||
|
CFGMAP_constructor(CFGMAP * self);
|
||||||
|
/******************************************************************
|
||||||
|
* Create an empty map.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CFGMAP_destroy(s) \
|
||||||
|
{if(CFGMAP_destructor(s)) {free(s); s=0;}}
|
||||||
|
void*
|
||||||
|
CFGMAP_destructor(CFGMAP * self);
|
||||||
|
/******************************************************************
|
||||||
|
* Free resources associated with configuration file map.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
CFGMAP_file_read(CFGMAP * self, const char *fname);
|
||||||
|
/**************************************************************************
|
||||||
|
* Read a file to populate the map.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
CFGMAP_print(CFGMAP * self, FILE * fh);
|
||||||
|
/******************************************************************
|
||||||
|
* Print to stream for debugging purposes
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
CFGMAP_visitAllSymbols(CFGMAP * self, int (*func) (const char *symbol, void *ctxt), void *ctxt);
|
||||||
|
/******************************************************************
|
||||||
|
* Call (*func)() for all symbols in the map.
|
||||||
|
*/
|
||||||
|
|
||||||
|
size_t
|
||||||
|
CFGMAP_numUnused_symbols(CFGMAP * self);
|
||||||
|
/******************************************************************
|
||||||
|
* Print unused symbol count.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
CFGMAP_print_unused_symbols(CFGMAP * self, FILE * fh);
|
||||||
|
/******************************************************************
|
||||||
|
* Print unused symbols for troubleshooting
|
||||||
|
*/
|
||||||
|
|
||||||
|
const CFGMAP_ENTRY*
|
||||||
|
CFGMAP_find(CFGMAP * self, const char *symbol);
|
||||||
|
/************************************************************************
|
||||||
|
* Try to locate a matching CFGMAP_ENTRY
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct CFGMAP_tuple {
|
||||||
|
const char *key,
|
||||||
|
*value;
|
||||||
|
unsigned serial_no;
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned
|
||||||
|
CFGMAP_find_tuples(CFGMAP * self, struct CFGMAP_tuple rtn_arr[], const char *symbol);
|
||||||
|
/************************************************************************
|
||||||
|
* Find all tuples with a key matching symbol
|
||||||
|
* returns the number of tuples which were populated.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
CFGMAP_regex_find(CFGMAP * self, const CFGMAP_ENTRY * rtn_arr[], const char *patternStr);
|
||||||
|
/************************************************************************
|
||||||
|
* Find all instances of symbol which match patternStr.
|
||||||
|
* Returns: the number of matches, or -1 for error.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const char*
|
||||||
|
CFGMAP_find_single_value(CFGMAP * self, const char *symbol);
|
||||||
|
/************************************************************************
|
||||||
|
* Find exactly one value for a symbol, or return NULL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const char*
|
||||||
|
CFGMAP_find_last_value(CFGMAP * self, const char *symbol);
|
||||||
|
/************************************************************************
|
||||||
|
* Find the last value for a symbol, or return NULL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
CFGMAP_append(CFGMAP * self, const char *symbol, unsigned int symLen, const char *value);
|
||||||
|
/**************************************************************************
|
||||||
|
* Append a value to a config entry, creating a new entry if necessary.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
CFGMAP_query_uint(CFGMAP * self, unsigned int *pRtn, unsigned int dfltVal, const char *symbol);
|
||||||
|
/**********************************************************************************
|
||||||
|
* Convenience query function.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
CFGMAP_query_last_enum(
|
||||||
|
CFGMAP * self,
|
||||||
|
int *pRtn,
|
||||||
|
int dfltVal,
|
||||||
|
const char *symbol,
|
||||||
|
const struct enumTuple et_arr[]
|
||||||
|
);
|
||||||
|
/**********************************************************************************
|
||||||
|
* Convenience query function for enums.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
CFGMAP_query_last_flags(
|
||||||
|
CFGMAP * self,
|
||||||
|
int *pRtn,
|
||||||
|
int dfltVal,
|
||||||
|
const char *symbol,
|
||||||
|
const struct bitTuple bt_arr[]
|
||||||
|
);
|
||||||
|
/**********************************************************************************
|
||||||
|
* Convenience query function for possibly OR'd flags.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
CFGMAP_query_last_bool(CFGMAP * self, int *pRtn, int dfltVal, const char *symbol);
|
||||||
|
/**********************************************************************************
|
||||||
|
* Convenience function.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
CFGMAP_query_last_int(CFGMAP * self, int *pRtn, int dfltVal, const char *symbol);
|
||||||
|
/**********************************************************************************
|
||||||
|
* Convenience function.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
CFGMAP_query_last_uint(CFGMAP * self, unsigned *pRtn, unsigned dfltVal, const char *symbol);
|
||||||
|
/**********************************************************************************
|
||||||
|
* Convenience function.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
CFGMAP_query_last_dbl(CFGMAP * self, double *pRtn, double dfltVal, const char *symbol);
|
||||||
|
/**********************************************************************************
|
||||||
|
* Convenience function.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
CFGMAP_query_last_string(CFGMAP * self, char **pRtn, const char *dfltVal, const char *symbol);
|
||||||
|
/**********************************************************************************
|
||||||
|
* Convenience function.
|
||||||
|
* Note: string assigned to *pRtn was allocated by strdup().
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
CFGMAP_query_last_time_of_day(CFGMAP * self, int *pRtn, int dfltVal, const char *symbol);
|
||||||
|
/**********************************************************************************
|
||||||
|
* Convenience function to convert hh:mm to a number of seconds.
|
||||||
|
*/
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
CFGMAP_numEntries(CFGMAP * self);
|
||||||
|
/******************************************************************
|
||||||
|
* Return the number of values stored for a given entry.
|
||||||
|
*/
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
CFGMAP_numTuples(CFGMAP * self);
|
||||||
|
/******************************************************************
|
||||||
|
* Return the number of tuples stored in the configuration map.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
CFGMAP_obtain_prefix(char *rtnBuf, size_t buf_sz, const char *path);
|
||||||
|
/******************************************************************
|
||||||
|
* Given a full path string, place the prefix in rtnBuf.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
64
cntry.c
Normal file
64
cntry.c
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2019 by John D. Robertson *
|
||||||
|
* john@rrci.com *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program 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 *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#include <assert.h>
|
||||||
|
#include <GeoIP.h>
|
||||||
|
|
||||||
|
#include "ban2fail.h"
|
||||||
|
#include "cntry.h"
|
||||||
|
#include "map.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
/*==================================================================*/
|
||||||
|
/*=================== Local static data ============================*/
|
||||||
|
/*==================================================================*/
|
||||||
|
static struct {
|
||||||
|
|
||||||
|
int is_init;
|
||||||
|
GeoIP *gip;
|
||||||
|
|
||||||
|
} S;
|
||||||
|
|
||||||
|
static void
|
||||||
|
init()
|
||||||
|
/********************************************************
|
||||||
|
* Perform any 1 time initialization.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
/* Note that initialization has happened */
|
||||||
|
S.is_init= 1;
|
||||||
|
|
||||||
|
/* Open the GeoIP database */
|
||||||
|
S.gip= GeoIP_open(GEOIP_DB, 0);
|
||||||
|
if(!S.gip) {
|
||||||
|
eprintf("PANIC: GeoIP_open(\"%s\") failed!", GEOIP_DB);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
COUNTRY_get_code(const char *addr)
|
||||||
|
/********************************************************
|
||||||
|
* Try to get the country code.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
if(!S.is_init) init();
|
||||||
|
|
||||||
|
return GeoIP_country_code_by_addr(S.gip, addr);
|
||||||
|
}
|
||||||
|
|
40
cntry.h
Normal file
40
cntry.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2019 by John D. Robertson *
|
||||||
|
* john@rrci.com *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program 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 *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef COUNTRY_H
|
||||||
|
#define COUNTRY_H
|
||||||
|
|
||||||
|
#include "cfgmap.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const char*
|
||||||
|
COUNTRY_get_code(const char *addr);
|
||||||
|
/********************************************************
|
||||||
|
* Return a pointer to the 2 letter country abbrev,
|
||||||
|
* or NULL if not known.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
77
ez_dirent.c
Normal file
77
ez_dirent.c
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2019 by John D. Robertson *
|
||||||
|
* john@rrci.com *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program 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 *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
#include "ez_dirent.h"
|
||||||
|
|
||||||
|
/***************************************************/
|
||||||
|
DIR* _ez_opendir (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
const char *name
|
||||||
|
)
|
||||||
|
{
|
||||||
|
DIR *rtn= opendir (name);
|
||||||
|
if (!rtn) {
|
||||||
|
_sys_eprintf((const char*(*)(int))strerror, fileName, lineNo, funcName, "opendir(\"%s\") failed", name);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************/
|
||||||
|
int _ez_closedir (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
DIR *dirp
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int rtn= closedir (dirp);
|
||||||
|
if (-1 == rtn) {
|
||||||
|
_sys_eprintf((const char*(*)(int))strerror, fileName, lineNo, funcName, "closedir() failed");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************/
|
||||||
|
struct dirent* _ez_readdir (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
DIR *dirp
|
||||||
|
)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Pass on doctored format string and varargs to vfprintf() */
|
||||||
|
errno= 0;
|
||||||
|
struct dirent* rtn= readdir(dirp);
|
||||||
|
|
||||||
|
if (!rtn && errno) {
|
||||||
|
_sys_eprintf((const char*(*)(int))strerror, fileName, lineNo, funcName, "readdir() failed");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
70
ez_dirent.h
Normal file
70
ez_dirent.h
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2018 by John D. Robertson *
|
||||||
|
* john@rrci.com *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program 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 *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
/***************************************************************************
|
||||||
|
ez_dirent.h - description
|
||||||
|
dirent calls with boilerplate error handling.
|
||||||
|
|
||||||
|
-------------------
|
||||||
|
begin : Tue Nov 13 19:42:23 EST 2018
|
||||||
|
email : john@rrci.com
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef EZ_DIRENT_H
|
||||||
|
#define EZ_DIRENT_H
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define ez_opendir(name) \
|
||||||
|
_ez_opendir(__FILE__, __LINE__, __FUNCTION__, name)
|
||||||
|
DIR* _ez_opendir (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
const char *name
|
||||||
|
);
|
||||||
|
|
||||||
|
#define ez_closedir(dirp) \
|
||||||
|
_ez_closedir(__FILE__, __LINE__, __FUNCTION__, dirp)
|
||||||
|
int _ez_closedir (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
DIR *dirp
|
||||||
|
);
|
||||||
|
|
||||||
|
#define ez_readdir(dirp) \
|
||||||
|
_ez_readdir(__FILE__, __LINE__, __FUNCTION__, dirp)
|
||||||
|
struct dirent* _ez_readdir (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
DIR *dirp
|
||||||
|
);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
192
ez_gzfile.c
Normal file
192
ez_gzfile.c
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2019 by John D. Robertson *
|
||||||
|
* john@rrci.com *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program 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 *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "ez_gzfile.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
/***************************************************/
|
||||||
|
gzFile _ez_gzopen(
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
const char *path,
|
||||||
|
const char *mode
|
||||||
|
)
|
||||||
|
{
|
||||||
|
gzFile rtn= gzopen(path, mode);
|
||||||
|
if(rtn) return rtn;
|
||||||
|
|
||||||
|
_sys_eprintf((const char*(*)(int))strerror, fileName, lineNo, funcName, "ERROR: gzopen()");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************/
|
||||||
|
int _ez_gzclose(
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
gzFile file
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int err= gzclose(file);
|
||||||
|
if(Z_OK == err) return Z_OK;
|
||||||
|
|
||||||
|
const char *msg="Unknow error";
|
||||||
|
|
||||||
|
switch(err) {
|
||||||
|
|
||||||
|
case Z_ERRNO:
|
||||||
|
_sys_eprintf((const char*(*)(int))strerror, fileName, lineNo, funcName, "ERROR: gzclose()");
|
||||||
|
abort();
|
||||||
|
|
||||||
|
case Z_STREAM_ERROR:
|
||||||
|
msg= "File not valid";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Z_MEM_ERROR:
|
||||||
|
msg= "Out of memory";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Z_BUF_ERROR:
|
||||||
|
msg= "Read ended in middle of a stream";
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
_eprintf(fileName, lineNo, funcName, "ERROR: gzclose() [ %s ]", msg);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************/
|
||||||
|
int _ez_gzwrite(
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
gzFile file,
|
||||||
|
voidpc buf,
|
||||||
|
unsigned len
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int n= gzwrite(file, buf, len);
|
||||||
|
if(n == len) return n;
|
||||||
|
|
||||||
|
int err;
|
||||||
|
const char *str= gzerror(file, &err);
|
||||||
|
if(Z_ERRNO == err) {
|
||||||
|
_sys_eprintf((const char*(*)(int))strerror, fileName, lineNo, funcName, "ERROR: gzwrite()");
|
||||||
|
} else {
|
||||||
|
_eprintf(fileName, lineNo, funcName, "ERROR: gzwrite() [ %s ]", str);
|
||||||
|
}
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************/
|
||||||
|
int _ez_gzread(
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
gzFile file,
|
||||||
|
voidp buf,
|
||||||
|
unsigned len
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int n= gzread(file, buf, len);
|
||||||
|
if(-1 != n) return n;
|
||||||
|
|
||||||
|
int err;
|
||||||
|
const char *str= gzerror(file, &err);
|
||||||
|
if(Z_ERRNO == err) {
|
||||||
|
_sys_eprintf((const char*(*)(int))strerror, fileName, lineNo, funcName, "ERROR: gzread()");
|
||||||
|
} else {
|
||||||
|
_eprintf(fileName, lineNo, funcName, "ERROR: gzread() [ %s ]", str);
|
||||||
|
}
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************/
|
||||||
|
int _ez_gzflush(
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
gzFile file,
|
||||||
|
int flush
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int err= gzflush(file, flush);
|
||||||
|
if(Z_OK == err) return Z_OK;
|
||||||
|
|
||||||
|
const char *str= gzerror(file, &err);
|
||||||
|
if(Z_ERRNO == err) {
|
||||||
|
_sys_eprintf((const char*(*)(int))strerror, fileName, lineNo, funcName, "ERROR: gzflush()");
|
||||||
|
} else {
|
||||||
|
_eprintf(fileName, lineNo, funcName, "ERROR: gzflush() [ %s ]", str);
|
||||||
|
}
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************/
|
||||||
|
z_off_t _ez_gzseek(
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
gzFile file,
|
||||||
|
z_off_t offset,
|
||||||
|
int whence
|
||||||
|
)
|
||||||
|
{
|
||||||
|
z_off_t rtn= gzseek(file, offset, whence);
|
||||||
|
if(-1 != rtn) return rtn;
|
||||||
|
|
||||||
|
int err;
|
||||||
|
const char *str= gzerror(file, &err);
|
||||||
|
if(Z_ERRNO == err) {
|
||||||
|
_sys_eprintf((const char*(*)(int))strerror, fileName, lineNo, funcName, "ERROR: gzseek()");
|
||||||
|
} else {
|
||||||
|
_eprintf(fileName, lineNo, funcName, "ERROR: gzseek() [ %s ]", str);
|
||||||
|
}
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************/
|
||||||
|
char* _ez_gzgets (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
gzFile file,
|
||||||
|
char *buf,
|
||||||
|
int len
|
||||||
|
)
|
||||||
|
{
|
||||||
|
char *rtn= gzgets(file, buf, len);
|
||||||
|
|
||||||
|
if(!rtn) {
|
||||||
|
int err;
|
||||||
|
const char *str= gzerror(file, &err);
|
||||||
|
if(Z_OK != err && Z_STREAM_END != err) {
|
||||||
|
if(Z_ERRNO == err) {
|
||||||
|
_sys_eprintf((const char*(*)(int))strerror, fileName, lineNo, funcName, "ERROR: gzgets()");
|
||||||
|
} else {
|
||||||
|
_eprintf(fileName, lineNo, funcName, "ERROR: gzgets() [ %s ]", str);
|
||||||
|
}
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rtn;
|
||||||
|
}
|
107
ez_gzfile.h
Normal file
107
ez_gzfile.h
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2019 by John D. Robertson *
|
||||||
|
* john@rrci.com *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program 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 *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef EZ_GZFILE_H
|
||||||
|
#define EZ_GZFILE_H
|
||||||
|
|
||||||
|
/* Simplified interface to libz file functions */
|
||||||
|
#include <zlib.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ez_gzopen(path, mode) \
|
||||||
|
_ez_gzopen(__FILE__, __LINE__, __FUNCTION__, path, mode)
|
||||||
|
gzFile _ez_gzopen(
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
const char *path,
|
||||||
|
const char *mode
|
||||||
|
);
|
||||||
|
|
||||||
|
#define ez_gzclose(file) \
|
||||||
|
_ez_gzclose(__FILE__, __LINE__, __FUNCTION__, file)
|
||||||
|
int _ez_gzclose(
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
gzFile file
|
||||||
|
);
|
||||||
|
|
||||||
|
#define ez_gzwrite(file, buf, len) \
|
||||||
|
_ez_gzwrite(__FILE__, __LINE__, __FUNCTION__, file, buf, len)
|
||||||
|
int _ez_gzwrite(
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
gzFile file,
|
||||||
|
voidpc buf,
|
||||||
|
unsigned len
|
||||||
|
);
|
||||||
|
|
||||||
|
#define ez_gzread(file, buf, len) \
|
||||||
|
_ez_gzread(__FILE__, __LINE__, __FUNCTION__, file, buf, len)
|
||||||
|
int _ez_gzread(
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
gzFile file,
|
||||||
|
voidp buf,
|
||||||
|
unsigned len
|
||||||
|
);
|
||||||
|
|
||||||
|
#define ez_gzflush(file, flush) \
|
||||||
|
_ez_gzflush(__FILE__, __LINE__, __FUNCTION__, file, flush)
|
||||||
|
int _ez_gzflush(
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
gzFile file,
|
||||||
|
int flush
|
||||||
|
);
|
||||||
|
|
||||||
|
#define ez_gzseek(file, offset, whence) \
|
||||||
|
_ez_gzseek(__FILE__, __LINE__, __FUNCTION__, file, offset, whence)
|
||||||
|
z_off_t _ez_gzseek(
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
gzFile file,
|
||||||
|
z_off_t offset,
|
||||||
|
int whence
|
||||||
|
);
|
||||||
|
|
||||||
|
#define ez_gzgets(file, buf, len) \
|
||||||
|
_ez_gzgets(__FILE__, __LINE__, __FUNCTION__, file, buf, len)
|
||||||
|
char* _ez_gzgets (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
gzFile file,
|
||||||
|
char *buf,
|
||||||
|
int len
|
||||||
|
);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
238
ez_stdio.c
Normal file
238
ez_stdio.c
Normal file
@ -0,0 +1,238 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2019 by John D. Robertson *
|
||||||
|
* john@rrci.com *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program 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 *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
#include "ez_stdio.h"
|
||||||
|
|
||||||
|
/***************************************************/
|
||||||
|
int _ez_fputs (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
const char *s,
|
||||||
|
FILE *stream
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int rtn= fputs (s, stream);
|
||||||
|
if (EOF == rtn) {
|
||||||
|
_sys_eprintf((const char*(*)(int))strerror, fileName, lineNo, funcName, "fputs() failed");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************/
|
||||||
|
int _ez_fputc (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
int c,
|
||||||
|
FILE *stream
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int rtn= fputc (c, stream);
|
||||||
|
if (EOF == rtn) {
|
||||||
|
_sys_eprintf((const char*(*)(int))strerror, fileName, lineNo, funcName, "fputc() failed");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************/
|
||||||
|
int _ez_fprintf (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
FILE *stream,
|
||||||
|
const char *fmt,
|
||||||
|
...
|
||||||
|
)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
|
||||||
|
/* Pass on doctored format string and varargs to vfprintf() */
|
||||||
|
va_start(args, fmt);
|
||||||
|
int rtn= vfprintf(stream, fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
if (0 > rtn) {
|
||||||
|
_sys_eprintf((const char*(*)(int))strerror, fileName, lineNo, funcName, "vfprintf() failed");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************/
|
||||||
|
FILE* _ez_popen (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
const char *command,
|
||||||
|
const char *type
|
||||||
|
)
|
||||||
|
{
|
||||||
|
FILE *rtn= popen (command, type);
|
||||||
|
if (!rtn) {
|
||||||
|
_sys_eprintf((const char*(*)(int))strerror, fileName, lineNo, funcName, "popen(\"%s\", \"%s\") failed", command, type);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************/
|
||||||
|
FILE* _ez_fopen (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
const char *pathname,
|
||||||
|
const char *mode
|
||||||
|
)
|
||||||
|
{
|
||||||
|
FILE *rtn= fopen (pathname, mode);
|
||||||
|
if (!rtn) {
|
||||||
|
_sys_eprintf((const char*(*)(int))strerror, fileName, lineNo, funcName, "fopen(\"%s\", \"%s\") failed", pathname, mode);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************/
|
||||||
|
int _ez_fclose (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
FILE *stream
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int rtn= fclose (stream);
|
||||||
|
if (EOF == rtn) {
|
||||||
|
_sys_eprintf((const char*(*)(int))strerror, fileName, lineNo, funcName, "fclose() failed");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************/
|
||||||
|
size_t _ez_fread (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
void *ptr,
|
||||||
|
size_t size,
|
||||||
|
size_t nmemb,
|
||||||
|
FILE *stream
|
||||||
|
)
|
||||||
|
{
|
||||||
|
size_t rtn= fread (ptr, size, nmemb, stream);
|
||||||
|
if (ferror(stream)) {
|
||||||
|
_sys_eprintf((const char*(*)(int))strerror, fileName, lineNo, funcName, "fread() failed");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************/
|
||||||
|
size_t _ez_fwrite (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
const void *ptr,
|
||||||
|
size_t size,
|
||||||
|
size_t nmemb,
|
||||||
|
FILE *stream
|
||||||
|
)
|
||||||
|
{
|
||||||
|
size_t rtn= fwrite (ptr, size, nmemb, stream);
|
||||||
|
if (ferror(stream)) {
|
||||||
|
_sys_eprintf((const char*(*)(int))strerror, fileName, lineNo, funcName, "fwrite() failed");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************/
|
||||||
|
int _ez_pclose (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
FILE *stream
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int rtn= pclose (stream);
|
||||||
|
if (-1 == rtn) {
|
||||||
|
_sys_eprintf((const char*(*)(int))strerror, fileName, lineNo, funcName, "pclose() failed");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************/
|
||||||
|
char* _ez_fgets (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
char *s,
|
||||||
|
int size,
|
||||||
|
FILE *stream
|
||||||
|
)
|
||||||
|
{
|
||||||
|
char *rtn= fgets (s, size, stream);
|
||||||
|
if (!rtn && !feof(stream)) {
|
||||||
|
_sys_eprintf((const char*(*)(int))strerror, fileName, lineNo, funcName, "fgets() failed");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************/
|
||||||
|
int _ez_remove (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
const char *pathname
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int rtn= remove (pathname);
|
||||||
|
if (-1 == rtn) {
|
||||||
|
_sys_eprintf((const char*(*)(int))strerror, fileName, lineNo, funcName, "remove(\"%s\") failed", pathname);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************/
|
||||||
|
int _ez_rename (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
const char *oldpath,
|
||||||
|
const char *newpath
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int rtn= rename (oldpath, newpath);
|
||||||
|
if (-1 == rtn) {
|
||||||
|
_sys_eprintf((const char*(*)(int))strerror, fileName, lineNo, funcName, "rename(\"%s\", \"%s\") failed", oldpath, newpath);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
165
ez_stdio.h
Normal file
165
ez_stdio.h
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2018 by John D. Robertson *
|
||||||
|
* john@rrci.com *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program 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 *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
/***************************************************************************
|
||||||
|
ez_stdio.h - description
|
||||||
|
stdio calls with boilerplate error handling.
|
||||||
|
|
||||||
|
-------------------
|
||||||
|
begin : Tue Nov 13 19:42:23 EST 2018
|
||||||
|
email : john@rrci.com
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef EZ_STDIO_H
|
||||||
|
#define EZ_STDIO_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define ez_fputs(s, stream) \
|
||||||
|
_ez_fputs(__FILE__, __LINE__, __FUNCTION__, s, stream)
|
||||||
|
int _ez_fputs (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
const char *s,
|
||||||
|
FILE *stream
|
||||||
|
);
|
||||||
|
|
||||||
|
#define ez_fputc(c, stream) \
|
||||||
|
_ez_fputc(__FILE__, __LINE__, __FUNCTION__, c, stream)
|
||||||
|
int _ez_fputc (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
int c,
|
||||||
|
FILE *stream
|
||||||
|
);
|
||||||
|
|
||||||
|
#define ez_fprintf(stream, fmt, ...) \
|
||||||
|
_ez_fprintf(__FILE__, __LINE__, __FUNCTION__, stream, fmt, ##__VA_ARGS__)
|
||||||
|
int _ez_fprintf (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
FILE *stream,
|
||||||
|
const char *fmt,
|
||||||
|
...
|
||||||
|
);
|
||||||
|
|
||||||
|
#define ez_popen(command, type) \
|
||||||
|
_ez_popen(__FILE__, __LINE__, __FUNCTION__, command, type)
|
||||||
|
FILE* _ez_popen (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
const char *command,
|
||||||
|
const char *type
|
||||||
|
);
|
||||||
|
|
||||||
|
#define ez_fopen(pathname, mode) \
|
||||||
|
_ez_fopen(__FILE__, __LINE__, __FUNCTION__, pathname, mode)
|
||||||
|
FILE* _ez_fopen (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
const char *pathname,
|
||||||
|
const char *mode
|
||||||
|
);
|
||||||
|
|
||||||
|
#define ez_fclose(stream) \
|
||||||
|
_ez_fclose(__FILE__, __LINE__, __FUNCTION__, stream)
|
||||||
|
int _ez_fclose (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
FILE *stream
|
||||||
|
);
|
||||||
|
|
||||||
|
#define ez_fread(ptr, size, nmemb, stream) \
|
||||||
|
_ez_fread(__FILE__, __LINE__, __FUNCTION__, ptr, size, nmemb, stream)
|
||||||
|
size_t _ez_fread(
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
void *ptr,
|
||||||
|
size_t size,
|
||||||
|
size_t nmemb,
|
||||||
|
FILE *stream
|
||||||
|
);
|
||||||
|
|
||||||
|
#define ez_fwrite(ptr, size, nmemb, stream) \
|
||||||
|
_ez_fwrite(__FILE__, __LINE__, __FUNCTION__, ptr, size, nmemb, stream)
|
||||||
|
size_t _ez_fwrite(
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
const void *ptr,
|
||||||
|
size_t size,
|
||||||
|
size_t nmemb,
|
||||||
|
FILE *stream
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
#define ez_pclose(stream) \
|
||||||
|
_ez_pclose(__FILE__, __LINE__, __FUNCTION__, stream)
|
||||||
|
int _ez_pclose (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
FILE *stream
|
||||||
|
);
|
||||||
|
|
||||||
|
#define ez_fgets(s, size, stream) \
|
||||||
|
_ez_fgets(__FILE__, __LINE__, __FUNCTION__, s, size, stream)
|
||||||
|
char* _ez_fgets (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
char *s,
|
||||||
|
int size,
|
||||||
|
FILE *stream
|
||||||
|
);
|
||||||
|
|
||||||
|
#define ez_remove(pathname) \
|
||||||
|
_ez_remove(__FILE__, __LINE__, __FUNCTION__, pathname)
|
||||||
|
int _ez_remove (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
const char *pathname
|
||||||
|
);
|
||||||
|
|
||||||
|
#define ez_rename(oldpath, newpath) \
|
||||||
|
_ez_rename(__FILE__, __LINE__, __FUNCTION__, oldpath, newpath)
|
||||||
|
int _ez_rename (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
const char *oldpath,
|
||||||
|
const char *newpath
|
||||||
|
);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
122
ez_stdlib.c
Normal file
122
ez_stdlib.c
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2019 by John D. Robertson *
|
||||||
|
* john@rrci.com *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program 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 *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
#include "ez_stdlib.h"
|
||||||
|
|
||||||
|
/***************************************************/
|
||||||
|
int _ez_close (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
int fd
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int rtn= close (fd);
|
||||||
|
if (-1 == rtn) {
|
||||||
|
_sys_eprintf((const char*(*)(int))strerror, fileName, lineNo, funcName, "close(%d) failed", fd);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************/
|
||||||
|
ssize_t _ez_write (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
int fd,
|
||||||
|
const void *buf,
|
||||||
|
size_t count
|
||||||
|
)
|
||||||
|
{
|
||||||
|
ssize_t rtn= write (fd, buf, count);
|
||||||
|
if (-1 == rtn) {
|
||||||
|
_sys_eprintf((const char*(*)(int))strerror, fileName, lineNo, funcName, "write(fd= %d) failed", fd);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************/
|
||||||
|
int _ez_stat (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
const char *pathname,
|
||||||
|
struct stat *statbuf
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int rtn= stat (pathname, statbuf);
|
||||||
|
if (-1 == rtn) {
|
||||||
|
_sys_eprintf((const char*(*)(int))strerror, fileName, lineNo, funcName, "stat(\"%s\") failed", pathname);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************/
|
||||||
|
int _ez_mkdir (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
const char *pathname,
|
||||||
|
mode_t mode
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int rtn= mkdir (pathname, mode);
|
||||||
|
if (-1 == rtn) {
|
||||||
|
_sys_eprintf((const char*(*)(int))strerror, fileName, lineNo, funcName, "mkdir(\"%s\", %04x) failed", pathname, (unsigned)mode);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************/
|
||||||
|
int _ez_rmdir (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
const char *pathname
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int rtn= rmdir (pathname);
|
||||||
|
if (-1 == rtn) {
|
||||||
|
_sys_eprintf((const char*(*)(int))strerror, fileName, lineNo, funcName, "rmdir(\"%s\") failed", pathname);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************/
|
||||||
|
int _ez_unlink (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
const char *pathname
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int rtn= unlink (pathname);
|
||||||
|
if (-1 == rtn) {
|
||||||
|
_sys_eprintf((const char*(*)(int))strerror, fileName, lineNo, funcName, "unlink(\"%s\") failed", pathname);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
return rtn;
|
||||||
|
}
|
117
ez_stdlib.h
Normal file
117
ez_stdlib.h
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2018 by John D. Robertson *
|
||||||
|
* john@rrci.com *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program 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 *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
/***************************************************************************
|
||||||
|
ez_stdlib.h - description
|
||||||
|
stdlib calls with boilerplate error handling.
|
||||||
|
|
||||||
|
-------------------
|
||||||
|
begin : Tue Nov 13 19:42:23 EST 2018
|
||||||
|
email : john@rrci.com
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef EZ_STDLIB_H
|
||||||
|
#define EZ_STDLIB_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ez_close(fd) \
|
||||||
|
_ez_close(__FILE__, __LINE__, __FUNCTION__, fd)
|
||||||
|
int _ez_close (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
int fd
|
||||||
|
);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// FIXME: this needs to be implemented and tested
|
||||||
|
#define ez_read(fd, buf, count) \
|
||||||
|
_ez_read(__FILE__, __LINE__, __FUNCTION__, fd, buf, count)
|
||||||
|
ssize_t _ez_read (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
int fd,
|
||||||
|
void *buf,
|
||||||
|
size_t count
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ez_write(fd, buf, count) \
|
||||||
|
_ez_write(__FILE__, __LINE__, __FUNCTION__, fd, buf, count)
|
||||||
|
ssize_t _ez_write (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
int fd,
|
||||||
|
const void *buf,
|
||||||
|
size_t count
|
||||||
|
);
|
||||||
|
|
||||||
|
#define ez_stat(pathname, statbuf) \
|
||||||
|
_ez_stat(__FILE__, __LINE__, __FUNCTION__, pathname, statbuf)
|
||||||
|
int _ez_stat (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
const char *pathname,
|
||||||
|
struct stat *statbuf
|
||||||
|
);
|
||||||
|
|
||||||
|
// FIXME: xxxdir() function should be in ez_unistd.h
|
||||||
|
#define ez_mkdir(pathname, mode) \
|
||||||
|
_ez_mkdir(__FILE__, __LINE__, __FUNCTION__, pathname, mode)
|
||||||
|
int _ez_mkdir (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
const char *pathname,
|
||||||
|
mode_t mode
|
||||||
|
);
|
||||||
|
|
||||||
|
#define ez_rmdir(pathname) \
|
||||||
|
_ez_rmdir(__FILE__, __LINE__, __FUNCTION__, pathname)
|
||||||
|
int _ez_rmdir (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
const char *pathname
|
||||||
|
);
|
||||||
|
|
||||||
|
#define ez_unlink(pathname) \
|
||||||
|
_ez_unlink(__FILE__, __LINE__, __FUNCTION__, pathname)
|
||||||
|
int _ez_unlink (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
const char *pathname
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
159
iptables.c
Normal file
159
iptables.c
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2019 by John D. Robertson *
|
||||||
|
* john@rrci.com *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program 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 *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "ban2fail.h"
|
||||||
|
#include "ez_stdio.h"
|
||||||
|
#include "iptables.h"
|
||||||
|
#include "map.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
|
||||||
|
int is_init;
|
||||||
|
MAP addr_map;
|
||||||
|
|
||||||
|
} S;
|
||||||
|
|
||||||
|
static void
|
||||||
|
initialize (void)
|
||||||
|
/********************************************************
|
||||||
|
* Prepare static data, populate index from iptables.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
S.is_init= 1;
|
||||||
|
|
||||||
|
MAP_constructor(&S.addr_map, 1000, 200);
|
||||||
|
|
||||||
|
static char lbuf[1024];
|
||||||
|
static char addr[64];
|
||||||
|
FILE *fh= ez_popen(IPTABLES " -nL INPUT 2>/dev/null", "r");
|
||||||
|
for(unsigned i= 0; ez_fgets(lbuf, sizeof(lbuf)-1, fh); ++i) {
|
||||||
|
if(0 == i || 1 == i) continue;
|
||||||
|
if(1 != sscanf(lbuf, "DROP all -- %63s 0.0.0.0/0", addr)) continue;
|
||||||
|
MAP_addStrKey(&S.addr_map, addr, (void*)-1);
|
||||||
|
}
|
||||||
|
ez_pclose(fh);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
IPTABLES_is_currently_blocked(const char *addr)
|
||||||
|
/********************************************************
|
||||||
|
* This provides an efficient lookup of addresses blocked
|
||||||
|
* by iptables in the filter table, INPUT chain.
|
||||||
|
*
|
||||||
|
* RETURN:
|
||||||
|
* 1 if the supplied addr is blocked by iptables.
|
||||||
|
* 0 otherwise.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
if(!S.is_init)
|
||||||
|
initialize();
|
||||||
|
|
||||||
|
/* See if this addr is in the map */
|
||||||
|
if(MAP_findStrItem(&S.addr_map, addr)) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_control_addresses(int cmdFlag, PTRVEC *h_vec, unsigned batch_sz)
|
||||||
|
/**************************************************************
|
||||||
|
* (Un)block addresses in batches of batch_sz.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
if(!S.is_init)
|
||||||
|
initialize();
|
||||||
|
|
||||||
|
int rtn= -1;
|
||||||
|
|
||||||
|
/* Sanity check for debugging */
|
||||||
|
assert(batch_sz > 0 && batch_sz <= 100);
|
||||||
|
|
||||||
|
/* Use string buffer to form command */
|
||||||
|
static STR cmd_sb;
|
||||||
|
|
||||||
|
const char *addr;
|
||||||
|
|
||||||
|
/* Work through addresses in the vector */
|
||||||
|
while((addr= PTRVEC_remHead(h_vec))) {
|
||||||
|
|
||||||
|
/* Initialize / reset string buffer */
|
||||||
|
STR_sinit(&cmd_sb, 256+batch_sz*42);
|
||||||
|
|
||||||
|
/* Beginning of command string, with first source address */
|
||||||
|
STR_sprintf(&cmd_sb, IPTABLES " 2>&1 -%c INPUT -s %s", cmdFlag, addr);
|
||||||
|
|
||||||
|
/* Append additional source addresses */
|
||||||
|
unsigned i= 1;
|
||||||
|
while(i < batch_sz && (addr= PTRVEC_remHead(h_vec))) {
|
||||||
|
|
||||||
|
/* employ multiple source addresses for batching */
|
||||||
|
STR_sprintf(&cmd_sb, ",%s", addr);
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Put the end of the command in place */
|
||||||
|
STR_sprintf(&cmd_sb, " -j DROP");
|
||||||
|
|
||||||
|
/* Run iptables */
|
||||||
|
FILE *fh= ez_popen(STR_str(&cmd_sb), "r");
|
||||||
|
/* Display any output from iptables */
|
||||||
|
static char lbuf[1024];
|
||||||
|
while(ez_fgets(lbuf, sizeof(lbuf), fh))
|
||||||
|
ez_fprintf(stderr, "NOTE: iptables output: %s", lbuf);
|
||||||
|
|
||||||
|
/* All done */
|
||||||
|
ez_pclose(fh);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
rtn= 0;
|
||||||
|
abort:
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
IPTABLES_block_addresses(PTRVEC *h_vec, unsigned batch_sz)
|
||||||
|
/**************************************************************
|
||||||
|
* Block addresses in batches of batch_sz.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
if(!S.is_init)
|
||||||
|
initialize();
|
||||||
|
|
||||||
|
return _control_addresses('A', h_vec, batch_sz);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
IPTABLES_unblock_addresses(PTRVEC *h_vec, unsigned batch_sz)
|
||||||
|
/**************************************************************
|
||||||
|
* Block addresses in batches of batch_sz.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
if(!S.is_init)
|
||||||
|
initialize();
|
||||||
|
|
||||||
|
return _control_addresses('D', h_vec, batch_sz);
|
||||||
|
|
||||||
|
}
|
57
iptables.h
Normal file
57
iptables.h
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2019 by John D. Robertson *
|
||||||
|
* john@rrci.com *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program 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 *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef IPTABLES_H
|
||||||
|
#define IPTABLES_H
|
||||||
|
|
||||||
|
#include "ptrvec.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int
|
||||||
|
IPTABLES_is_currently_blocked(const char *addr);
|
||||||
|
/********************************************************
|
||||||
|
* This provides an efficient lookup of addresses blocked
|
||||||
|
* by iptables in the filter table, INPUT chain.
|
||||||
|
*
|
||||||
|
* RETURN:
|
||||||
|
* 1 if the supplied addr is blocked by iptables.
|
||||||
|
* 0 otherwise.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
IPTABLES_block_addresses(PTRVEC *h_vec, unsigned batch_sz);
|
||||||
|
/**************************************************************
|
||||||
|
* Block addresses in batches of batch_sz.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
IPTABLES_unblock_addresses(PTRVEC *h_vec, unsigned batch_sz);
|
||||||
|
/**************************************************************
|
||||||
|
* Unblock addresses in batches of batch_sz.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
168
logEntry.c
Normal file
168
logEntry.c
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2019 by John D. Robertson *
|
||||||
|
* john@rrci.com *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program 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 *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#include <assert.h>
|
||||||
|
#include <GeoIP.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "ban2fail.h"
|
||||||
|
#include "cntry.h"
|
||||||
|
#include "ez_stdio.h"
|
||||||
|
#include "map.h"
|
||||||
|
#include "logEntry.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
/********************************************************/
|
||||||
|
/**************** LOGENTRY ******************************/
|
||||||
|
/********************************************************/
|
||||||
|
|
||||||
|
static void
|
||||||
|
common_constructor(LOGENTRY *self)
|
||||||
|
/******************************************************************
|
||||||
|
* common portion for all constructors.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
memset(self, 0, sizeof(*self));
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGENTRY*
|
||||||
|
LOGENTRY_addr_constructor(LOGENTRY *self, const char *addr)
|
||||||
|
/********************************************************
|
||||||
|
* Prepare for use.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
LOGENTRY *rtn= NULL;
|
||||||
|
|
||||||
|
common_constructor(self);
|
||||||
|
|
||||||
|
strncpy(self->addr, addr, sizeof(self->addr)-1);
|
||||||
|
|
||||||
|
const char *cntry= COUNTRY_get_code(self->addr);
|
||||||
|
if(cntry)
|
||||||
|
strncpy(self->cntry, cntry, 2);
|
||||||
|
|
||||||
|
rtn= self;
|
||||||
|
abort:
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGENTRY*
|
||||||
|
LOGENTRY_cache_constructor(LOGENTRY *self, const char *cacheFileEntry)
|
||||||
|
/********************************************************
|
||||||
|
* Prepare for use.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
LOGENTRY *rtn= NULL;
|
||||||
|
|
||||||
|
common_constructor(self);
|
||||||
|
|
||||||
|
int rc= sscanf(cacheFileEntry, "%u %45s %2s"
|
||||||
|
,&self->count
|
||||||
|
,self->addr
|
||||||
|
,self->cntry);
|
||||||
|
|
||||||
|
if(2 > rc) {
|
||||||
|
eprintf("ERROR: failed to interpret \"%s\"", cacheFileEntry);
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
|
||||||
|
rtn= self;
|
||||||
|
abort:
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
LOGENTRY_destructor(LOGENTRY *self)
|
||||||
|
/********************************************************
|
||||||
|
* Free resources.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LOGENTRY_register(LOGENTRY *self)
|
||||||
|
/********************************************************
|
||||||
|
* Register the current failure try.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
/* Keep track of count */
|
||||||
|
++self->count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
LOGENTRY_cacheWrite(LOGENTRY *self, FILE *fh)
|
||||||
|
/********************************************************
|
||||||
|
* Write to the cache file in a form we can read later.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
ez_fprintf(fh, "%u %s %s\n"
|
||||||
|
, self->count
|
||||||
|
, self->addr
|
||||||
|
, self->cntry
|
||||||
|
);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
LOGENTRY_print(LOGENTRY *self, FILE *fh)
|
||||||
|
/********************************************************
|
||||||
|
* Print a human readable representation of *self.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
ez_fprintf(fh,
|
||||||
|
"\tLOGENTRY %p { addr= \"%s\", cntry= \"%2s\" count= %u }\n"
|
||||||
|
, self
|
||||||
|
, self->addr
|
||||||
|
, self->cntry
|
||||||
|
, self->count
|
||||||
|
);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
LOGENTRY_map_addr(LOGENTRY *self, MAP *h_rtnMap)
|
||||||
|
/********************************************************
|
||||||
|
* Create a map of LOGENTRY objects with composite
|
||||||
|
* counts by address.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
LOGENTRY *e= MAP_findStrItem(h_rtnMap, self->addr);
|
||||||
|
|
||||||
|
if(!e) {
|
||||||
|
LOGENTRY_addr_create(e, self->addr);
|
||||||
|
assert(e);
|
||||||
|
MAP_addStrKey(h_rtnMap, e->addr, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
e->count += self->count;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
LOGENTRY_offenseCount(LOGENTRY *self, unsigned *h_sum)
|
||||||
|
/********************************************************
|
||||||
|
* Get a count of all offenses for this entry.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
*h_sum += self->count;
|
||||||
|
return 0;
|
||||||
|
}
|
107
logEntry.h
Normal file
107
logEntry.h
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2019 by John D. Robertson *
|
||||||
|
* john@rrci.com *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program 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 *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef LOGENTRY_H
|
||||||
|
#define LOGENTRY_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "map.h"
|
||||||
|
|
||||||
|
/* One of these for each offense found in a log file */
|
||||||
|
typedef struct _LOGENTRY {
|
||||||
|
unsigned logfile_ndx;
|
||||||
|
char addr[46],
|
||||||
|
cntry[3];
|
||||||
|
unsigned count;
|
||||||
|
} LOGENTRY;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define LOGENTRY_addr_create(p, addr) \
|
||||||
|
((p)=(LOGENTRY_addr_constructor((p)=malloc(sizeof(LOGENTRY)), addr) ? (p) : ( p ? realloc(LOGENTRY_destructor(p),0) : 0 )))
|
||||||
|
LOGENTRY*
|
||||||
|
LOGENTRY_addr_constructor(LOGENTRY *self, const char *addr);
|
||||||
|
/********************************************************
|
||||||
|
* Prepare for use from an address found in a log entry.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define LOGENTRY_cache_create(p, cacheFileEntry) \
|
||||||
|
((p)=(LOGENTRY_cache_constructor((p)=malloc(sizeof(LOGENTRY)), cacheFileEntry) ? (p) : ( p ? realloc(LOGENTRY_destructor(p),0) : 0 )))
|
||||||
|
LOGENTRY*
|
||||||
|
LOGENTRY_cache_constructor(LOGENTRY *self, const char *cacheFileEntry);
|
||||||
|
/********************************************************
|
||||||
|
* Prepare for use with entry from cache file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define LOGENTRY_destroy(s) \
|
||||||
|
{if(LOGENTRY_destructor(s)) {free(s); (s)=0;}}
|
||||||
|
void*
|
||||||
|
LOGENTRY_destructor(LOGENTRY *self);
|
||||||
|
/********************************************************
|
||||||
|
* Free resources.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
LOGENTRY_register(LOGENTRY *self);
|
||||||
|
/********************************************************
|
||||||
|
* Register the current failure try.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
int
|
||||||
|
LOGENTRY_is_blocked_country(const LOGENTRY *self);
|
||||||
|
/********************************************************
|
||||||
|
* Return 1 if the country is blocked, or 0.
|
||||||
|
*/
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int
|
||||||
|
LOGENTRY_cacheWrite(LOGENTRY *self, FILE *fh);
|
||||||
|
/********************************************************
|
||||||
|
* Write to the cache file in a form we can read later.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
LOGENTRY_print(LOGENTRY *self, FILE *fh);
|
||||||
|
/********************************************************
|
||||||
|
* Print a human readable representation of *self.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
LOGENTRY_map_addr(LOGENTRY *self, MAP *h_rtnMap);
|
||||||
|
/********************************************************
|
||||||
|
* Create a map of LOGENTRY objects with composite
|
||||||
|
* counts by address.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
LOGENTRY_offenseCount(LOGENTRY *self, unsigned *h_sum);
|
||||||
|
/********************************************************
|
||||||
|
* Get a count of all offenses for this entry.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
216
logFile.c
Normal file
216
logFile.c
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2019 by John D. Robertson *
|
||||||
|
* john@rrci.com *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program 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 *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#include <assert.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <openssl/md5.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "cntry.h"
|
||||||
|
#include "logEntry.h"
|
||||||
|
#include "logFile.h"
|
||||||
|
#include "ez_stdio.h"
|
||||||
|
#include "ez_gzfile.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#define NOFFENSES_CACHED_FLG (1<<0)
|
||||||
|
|
||||||
|
/*==================================================================*/
|
||||||
|
/*=================== LOGFILE ======================================*/
|
||||||
|
/*==================================================================*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
common_constructor(LOGFILE *self)
|
||||||
|
/******************************************************************
|
||||||
|
* common portion for all constructors.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
memset(self, 0, sizeof(*self));
|
||||||
|
MAP_constructor(&self->addr_map, 1000, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGFILE*
|
||||||
|
LOGFILE_cache_constructor(LOGFILE *self, const char *fname)
|
||||||
|
/******************************************************************
|
||||||
|
* Initialize an instance of a LOGFILE class from a cache file.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
LOGFILE *rtn= NULL;
|
||||||
|
|
||||||
|
common_constructor(self);
|
||||||
|
|
||||||
|
FILE *fh= ez_fopen(fname, "r");
|
||||||
|
|
||||||
|
static char buf[256];
|
||||||
|
while(ez_fgets(buf, sizeof(buf), fh)) {
|
||||||
|
LOGENTRY *e;
|
||||||
|
LOGENTRY_cache_create(e, buf);
|
||||||
|
if(!e) goto abort;
|
||||||
|
MAP_addStrKey(&self->addr_map, e->addr, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
rtn= self;
|
||||||
|
|
||||||
|
abort:
|
||||||
|
if(fh) ez_fclose(fh);
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGFILE*
|
||||||
|
LOGFILE_log_constructor(LOGFILE *self, const struct logProtoType *h_protoType, const char *fname)
|
||||||
|
/******************************************************************
|
||||||
|
* Initialize an instance of a LOGFILE from an actual log file.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
LOGFILE *rtn= NULL;
|
||||||
|
|
||||||
|
common_constructor(self);
|
||||||
|
|
||||||
|
static char lbuf[1024];
|
||||||
|
|
||||||
|
/* Open the log file for reading */
|
||||||
|
gzFile fh= ez_gzopen(fname, "r");
|
||||||
|
|
||||||
|
/* Loop through one line at a time */
|
||||||
|
while(ez_gzgets(fh, lbuf, sizeof(lbuf)-1)) {
|
||||||
|
size_t len= strlen(lbuf);
|
||||||
|
/* Get rid of trailing newline, spaces */
|
||||||
|
while(len && isspace(lbuf[len-1]))
|
||||||
|
lbuf[--len]= '\0';
|
||||||
|
|
||||||
|
/* Search for a match in the targets */
|
||||||
|
for(struct target *tg= h_protoType->targetArr; tg->pattern; ++tg) {
|
||||||
|
|
||||||
|
/* If there is no match, continue looking */
|
||||||
|
regmatch_t matchArr[2];
|
||||||
|
if(0 != regexec(&tg->re, lbuf, 2, matchArr, 0) || -1 == matchArr[1].rm_so)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
static char addr[128];
|
||||||
|
unsigned len;
|
||||||
|
len= matchArr[1].rm_eo - matchArr[1].rm_so;
|
||||||
|
strncpy(addr, lbuf+matchArr[1].rm_so, sizeof(addr)-1);
|
||||||
|
addr[MIN(len, sizeof(addr)-1)]= '\0';
|
||||||
|
|
||||||
|
LOGENTRY *e= MAP_findStrItem(&self->addr_map, addr);
|
||||||
|
if(!e) {
|
||||||
|
LOGENTRY_addr_create(e, addr);
|
||||||
|
if(!e) goto abort;
|
||||||
|
|
||||||
|
/* Add to the addr_map */
|
||||||
|
MAP_addStrKey(&self->addr_map, e->addr, e);
|
||||||
|
}
|
||||||
|
LOGENTRY_register(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rtn= self;
|
||||||
|
abort:
|
||||||
|
if(fh) ez_gzclose(fh);
|
||||||
|
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGFILE*
|
||||||
|
LOGFILE_destructor(LOGFILE *self)
|
||||||
|
/******************************************************************
|
||||||
|
* Free resources associated with LOGFILE object.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
if(self->logFilePath)
|
||||||
|
free(self->logFilePath);
|
||||||
|
|
||||||
|
MAP_clearAndDestroy(&self->addr_map, (void*(*)(void*))LOGENTRY_destructor);
|
||||||
|
MAP_destructor(&self->addr_map);
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LOGFILE_set_logFilePath(LOGFILE *self, const char *path)
|
||||||
|
/******************************************************************
|
||||||
|
* Set the log file name by making a copy of the path.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
if(self->logFilePath)
|
||||||
|
free(self->logFilePath);
|
||||||
|
|
||||||
|
self->logFilePath= strdup(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
LOGFILE_writeCache(LOGFILE *self, const char *fname)
|
||||||
|
/******************************************************************
|
||||||
|
* Create a cache file and dump contents of this object.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
int rc, rtn= -1;
|
||||||
|
|
||||||
|
FILE *fh= ez_fopen(fname, "w");
|
||||||
|
rc= MAP_visitAllEntries(&self->addr_map, (int(*)(void*,void*))LOGENTRY_cacheWrite, fh);
|
||||||
|
if(rc) goto abort;
|
||||||
|
|
||||||
|
rtn= 0;
|
||||||
|
abort:
|
||||||
|
if(fh) ez_fclose(fh);
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
LOGFILE_print(LOGFILE *self, FILE *fh)
|
||||||
|
/********************************************************
|
||||||
|
* Print a human readable representation of *self.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
ez_fprintf(fh, "LOGFILE %p \"%s\" {\n", self, self->logFilePath);
|
||||||
|
MAP_visitAllEntries(&self->addr_map, (int(*)(void*,void*))LOGENTRY_print, fh);
|
||||||
|
ez_fprintf(fh, "}\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
LOGFILE_map_addr(LOGFILE *self, MAP *h_rtnMap)
|
||||||
|
/********************************************************
|
||||||
|
* Create a addr_map of LOGENTRY objects with composite
|
||||||
|
* counts by address.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
MAP_visitAllEntries(&self->addr_map, (int(*)(void*,void*))LOGENTRY_map_addr, h_rtnMap);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
LOGFILE_offenseCount(LOGFILE *self, unsigned *h_sum)
|
||||||
|
/********************************************************
|
||||||
|
* Get a count of all offenses for this file.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
if(!(self->flags & NOFFENSES_CACHED_FLG)) {
|
||||||
|
MAP_visitAllEntries(&self->addr_map, (int(*)(void*,void*))LOGENTRY_offenseCount, &self->nOffenses);
|
||||||
|
self->flags |= NOFFENSES_CACHED_FLG;
|
||||||
|
}
|
||||||
|
|
||||||
|
*h_sum += self->nOffenses;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
100
logFile.h
Normal file
100
logFile.h
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2019 by John D. Robertson *
|
||||||
|
* john@rrci.com *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program 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 *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef LOGFILE_H
|
||||||
|
#define LOGFILE_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "logType.h"
|
||||||
|
#include "map.h"
|
||||||
|
|
||||||
|
/* One of these for each log file which is scanned. */
|
||||||
|
typedef struct _LOGFILE {
|
||||||
|
int flags;
|
||||||
|
char *logFilePath;
|
||||||
|
MAP addr_map;
|
||||||
|
unsigned nOffenses;
|
||||||
|
} LOGFILE;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define LOGFILE_cache_create(s, fname) \
|
||||||
|
((s)=(LOGFILE_cache_constructor((s)=malloc(sizeof(LOGFILE)), fname) ? (s) : ( s ? realloc(LOGFILE_destructor(s),0) : 0 )))
|
||||||
|
LOGFILE*
|
||||||
|
LOGFILE_cache_constructor(LOGFILE *self, const char *fname);
|
||||||
|
/******************************************************************
|
||||||
|
* Initialize an instance of a LOGFILE class.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define LOGFILE_log_create(s, h_protoType, fname) \
|
||||||
|
((s)=(LOGFILE_log_constructor((s)=malloc(sizeof(LOGFILE)), h_protoType, fname) ? (s) : ( s ? realloc(LOGFILE_destructor(s),0) : 0 )))
|
||||||
|
LOGFILE*
|
||||||
|
LOGFILE_log_constructor(LOGFILE *self,
|
||||||
|
const struct logProtoType *h_protoType,
|
||||||
|
const char *fname);
|
||||||
|
/******************************************************************
|
||||||
|
* Initialize an instance of a LOGFILE class.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define LOGFILE_destroy(s) \
|
||||||
|
{if(LOGFILE_destructor(s)) {free(s);(s)=0;}}
|
||||||
|
LOGFILE*
|
||||||
|
LOGFILE_destructor(LOGFILE *self);
|
||||||
|
/******************************************************************
|
||||||
|
* Free resources associated with a LOGFILE object.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
LOGFILE_set_logFilePath(LOGFILE *self, const char *path);
|
||||||
|
/******************************************************************
|
||||||
|
* Set the log file name by making a copy of the path.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
LOGFILE_writeCache(LOGFILE *self, const char *fname);
|
||||||
|
/******************************************************************
|
||||||
|
* Create a cache file and dump contents of this object.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
LOGFILE_print(LOGFILE *self, FILE *fh);
|
||||||
|
/********************************************************
|
||||||
|
* Print a human readable representation of *self.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
LOGFILE_map_addr(LOGFILE *self, MAP *h_rtnMap);
|
||||||
|
/********************************************************
|
||||||
|
* Create a map of LOGENTRY objects with composite
|
||||||
|
* counts by address.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
LOGFILE_offenseCount(LOGFILE *self, unsigned *h_sum);
|
||||||
|
/********************************************************
|
||||||
|
* Get a count of all offenses for this file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* LOGFILE_H */
|
382
logType.c
Normal file
382
logType.c
Normal file
@ -0,0 +1,382 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2019 by John D. Robertson *
|
||||||
|
* john@rrci.com *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program 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 *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <openssl/md5.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "ban2fail.h"
|
||||||
|
#include "logFile.h"
|
||||||
|
#include "logType.h"
|
||||||
|
#include "ez_dirent.h"
|
||||||
|
#include "ez_stdio.h"
|
||||||
|
#include "ez_stdlib.h"
|
||||||
|
#include "str.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#define NOFFENSES_CACHED_FLG (1<<0)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define LOGTYPE_proto_create(s, proto) \
|
||||||
|
((s)=(LOGTYPE_proto_constructor((s)=malloc(sizeof(LOGTYPE)), proto) ? (s) : ( s ? realloc(LOGTYPE_destructor(s),0) : 0 )))
|
||||||
|
static LOGTYPE*
|
||||||
|
LOGTYPE_proto_constructor(LOGTYPE *self, const struct logProtoType *proto)
|
||||||
|
/******************************************************************
|
||||||
|
* Initialize an instance of a LOGTYPE class.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
LOGTYPE *rtn= NULL;
|
||||||
|
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
/* Not reentrant! */
|
||||||
|
static char LogFname[PATH_MAX],
|
||||||
|
CacheDname[PATH_MAX],
|
||||||
|
CacheFname[PATH_MAX];
|
||||||
|
|
||||||
|
memset(self, 0, sizeof(*self));
|
||||||
|
|
||||||
|
MAP_constructor(&self->file_map, 10, 10);
|
||||||
|
self->dir= strdup(proto->dir);
|
||||||
|
self->pfix= strdup(proto->pfix);
|
||||||
|
|
||||||
|
size_t pfix_len= strlen(self->pfix);
|
||||||
|
|
||||||
|
{ /* Compute md5sum of all patterns put together */
|
||||||
|
MD5_CTX md5ctx;
|
||||||
|
MD5_Init(&md5ctx);
|
||||||
|
const struct target *t;
|
||||||
|
for(t= proto->targetArr; t->pattern; ++t) {
|
||||||
|
MD5_Update(&md5ctx, t->pattern, strlen(t->pattern));
|
||||||
|
}
|
||||||
|
static unsigned char sum[16];
|
||||||
|
MD5_Final(sum, &md5ctx);
|
||||||
|
const char *str= bytes_2_hexStr(self->patterns_md5sum, sizeof(self->patterns_md5sum), sum, 16);
|
||||||
|
assert(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* At this point we can call LOGTYPE_cacheName() */
|
||||||
|
|
||||||
|
/* Keep the name of this logType's cache directory */
|
||||||
|
rc= snprintf(CacheDname, sizeof(CacheDname), "%s/%s", G.cacheDir, LOGTYPE_cacheName(self));
|
||||||
|
|
||||||
|
{ /*** Compute md5sum for each log file ***/
|
||||||
|
|
||||||
|
/* Open the logfile directory, look for candidate files */
|
||||||
|
DIR *dir= ez_opendir(self->dir);
|
||||||
|
struct dirent *entry;
|
||||||
|
|
||||||
|
while((entry= ez_readdir(dir))) {
|
||||||
|
|
||||||
|
/* Skip uninteresting entries */
|
||||||
|
if(!strcmp(".", entry->d_name) ||
|
||||||
|
!strcmp("..", entry->d_name) ||
|
||||||
|
strncmp(self->pfix, entry->d_name, pfix_len)) continue;
|
||||||
|
|
||||||
|
/* Now compute the checksum */
|
||||||
|
static char buf[1024];
|
||||||
|
MD5_CTX md5ctx;
|
||||||
|
static char sumStr[33];
|
||||||
|
|
||||||
|
MD5_Init(&md5ctx);
|
||||||
|
|
||||||
|
snprintf(LogFname, sizeof(LogFname), "%s/%s", self->dir, entry->d_name);
|
||||||
|
|
||||||
|
|
||||||
|
{ /* Compute the checksum of the log file */
|
||||||
|
|
||||||
|
FILE *fh= ez_fopen(LogFname, "r");
|
||||||
|
int rc;
|
||||||
|
while((rc= ez_fread(buf, 1, sizeof(buf), fh))) {
|
||||||
|
MD5_Update(&md5ctx, buf, rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned char sum[16];
|
||||||
|
MD5_Final(sum, &md5ctx);
|
||||||
|
bytes_2_hexStr(sumStr, sizeof(sumStr), sum, 16);
|
||||||
|
|
||||||
|
ez_fclose(fh);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(G.flags & GLB_PRINT_MASK) {
|
||||||
|
ez_fprintf(stdout, "Scanning \"%s\" ...", LogFname);
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now we have the checksum of the log file */
|
||||||
|
/* See if the cached results exist */
|
||||||
|
rc= snprintf(CacheFname, sizeof(CacheFname), "%s/%s", CacheDname, sumStr);
|
||||||
|
LOGFILE *f;
|
||||||
|
|
||||||
|
if(!access(CacheFname, F_OK)) {
|
||||||
|
|
||||||
|
/* Construct object from cache file */
|
||||||
|
LOGFILE_cache_create(f, CacheFname);
|
||||||
|
assert(f);
|
||||||
|
LOGFILE_set_logFilePath(f, LogFname);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if(access(CacheDname, F_OK)) {
|
||||||
|
ez_mkdir(CacheDname, 0770);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Construct object from log file */
|
||||||
|
LOGFILE_log_create(f, proto, LogFname);
|
||||||
|
assert(f);
|
||||||
|
LOGFILE_set_logFilePath(f, LogFname);
|
||||||
|
if(LOGFILE_writeCache(f, CacheFname))
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
assert(f);
|
||||||
|
|
||||||
|
unsigned nFound= 0;
|
||||||
|
LOGFILE_offenseCount(f, &nFound);
|
||||||
|
|
||||||
|
if(G.flags & GLB_PRINT_MASK) {
|
||||||
|
ez_fprintf(stdout, " found %u offenses\n", nFound);
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
MAP_addStrKey(&self->file_map, sumStr, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
ez_closedir(dir);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
{ /*** clean up unused cache files ***/
|
||||||
|
|
||||||
|
/* Open the cache directory, check each cache file's name against the file_map */
|
||||||
|
DIR *dir= ez_opendir(CacheDname);
|
||||||
|
struct dirent *entry;
|
||||||
|
|
||||||
|
while((entry= ez_readdir(dir))) {
|
||||||
|
|
||||||
|
/* Skip uninteresting entries */
|
||||||
|
if(!strcmp(".", entry->d_name) ||
|
||||||
|
!strcmp("..", entry->d_name)) continue;
|
||||||
|
|
||||||
|
LOGFILE *f= MAP_findStrItem(&self->file_map, entry->d_name);
|
||||||
|
if(f) continue;
|
||||||
|
|
||||||
|
rc= snprintf(CacheFname, sizeof(CacheFname), "%s/%s", CacheDname, entry->d_name);
|
||||||
|
ez_unlink(CacheFname);
|
||||||
|
}
|
||||||
|
|
||||||
|
ez_closedir(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned nFound= 0;
|
||||||
|
LOGTYPE_offenseCount(self, &nFound);
|
||||||
|
|
||||||
|
if(G.flags & GLB_PRINT_MASK) {
|
||||||
|
ez_fprintf(stdout, ">>>> Found %u offenses for %s/%s*\n"
|
||||||
|
, nFound
|
||||||
|
, self->dir
|
||||||
|
, self->pfix
|
||||||
|
);
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
rtn= self;
|
||||||
|
abort:
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
LOGTYPE_init(CFGMAP *h_map, char *pfix)
|
||||||
|
/**************************************************************
|
||||||
|
* Initialize object from configuration map.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
int rtn= -1;
|
||||||
|
|
||||||
|
struct logProtoType proto;
|
||||||
|
memset(&proto, 0, sizeof(proto));
|
||||||
|
|
||||||
|
size_t len= strlen(pfix)+1024;
|
||||||
|
char symBuf[len];
|
||||||
|
unsigned arr_sz= CFGMAP_numTuples(h_map);
|
||||||
|
struct CFGMAP_tuple rtn_arr[arr_sz];
|
||||||
|
|
||||||
|
{ /*--- Check for "dir" symbol ---*/
|
||||||
|
snprintf(symBuf, len, "%s\\DIR", pfix);
|
||||||
|
proto.dir= CFGMAP_find_last_value(h_map, symBuf);
|
||||||
|
|
||||||
|
if(!proto.dir) {
|
||||||
|
eprintf("ERROR: cannot find \"DIR\" entry for LOGTYPE %s", pfix);
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ /*--- Check for "prefix" symbol ---*/
|
||||||
|
snprintf(symBuf, len, "%s\\PREFIX", pfix);
|
||||||
|
proto.pfix= CFGMAP_find_last_value(h_map, symBuf);
|
||||||
|
|
||||||
|
if(!proto.pfix) {
|
||||||
|
eprintf("ERROR: cannot find \"PREFIX\" entry for LOGTYPE %s", pfix);
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ /*--- Get all regex entries ---*/
|
||||||
|
snprintf(symBuf, len, "%s\\REGEX", pfix);
|
||||||
|
|
||||||
|
unsigned nFound= CFGMAP_find_tuples(h_map, rtn_arr, symBuf);
|
||||||
|
|
||||||
|
/* Get enough object to include a terminating entry */
|
||||||
|
struct target targetArr[nFound+1];
|
||||||
|
/* Clear all bits in array */
|
||||||
|
memset(targetArr, 0, sizeof(struct target)*(nFound+1));
|
||||||
|
|
||||||
|
proto.targetArr= targetArr;
|
||||||
|
|
||||||
|
for(unsigned i= 0; i < nFound; ++i) {
|
||||||
|
const struct CFGMAP_tuple *tpl= rtn_arr + i;
|
||||||
|
struct target *tg= targetArr + i;
|
||||||
|
tg->pattern= tpl->value;
|
||||||
|
if(regcomp(&tg->re, tg->pattern, REG_EXTENDED)) {
|
||||||
|
eprintf("ERROR: regex_compile(\"%s\") failed.", tg->pattern);
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create the LOGTYPE object, place in global map */
|
||||||
|
LOGTYPE *obj;
|
||||||
|
LOGTYPE_proto_create(obj, &proto);
|
||||||
|
assert(obj);
|
||||||
|
|
||||||
|
/* Place int the global map */
|
||||||
|
MAP_addStrKey(&G.logType_map, LOGTYPE_cacheName(obj), obj);
|
||||||
|
|
||||||
|
/* Free regex pattern data */
|
||||||
|
for(unsigned i= 0; i < nFound; ++i) {
|
||||||
|
struct target *tg= targetArr + i;
|
||||||
|
regfree(&tg->re);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rtn= 0;
|
||||||
|
abort:
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGTYPE*
|
||||||
|
LOGTYPE_destructor(LOGTYPE *self)
|
||||||
|
/******************************************************************
|
||||||
|
* Free resources associated with LOGTYPE object.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
if(self->dir) free(self->dir);
|
||||||
|
if(self->pfix) free(self->pfix);
|
||||||
|
|
||||||
|
MAP_clearAndDestroy(&self->file_map, (void*(*)(void*))LOGFILE_destructor);
|
||||||
|
MAP_destructor(&self->file_map);
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
LOGTYPE_cacheName(const LOGTYPE *self)
|
||||||
|
/******************************************************************
|
||||||
|
* Return in a static buffer the name of the cache directory which
|
||||||
|
* will hold results for this log type.
|
||||||
|
* Result will take this form:
|
||||||
|
* dir= /var/log
|
||||||
|
* pfix= auth
|
||||||
|
* patterns_md5sum= 71f9514f13bb7acfe4ea2fb0ca2158b7
|
||||||
|
* result= :var:log;auth;71f9514f13bb7acfe4ea2fb0ca2158b7
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
assert(self->dir &&
|
||||||
|
self->pfix &&
|
||||||
|
strlen(self->patterns_md5sum));
|
||||||
|
|
||||||
|
/* Not reentrant! */
|
||||||
|
static STR sb;
|
||||||
|
STR_sinit(&sb, PATH_MAX);
|
||||||
|
|
||||||
|
/* Encode the dir section replacing '/' with ':' */
|
||||||
|
const char *pc;
|
||||||
|
for(pc= self->dir; *pc; ++pc) {
|
||||||
|
if(*pc == '/') {
|
||||||
|
STR_putc(&sb, ':');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
STR_putc(&sb, *pc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Semicolon, the the pfix part */
|
||||||
|
STR_putc(&sb, ';');
|
||||||
|
STR_append(&sb, self->pfix, strlen(self->pfix));
|
||||||
|
/* Semicolon, and the md5sum */
|
||||||
|
STR_putc(&sb, ';');
|
||||||
|
STR_append(&sb, self->patterns_md5sum, strlen(self->patterns_md5sum));
|
||||||
|
/* Return static buffer */
|
||||||
|
return STR_str(&sb);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
LOGTYPE_print(LOGTYPE *self, FILE *fh)
|
||||||
|
/********************************************************
|
||||||
|
* Print a human readable representation of *self.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
ez_fprintf(fh,
|
||||||
|
"LOGTYPE %p { dir= \"%s\", pfix= \"%s\", patterns_md5sum= \"%s\" }\n"
|
||||||
|
, self
|
||||||
|
, self->dir
|
||||||
|
, self->pfix
|
||||||
|
, self->patterns_md5sum
|
||||||
|
);
|
||||||
|
|
||||||
|
MAP_visitAllEntries(&self->file_map, (int(*)(void*,void*))LOGFILE_print, fh);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
LOGTYPE_map_addr(LOGTYPE *self, MAP *h_rtnMap)
|
||||||
|
/********************************************************
|
||||||
|
* Create a map of LOGENTRY objects with composite
|
||||||
|
* counts by address.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
MAP_visitAllEntries(&self->file_map, (int(*)(void*,void*))LOGFILE_map_addr, h_rtnMap);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
LOGTYPE_offenseCount(LOGTYPE *self, unsigned *h_sum)
|
||||||
|
/********************************************************
|
||||||
|
* Get a count of all offenses for this log type.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
if(!(self->flags & NOFFENSES_CACHED_FLG)) {
|
||||||
|
MAP_visitAllEntries(&self->file_map, (int(*)(void*,void*))LOGFILE_offenseCount, &self->nOffenses);
|
||||||
|
self->flags |= NOFFENSES_CACHED_FLG;
|
||||||
|
}
|
||||||
|
*h_sum += self->nOffenses;
|
||||||
|
return 0;
|
||||||
|
}
|
114
logType.h
Normal file
114
logType.h
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2019 by John D. Robertson *
|
||||||
|
* john@rrci.com *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program 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 *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef LOGTYPE_H
|
||||||
|
#define LOGTYPE_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "ban2fail.h"
|
||||||
|
#include "cfgmap.h"
|
||||||
|
#include "map.h"
|
||||||
|
|
||||||
|
/*==================================================================*/
|
||||||
|
/*===================== target =====================================*/
|
||||||
|
/*==================================================================*/
|
||||||
|
struct target {
|
||||||
|
const char *pattern;
|
||||||
|
regex_t re;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*==================================================================*/
|
||||||
|
/*===================== log file prototype =========================*/
|
||||||
|
/*==================================================================*/
|
||||||
|
struct logProtoType {
|
||||||
|
const char *dir,
|
||||||
|
*pfix;
|
||||||
|
struct target *targetArr;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*==================================================================*/
|
||||||
|
/*===================== LOGTYPE ====================================*/
|
||||||
|
/*==================================================================*/
|
||||||
|
/* One of these for each log file type to be scanned */
|
||||||
|
|
||||||
|
typedef struct _LOGTYPE {
|
||||||
|
int flags;
|
||||||
|
char *dir,
|
||||||
|
*pfix,
|
||||||
|
patterns_md5sum[33];
|
||||||
|
MAP file_map;
|
||||||
|
unsigned nOffenses;
|
||||||
|
} LOGTYPE;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int
|
||||||
|
LOGTYPE_init(CFGMAP *h_map, char *pfix);
|
||||||
|
/**************************************************************
|
||||||
|
* Initialize objects from configuration map.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define LOGTYPE_destroy(s) \
|
||||||
|
{if(LOGTYPE_destructor(s)) {free(s);(s)=0;}}
|
||||||
|
LOGTYPE*
|
||||||
|
LOGTYPE_destructor(LOGTYPE *self);
|
||||||
|
/******************************************************************
|
||||||
|
* Free resources associated with a LOGTYPE object.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const char*
|
||||||
|
LOGTYPE_cacheName(const LOGTYPE *self);
|
||||||
|
/******************************************************************
|
||||||
|
* Return in a static buffer the name of the cache directory which
|
||||||
|
* will hold results for this log type.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const char*
|
||||||
|
LOGTYPE_fname_2_cacheName(const char *fname);
|
||||||
|
/******************************************************************
|
||||||
|
* Return in a static buffer the name of the cache directory which
|
||||||
|
* will hold results for the log type indicated by fname.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
LOGTYPE_print(LOGTYPE *self, FILE *fh);
|
||||||
|
/********************************************************
|
||||||
|
* Print a human readable representation of *self.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
LOGTYPE_map_addr(LOGTYPE *self, MAP *h_rtnMap);
|
||||||
|
/********************************************************
|
||||||
|
* Create a map of LOGENTRY objects with composite
|
||||||
|
* counts by address.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
LOGTYPE_offenseCount(LOGTYPE *self, unsigned *h_sum);
|
||||||
|
/********************************************************
|
||||||
|
* Get a count of all offenses for this log type.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* LOGTYPE_H */
|
223
makefile
Normal file
223
makefile
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
baseDir := ~
|
||||||
|
libsDir := $(baseDir)/libs
|
||||||
|
projectName := ban2fail
|
||||||
|
versions := debug release
|
||||||
|
cc_exe := ban2fail
|
||||||
|
install_dir := /usr/local/bin
|
||||||
|
|
||||||
|
|
||||||
|
########################################
|
||||||
|
# Set up sources & libraries here. #
|
||||||
|
########################################
|
||||||
|
|
||||||
|
ifeq ($(exe), ban2fail)
|
||||||
|
src := \
|
||||||
|
ban2fail.c \
|
||||||
|
cfgmap.c \
|
||||||
|
cntry.c \
|
||||||
|
ez_dirent.c \
|
||||||
|
ez_gzfile.c \
|
||||||
|
ez_stdio.c \
|
||||||
|
ez_stdlib.c \
|
||||||
|
iptables.c \
|
||||||
|
logType.c \
|
||||||
|
logEntry.c \
|
||||||
|
logFile.c \
|
||||||
|
map.c \
|
||||||
|
maxoff.c \
|
||||||
|
ptrvec.c \
|
||||||
|
str.c \
|
||||||
|
util.c \
|
||||||
|
|
||||||
|
libs := z crypto GeoIP
|
||||||
|
endif
|
||||||
|
|
||||||
|
########################################
|
||||||
|
# Set up custom compile flags here. #
|
||||||
|
########################################
|
||||||
|
ifeq ($(version),debug)
|
||||||
|
local_cppflags := $(local_cppflags) -D_DEBUG -DDEBUG -std=gnu99
|
||||||
|
local_codeflags := -g2 -O0 -Wreturn-type -Wformat -Wchar-subscripts -Wparentheses -Wcast-qual -Wmissing-declarations
|
||||||
|
local_ldflags := $(local_ldflags) -L$(libsDir)/$(version)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(version),release)
|
||||||
|
local_cppflags := $(local_cppflags) -DNDEBUG -std=gnu99
|
||||||
|
local_codeflags := -g0 -O3 -Wreturn-type -Wformat -Wchar-subscripts -Wparentheses -Wcast-qual -Wmissing-declarations
|
||||||
|
local_ldflags := $(local_ldflags) -L$(libsDir)/$(version)
|
||||||
|
endif
|
||||||
|
|
||||||
|
makefile := makefile
|
||||||
|
ifndef version
|
||||||
|
.PHONY : all clean tidy debug release
|
||||||
|
all : debug release
|
||||||
|
debug :
|
||||||
|
@$(MAKE) version=debug exe=ban2fail mainType=CC --no-builtin-rules -f $(makefile) --no-print-directory
|
||||||
|
release :
|
||||||
|
@$(MAKE) version=release exe=ban2fail mainType=CC --no-builtin-rules -f $(makefile) --no-print-directory
|
||||||
|
install : release
|
||||||
|
@strip release/ban2fail
|
||||||
|
@cp release/ban2fail $(install_dir)/
|
||||||
|
clean :
|
||||||
|
$(RM) -r $(versions) core *.bak *.tab.h *.tab.c *.yy.c *.yy.h
|
||||||
|
tidy :
|
||||||
|
$(RM) $(foreach vs, $(versions), $(vs)/*.o $(vs)/*.d) core *.bak
|
||||||
|
endif
|
||||||
|
.DELETE_ON_ERROR :
|
||||||
|
|
||||||
|
ifdef version
|
||||||
|
roots := \
|
||||||
|
$(patsubst %.cc, %, $(filter %.cc, $(src)))\
|
||||||
|
$(patsubst %.cxx, %, $(filter %.cxx, $(src)))\
|
||||||
|
$(patsubst %.cpp, %, $(filter %.cpp, $(src)))\
|
||||||
|
$(patsubst %.C, %, $(filter %.C, $(src)))\
|
||||||
|
$(patsubst %.c, %, $(filter %.c, $(src)))\
|
||||||
|
$(patsubst %.f, %, $(filter %.f, $(src)))\
|
||||||
|
$(patsubst %.for, %, $(filter %.for, $(src)))\
|
||||||
|
$(patsubst %.sal, %, $(filter %.sal, $(src)))\
|
||||||
|
$(patsubst %.asm, %, $(filter %.asm, $(src)))\
|
||||||
|
$(patsubst %.h, qt_%, $(filter %.h, $(src)))
|
||||||
|
|
||||||
|
yacc_roots := $(patsubst %.y, %.tab, $(filter %.y, $(src)))
|
||||||
|
lex_roots := $(patsubst %.l, %.yy, $(filter %.l, $(src)))
|
||||||
|
obj := $(patsubst %, $(version)/%.o, $(roots) $(yacc_roots) $(lex_roots))
|
||||||
|
dep := $(patsubst %, $(version)/%.d, $(roots) $(yacc_roots) $(lex_roots))
|
||||||
|
|
||||||
|
|
||||||
|
ifdef exe #>>>>>>>>>>>> We are building an executable <<<<<<<<<<<<<<<<
|
||||||
|
|
||||||
|
ifndef mainType
|
||||||
|
$(version)/$(exe) : $(obj)
|
||||||
|
@echo 'THE VARIABLE "mainType" MUST BE DEFINED TO: CXX or CC or FC'
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(mainType),CXX)
|
||||||
|
$(version)/$(exe) : $(obj)
|
||||||
|
$(CXX) $(LDFLAGS) $(local_ldflags) $(obj) $(patsubst %, -l%, $(libs)) -o $@
|
||||||
|
endif # ifeq CXX
|
||||||
|
|
||||||
|
ifeq ($(mainType),CC)
|
||||||
|
$(version)/$(exe) : $(obj)
|
||||||
|
$(CC) $(LDFLAGS) $(local_ldflags) $(obj) $(patsubst %, -l%, $(libs)) -o $@
|
||||||
|
endif # ifeq CC
|
||||||
|
|
||||||
|
ifeq ($(mainType),FC)
|
||||||
|
$(version)/$(exe) : $(obj)
|
||||||
|
$(FC) $(LDFLAGS) $(local_ldflags) $(obj) $(patsubst %, -l%, $(libs)) -o $@
|
||||||
|
endif # ifeq FC
|
||||||
|
endif # ifdef exe
|
||||||
|
|
||||||
|
|
||||||
|
ifdef library #>>>>>>>>>>>> We are building a library <<<<<<<<<<<<<<<<
|
||||||
|
ifeq ($(libType),STATIC)
|
||||||
|
ifdef libsDir
|
||||||
|
$(libsDir)/$(version)/lib$(library).a : $(version)/lib$(library).a
|
||||||
|
@[ -d $(libsDir)/$(version) ] || mkdir -p $(libsDir)/$(version)
|
||||||
|
@ln -f -s `pwd`/$(version)/lib$(library).a $(libsDir)/$(version)/lib$(library).a
|
||||||
|
|
||||||
|
endif # ifdef libsDir
|
||||||
|
|
||||||
|
$(version)/lib$(library).a : $(obj)
|
||||||
|
$(AR) $(ARFLAGS) $@ $(obj)
|
||||||
|
endif # ifeq STATIC
|
||||||
|
|
||||||
|
ifeq ($(libType),SHARED)
|
||||||
|
ifdef libsDir
|
||||||
|
$(libsDir)/$(version)/lib$(library) : $(version)/lib$(library)
|
||||||
|
@[ -d $(libsDir)/$(version) ] || mkdir -p $(libsDir)/$(version)
|
||||||
|
@ln -f -s `pwd`/$(version)/lib$(library) $(libsDir)/$(version)/lib$(library)
|
||||||
|
|
||||||
|
endif # ifdef libsDir
|
||||||
|
$(version)/lib$(library) : $(obj)
|
||||||
|
g++ -shared -Wl,-soname,lib$(library) -o $@ $(obj)
|
||||||
|
|
||||||
|
local_codeflags += -fno-strength-reduce -fPIC
|
||||||
|
endif # ifeq SHARED
|
||||||
|
|
||||||
|
endif # ifdef library
|
||||||
|
#>>>>>>>>>>>>>>>>>>>> Finished library specific stuff <<<<<<<<<<<<<<<<<
|
||||||
|
|
||||||
|
# yacc stuff
|
||||||
|
yacc_h_output := $(patsubst %, %.h, $(yacc_roots))
|
||||||
|
yacc_c_output := $(patsubst %, %.c, $(yacc_roots))
|
||||||
|
yacc_output := $(yacc_h_output) $(yacc_c_output)
|
||||||
|
|
||||||
|
%.tab.c : %.y
|
||||||
|
bison -d $<
|
||||||
|
%.tab.h : %.y
|
||||||
|
bison -d $<
|
||||||
|
|
||||||
|
# lex stuff
|
||||||
|
lex_h_output := $(patsubst %, %.h, $(lex_roots))
|
||||||
|
lex_c_output := $(patsubst %, %.c, $(lex_roots))
|
||||||
|
lex_output := $(lex_h_output) $(lex_c_output)
|
||||||
|
|
||||||
|
%.yy.c: %.l
|
||||||
|
flex -o $*.yy.c --header-file=$*.yy.h $<
|
||||||
|
%.yy.h: %.l
|
||||||
|
flex -o $*.yy.c --header-file=$*.yy.h $<
|
||||||
|
|
||||||
|
# Make sure the build directory exists
|
||||||
|
$(dep) : | $(version)
|
||||||
|
|
||||||
|
$(version) :
|
||||||
|
@mkdir $(version)
|
||||||
|
|
||||||
|
# Dependency files rule
|
||||||
|
$(dep) : $(yacc_output) $(lex_output)
|
||||||
|
|
||||||
|
# Recipes to build .d files
|
||||||
|
$(version)/%.d: %.cc
|
||||||
|
@set -e; $(CXX) -M $(CPPFLAGS) $(local_cppflags) $< \
|
||||||
|
| sed 's/\($*\)\.o[ :]*/$(version)\/\1.o $(version)\/\1.d : /' > $@
|
||||||
|
$(version)/%.d: %.cxx
|
||||||
|
@set -e; $(CXX) -M $(CPPFLAGS) $(local_cppflags) $< \
|
||||||
|
| sed 's/\($*\)\.o[ :]*/$(version)\/\1.o $(version)\/\1.d : /' > $@
|
||||||
|
$(version)/%.d: %.cpp
|
||||||
|
@set -e; $(CXX) -M $(CPPFLAGS) $(local_cppflags) $< \
|
||||||
|
| sed 's/\($*\)\.o[ :]*/$(version)\/\1.o $(version)\/\1.d : /' > $@
|
||||||
|
$(version)/%.d: %.C
|
||||||
|
@set -e; $(CXX) -M $(CPPFLAGS) $(local_cppflags) $< \
|
||||||
|
| sed 's/\($*\)\.o[ :]*/$(version)\/\1.o $(version)\/\1.d : /' > $@
|
||||||
|
$(version)/%.d: %.c
|
||||||
|
@set -e; $(CC) -M $(CPPFLAGS) $(local_cppflags) $< \
|
||||||
|
| sed 's/\($*\)\.o[ :]*/$(version)\/\1.o $(version)\/\1.d : /' > $@
|
||||||
|
|
||||||
|
$(version)/%.d: %.f
|
||||||
|
@echo $(patsubst %.f, $(version)/%.o, $<) : $< > $@
|
||||||
|
|
||||||
|
$(version)/%.d: %.for
|
||||||
|
@echo $(patsubst %.for, $(version)/%.o, $<) : $< > $@
|
||||||
|
|
||||||
|
$(version)/qt_%.d: %.h
|
||||||
|
@echo $(patsubst %.h, $(version)/qt_%.cxx, $<) : $< > $@
|
||||||
|
|
||||||
|
$(version)/%.d: %.sal
|
||||||
|
@echo $(patsubst %.sal, $(version)/%.s, $<) : $< > $@
|
||||||
|
|
||||||
|
$(version)/%.d: %.asm
|
||||||
|
@echo $(patsubst %.asm, $(version)/%.s, $<) : $< > $@
|
||||||
|
|
||||||
|
# The .d files contain specific prerequisite dependencies
|
||||||
|
-include $(patsubst %, $(version)/%.d, $(roots) $(yacc_roots) $(lex_roots))
|
||||||
|
|
||||||
|
# Recipes to build object files
|
||||||
|
$(version)/%.o: %.cc
|
||||||
|
$(CXX) -c $(CXXFLAGS) $(local_codeflags) $(CPPFLAGS) $(local_cppflags) $< -o $@
|
||||||
|
$(version)/%.o: %.cxx
|
||||||
|
$(CXX) -c $(CXXFLAGS) $(local_codeflags) $(CPPFLAGS) $(local_cppflags) $< -o $@
|
||||||
|
$(version)/%.o: %.cpp
|
||||||
|
$(CXX) -c $(CXXFLAGS) $(local_codeflags) $(CPPFLAGS) $(local_cppflags) $< -o $@
|
||||||
|
$(version)/%.o: %.C
|
||||||
|
$(CXX) -c $(CXXFLAGS) $(local_codeflags) $(CPPFLAGS) $(local_cppflags) $< -o $@
|
||||||
|
$(version)/%.o: %.c
|
||||||
|
$(CC) -c $(CCFLAGS) $(local_codeflags) $(CPPFLAGS) $(local_cppflags) $< -o $@
|
||||||
|
$(version)/%.o: %.f
|
||||||
|
$(FC) -c $(FFLAGS) $(local_codeflags) $< -o $@
|
||||||
|
$(version)/%.o: %.for
|
||||||
|
$(FC) -c $(FFLAGS) $(local_codeflags) $< -o $@
|
||||||
|
$(version)/qt_%.o: %.h
|
||||||
|
$(QTDIR)/bin/moc $< -o $(version)/qt_$*.cxx
|
||||||
|
$(CXX) -c $(CXXFLAGS) $(local_codeflags) $(CPPFLAGS) $(local_cppflags) $(version)/qt_$*.cxx -o $(version)/qt_$*.o
|
||||||
|
|
||||||
|
endif # version
|
348
map.c
Normal file
348
map.c
Normal file
@ -0,0 +1,348 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
map.c - description
|
||||||
|
-------------------
|
||||||
|
begin : Thu Jul 12 2001
|
||||||
|
copyright : (C) 2001 by John D. Robertson
|
||||||
|
email : john@rrci.com
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
***************************************************************************/
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "map.h"
|
||||||
|
|
||||||
|
struct MAP_node {
|
||||||
|
unsigned int len;
|
||||||
|
void *item_ptr;
|
||||||
|
/* Key goes here */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Store the variable length key after the 'item_ptr' member of the MAP_node by
|
||||||
|
* malloc()'ing extra memory. This avoids indirection and memory fragmentation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Macro to access the address of the variable length key */
|
||||||
|
#define KEY_PTR(ht_node_ptr)\
|
||||||
|
((void *)(((char *)(ht_node_ptr)) + sizeof(struct MAP_node)))
|
||||||
|
|
||||||
|
static unsigned int
|
||||||
|
hash(const unsigned char *key, unsigned int len)
|
||||||
|
/********************************************************************
|
||||||
|
* Hashing function lifted from http://burtleburtle.net/bob/hash/hashfaq.html
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
unsigned int i, h;
|
||||||
|
|
||||||
|
for(h=0, i=0; i<len; ++i) {
|
||||||
|
h += key[i];
|
||||||
|
h += (h<<10);
|
||||||
|
h ^= (h>>6);
|
||||||
|
}
|
||||||
|
|
||||||
|
h += (h<<3);
|
||||||
|
h ^= (h>>11);
|
||||||
|
h += (h<<15);
|
||||||
|
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MAP *
|
||||||
|
MAP_constructor(MAP *self,
|
||||||
|
unsigned int numBuckets,
|
||||||
|
unsigned int slotsPerBucket)
|
||||||
|
/****************************************************************
|
||||||
|
* Construct a hash table with numBuckets buckets. slotsPerBucket provides
|
||||||
|
* an initial sizing of the buckets, but they can grow dynamically.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
if(!self) return NULL;
|
||||||
|
memset(self, 0, sizeof(*self));
|
||||||
|
|
||||||
|
self->numBuckets= numBuckets;
|
||||||
|
|
||||||
|
/* Get the array of buckets */
|
||||||
|
if(!(self->bucketArr= malloc(numBuckets*sizeof(PTRVEC)))) goto abort;
|
||||||
|
|
||||||
|
/* Initialize each bucket */
|
||||||
|
for(i= 0; i < numBuckets; ++i) {
|
||||||
|
if(!PTRVEC_constructor(self->bucketArr+i, slotsPerBucket)) goto abort;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
abort:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
MAP_sinit(MAP *self,
|
||||||
|
unsigned int numBuckets,
|
||||||
|
unsigned int slotsPerBucket)
|
||||||
|
/***********************************************************
|
||||||
|
* Initialize or clear() for a static instance.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
int rtn= 1;
|
||||||
|
if(!self->bucketArr) {
|
||||||
|
if(!MAP_constructor(self, numBuckets, slotsPerBucket)) goto abort;
|
||||||
|
} else {
|
||||||
|
MAP_clear(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
rtn= 0;
|
||||||
|
abort:
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
MAP_destructor(MAP *self)
|
||||||
|
/****************************************************************/
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
void *ptr;
|
||||||
|
|
||||||
|
for(i= 0; i < self->numBuckets; ++i) {
|
||||||
|
while((ptr= PTRVEC_remHead(self->bucketArr+i))) free(ptr);
|
||||||
|
if(!PTRVEC_destructor(self->bucketArr+i)) return NULL;
|
||||||
|
}
|
||||||
|
free(self->bucketArr);
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
MAP_clearAndDestroy(MAP *self, void *(* destructor)(void *self))
|
||||||
|
/***********************************************************************/
|
||||||
|
{
|
||||||
|
int rtn= 0;
|
||||||
|
unsigned int ndx;
|
||||||
|
struct MAP_node *n_ptr;
|
||||||
|
|
||||||
|
/* Loop through the buckets */
|
||||||
|
for(ndx= 0; ndx < self->numBuckets; ++ndx) {
|
||||||
|
/* For each node in the bucket... */
|
||||||
|
while((n_ptr= PTRVEC_remHead(self->bucketArr+ndx))) {
|
||||||
|
|
||||||
|
/* Call the supplied destructor */
|
||||||
|
if(destructor) {
|
||||||
|
if(!(*destructor)(n_ptr->item_ptr)) rtn= 1;
|
||||||
|
/* Free the item */
|
||||||
|
free(n_ptr->item_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* And the node */
|
||||||
|
free(n_ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
MAP_visitAllEntries(MAP *self, int (* func)(void *item_ptr, void *data), void *data)
|
||||||
|
/******************************************************************************/
|
||||||
|
{
|
||||||
|
unsigned ndx, i;
|
||||||
|
struct MAP_node *n_ptr;
|
||||||
|
|
||||||
|
/* Loop through the buckets */
|
||||||
|
for(ndx= 0; ndx < self->numBuckets; ++ndx) {
|
||||||
|
/* For each node in the bucket... */
|
||||||
|
PTRVEC_loopFwd(self->bucketArr+ndx, i, n_ptr) {
|
||||||
|
/* Call the supplied function */
|
||||||
|
if((*func)(n_ptr->item_ptr, data)) return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned
|
||||||
|
MAP_numItems(MAP *self)
|
||||||
|
/******************************************************************************
|
||||||
|
* Return a count of the items indexed in the hash table.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
unsigned ndx, rtn= 0;
|
||||||
|
|
||||||
|
/* Loop through the buckets */
|
||||||
|
for(ndx= 0; ndx < self->numBuckets; ++ndx) {
|
||||||
|
rtn += PTRVEC_numItems(self->bucketArr+ndx);
|
||||||
|
}
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
MAP_addKey(MAP *self,
|
||||||
|
const void *key_ptr,
|
||||||
|
unsigned int keyLen,
|
||||||
|
void *item_ptr)
|
||||||
|
/***************************************************************************/
|
||||||
|
{
|
||||||
|
struct MAP_node *n_ptr;
|
||||||
|
unsigned int ndx;
|
||||||
|
|
||||||
|
/* Figure out in which bucket to dump it */
|
||||||
|
ndx= hash(key_ptr, keyLen) % self->numBuckets;
|
||||||
|
|
||||||
|
/* malloc() the mode and add it to the node list */
|
||||||
|
if(!(n_ptr= malloc(sizeof(*n_ptr) + keyLen)) ||
|
||||||
|
!PTRVEC_addTail(self->bucketArr+ndx, n_ptr)) return 1;
|
||||||
|
|
||||||
|
/* store pertinant information in the node */
|
||||||
|
n_ptr->len= keyLen;
|
||||||
|
n_ptr->item_ptr= item_ptr;
|
||||||
|
memcpy(KEY_PTR(n_ptr), key_ptr, keyLen);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
MAP_findItems(MAP *self,
|
||||||
|
void* rtnArr[],
|
||||||
|
unsigned int rtnArrSize,
|
||||||
|
const void *key_ptr,
|
||||||
|
unsigned int keyLen)
|
||||||
|
/**********************************************************/
|
||||||
|
{
|
||||||
|
unsigned int ndx, i;
|
||||||
|
int count= 0;
|
||||||
|
struct MAP_node *n_ptr;
|
||||||
|
|
||||||
|
/* Figure out which bucket to search in */
|
||||||
|
ndx= hash(key_ptr, keyLen) % self->numBuckets;
|
||||||
|
|
||||||
|
/* Loop through the bucket looking for a matching key */
|
||||||
|
PTRVEC_loopFwd(self->bucketArr + ndx, i, n_ptr) {
|
||||||
|
/* Compare the keys */
|
||||||
|
if(keyLen == n_ptr->len &&
|
||||||
|
!memcmp(KEY_PTR(n_ptr), key_ptr, keyLen)) {
|
||||||
|
/* Store item_ptr in the return array */
|
||||||
|
if(count == rtnArrSize) return -1;
|
||||||
|
rtnArr[count]= n_ptr->item_ptr;
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct MAP_node *
|
||||||
|
_MAP_findNode(MAP *self,
|
||||||
|
unsigned int *rtnBucketNo_ptr,
|
||||||
|
const void *key_ptr,
|
||||||
|
unsigned int keyLen)
|
||||||
|
/**********************************************************************
|
||||||
|
* Find the node that matches the supplied key.
|
||||||
|
* Return it's pointer, or NULL if it cannot be found.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
unsigned int ndx, i;
|
||||||
|
struct MAP_node *n_ptr;
|
||||||
|
|
||||||
|
/* Figure out which bucket to search in */
|
||||||
|
ndx= hash(key_ptr, keyLen) % self->numBuckets;
|
||||||
|
|
||||||
|
/* Loop through the bucket looking for a matching key */
|
||||||
|
PTRVEC_loopFwd(self->bucketArr + ndx, i, n_ptr) {
|
||||||
|
/* Compare the keys */
|
||||||
|
if(keyLen == n_ptr->len &&
|
||||||
|
!memcmp(KEY_PTR(n_ptr), key_ptr, keyLen)) {
|
||||||
|
*rtnBucketNo_ptr= ndx;
|
||||||
|
return n_ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
MAP_findItem(MAP *self,
|
||||||
|
const void *key_ptr,
|
||||||
|
unsigned int keyLen)
|
||||||
|
/*************************************************************************/
|
||||||
|
{
|
||||||
|
struct MAP_node *n_ptr;
|
||||||
|
unsigned int bucket;
|
||||||
|
|
||||||
|
if(!(n_ptr= _MAP_findNode(self, &bucket, key_ptr, keyLen))) return NULL;
|
||||||
|
return n_ptr->item_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
MAP_removeSpecificItem(MAP *self,
|
||||||
|
const void *key_ptr,
|
||||||
|
unsigned int keyLen,
|
||||||
|
void *pItem)
|
||||||
|
/******************************************************************************
|
||||||
|
* Find the the first matching key and remove it from the hash table.
|
||||||
|
* pItem is the address of the specific item to be removed.
|
||||||
|
* Returns:
|
||||||
|
* NULL Not found
|
||||||
|
* item_ptr first one found
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
unsigned int ndx, i;
|
||||||
|
struct MAP_node *n_ptr;
|
||||||
|
void *rtn= NULL;
|
||||||
|
|
||||||
|
/* Figure out which bucket to search in */
|
||||||
|
ndx= hash(key_ptr, keyLen) % self->numBuckets;
|
||||||
|
|
||||||
|
/* Loop through the bucket looking for a matching key */
|
||||||
|
PTRVEC_loopFwd(self->bucketArr + ndx, i, n_ptr) {
|
||||||
|
/* Compare the keys */
|
||||||
|
if(keyLen == n_ptr->len &&
|
||||||
|
!memcmp(KEY_PTR(n_ptr), key_ptr, keyLen) &&
|
||||||
|
n_ptr->item_ptr == pItem) { /* And compare the item pointer */
|
||||||
|
|
||||||
|
rtn= n_ptr->item_ptr; /* Remember this for return value */
|
||||||
|
free(PTRVEC_remove(self->bucketArr + ndx, n_ptr)); /* Remove entry from this bucket */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
MAP_removeItem(MAP *self,
|
||||||
|
const void *key_ptr,
|
||||||
|
unsigned int keyLen)
|
||||||
|
/******************************************************************************/
|
||||||
|
{
|
||||||
|
struct MAP_node *n_ptr;
|
||||||
|
unsigned int bucket;
|
||||||
|
void *item_ptr;
|
||||||
|
|
||||||
|
if(!(n_ptr= _MAP_findNode(self, &bucket, key_ptr, keyLen))) return NULL;
|
||||||
|
item_ptr= n_ptr->item_ptr;
|
||||||
|
free(PTRVEC_remove(self->bucketArr + bucket, n_ptr));
|
||||||
|
|
||||||
|
return item_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
load_arr(void *item_ptr, void *data)
|
||||||
|
/******************************************************************
|
||||||
|
* lambda function to load all CFG_DICT_ENTRY's into an array.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
void ***ppp= (void***)data;
|
||||||
|
**ppp= item_ptr;
|
||||||
|
++(*ppp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MAP_fetchAllItems(MAP *self, void **rtn_arr)
|
||||||
|
/******************************************************************************
|
||||||
|
* Place the itme pointers into the supplied array.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
MAP_visitAllEntries(self, load_arr, &rtn_arr);
|
||||||
|
}
|
194
map.h
Normal file
194
map.h
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
map.h - description
|
||||||
|
|
||||||
|
Generic hashed map class.
|
||||||
|
-------------------
|
||||||
|
begin : Thu Jul 12 2001
|
||||||
|
copyright : (C) 2001 by John D. Robertson
|
||||||
|
email : john@rrci.com
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef MAP_H
|
||||||
|
#define MAP_H
|
||||||
|
|
||||||
|
#include "ptrvec.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Structure req'd for each map */
|
||||||
|
typedef struct {
|
||||||
|
PTRVEC* bucketArr;
|
||||||
|
unsigned int numBuckets;
|
||||||
|
} MAP;
|
||||||
|
|
||||||
|
/***************** Function prototypes and macros *******************/
|
||||||
|
#define MAP_is_init(s) \
|
||||||
|
((s)->bucketArr)
|
||||||
|
|
||||||
|
MAP*
|
||||||
|
MAP_constructor(MAP *self,
|
||||||
|
unsigned int numBuckets,
|
||||||
|
unsigned int slotsPerBucket);
|
||||||
|
/****************************************************************
|
||||||
|
* Construct a map with numBuckets buckets. slotsPerBucket provides
|
||||||
|
* an initial sizing of the buckets, but they can grow dynamically.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MAP_create(self, numBuckets, slotsPerBucket)\
|
||||||
|
(MAP_constructor((self)=malloc(sizeof(MAP)), numBuckets, slotsPerBucket) ? (self) : ( self ? realloc(MAP_destructor(self),0): 0))
|
||||||
|
/***********************************************************
|
||||||
|
* Same as constructor with the addition of the object being
|
||||||
|
* malloc()'ed for you.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
MAP_sinit(MAP *self,
|
||||||
|
unsigned int numBuckets,
|
||||||
|
unsigned int slotsPerBucket);
|
||||||
|
/***********************************************************
|
||||||
|
* Initialize or clear() for a static instance.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void*
|
||||||
|
MAP_destructor(MAP *self);
|
||||||
|
/************************************************
|
||||||
|
* Free resources associated with object.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MAP_destroy(s)\
|
||||||
|
{if(MAP_destructor(s)) {free(s); (s)=NULL;}}
|
||||||
|
/***********************************************************
|
||||||
|
* Same as destructor with the addition of freeing the object.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
MAP_clearAndDestroy(MAP *self, void *(* destructor)(void *item_ptr));
|
||||||
|
/****************************************************************
|
||||||
|
* Call destructors on all item_ptr's and free() them, and
|
||||||
|
* free() all key records.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MAP_clear(self) \
|
||||||
|
MAP_clearAndDestroy(self, NULL)
|
||||||
|
/****************************************************************
|
||||||
|
* free() all key records.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
MAP_addKey(MAP *self,
|
||||||
|
const void *key_ptr,
|
||||||
|
unsigned int keyLen,
|
||||||
|
void *item_ptr);
|
||||||
|
/*********************************************************************************
|
||||||
|
* Add a key to map, no checking for duplicates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MAP_addTypedKey(self, key, item_ptr) \
|
||||||
|
MAP_addKey(self, &(key), sizeof(key), item_ptr)
|
||||||
|
|
||||||
|
#define MAP_addStrKey(self, keystr, item_ptr) \
|
||||||
|
MAP_addKey(self, keystr, strlen(keystr), item_ptr)
|
||||||
|
|
||||||
|
void*
|
||||||
|
MAP_findItem(MAP *self,
|
||||||
|
const void *key_ptr,
|
||||||
|
unsigned int keyLen);
|
||||||
|
/******************************************************************************
|
||||||
|
* Find the the first matching key and return it's item_ptr.
|
||||||
|
* Returns:
|
||||||
|
* NULL Not found
|
||||||
|
* item_ptr first one found
|
||||||
|
*/
|
||||||
|
#define MAP_findTypedItem(self, key) \
|
||||||
|
MAP_findItem(self, &(key), sizeof(key))
|
||||||
|
|
||||||
|
#define MAP_findStrItem(self, keystr) \
|
||||||
|
MAP_findItem(self, keystr, strlen(keystr))
|
||||||
|
|
||||||
|
void*
|
||||||
|
MAP_removeItem(MAP *self,
|
||||||
|
const void *key_ptr,
|
||||||
|
unsigned int keyLen);
|
||||||
|
/******************************************************************************
|
||||||
|
* Find the the first matching key and remove it from the map.
|
||||||
|
* Returns:
|
||||||
|
* NULL Not found
|
||||||
|
* item_ptr first one found
|
||||||
|
*/
|
||||||
|
#define MAP_removeTypedItem(self, key) \
|
||||||
|
MAP_removeItem(self, &(key), sizeof(key))
|
||||||
|
|
||||||
|
#define MAP_removeStrItem(self, keystr) \
|
||||||
|
MAP_removeItem(self, keystr, strlen(keystr))
|
||||||
|
|
||||||
|
void*
|
||||||
|
MAP_removeSpecificItem(MAP *self,
|
||||||
|
const void *key_ptr,
|
||||||
|
unsigned int keyLen,
|
||||||
|
void *pItem);
|
||||||
|
/******************************************************************************
|
||||||
|
* Find the first matching key and pointer, and remove it from the map.
|
||||||
|
* pItem is the address of the specific item to be removed.
|
||||||
|
* Returns:
|
||||||
|
* NULL Not found
|
||||||
|
* item_ptr first one found
|
||||||
|
*/
|
||||||
|
#define MAP_removeSpecificTypedItem(self, key, pItem) \
|
||||||
|
MAP_removeSpecificItem(self, &(key), sizeof(key), pItem)
|
||||||
|
|
||||||
|
#define MAP_removeSpecificStrItem(self, keystr, pItem) \
|
||||||
|
MAP_removeSpecificItem(self, keystr, strlen(keystr), pItem)
|
||||||
|
|
||||||
|
int
|
||||||
|
MAP_findItems(MAP *self,
|
||||||
|
void* rtnArr[],
|
||||||
|
unsigned int rtnArrSize,
|
||||||
|
const void *key_ptr,
|
||||||
|
unsigned int keyLen);
|
||||||
|
/******************************************************************************
|
||||||
|
* Find all matching key(s) in the map, and put the accompanying item_ptr's
|
||||||
|
* into the rtnArr. Returns:
|
||||||
|
* -1 Insufficient space in rtnArr
|
||||||
|
* 0 .. INT_MAX Number of item_ptr's returned in rtnArr
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MAP_findTypedItems(self, rtnArr, rtnArrSize, key) \
|
||||||
|
MAP_findItems(self, rtnArr, rtnArrSize, &(key), sizeof(key))
|
||||||
|
|
||||||
|
#define MAP_findStrItems(self, rtnArr, rtnArrSize, keystr) \
|
||||||
|
MAP_findItems(self, rtnArr, rtnArrSize, keystr, strlen(keystr))
|
||||||
|
|
||||||
|
int
|
||||||
|
MAP_visitAllEntries(MAP *self, int (* func)(void *item_ptr, void *data), void *data);
|
||||||
|
/******************************************************************************
|
||||||
|
* Visit all entries in the map. if (*func) returns nonzero, then
|
||||||
|
* the process stops and MAP_visitAllEntries will return non-zero.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
MAP_fetchAllItems(MAP *self, void **rtn_arr);
|
||||||
|
/******************************************************************************
|
||||||
|
* Place the item pointers into the supplied array.
|
||||||
|
*/
|
||||||
|
|
||||||
|
unsigned
|
||||||
|
MAP_numItems(MAP *self);
|
||||||
|
/******************************************************************************
|
||||||
|
* Return a count of the items indexed in the map.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
136
maxoff.c
Normal file
136
maxoff.c
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2019 by John D. Robertson *
|
||||||
|
* john@rrci.com *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program 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 *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#include "cntry.h"
|
||||||
|
#include "maxoff.h"
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
int is_init;
|
||||||
|
MAP cntry_map,
|
||||||
|
addr_map;
|
||||||
|
} S;
|
||||||
|
|
||||||
|
static void
|
||||||
|
initialize(void)
|
||||||
|
/********************************************************
|
||||||
|
* Perform one-time initializations.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
S.is_init= 1;
|
||||||
|
MAP_constructor(&S.cntry_map, 10, 10);
|
||||||
|
MAP_constructor(&S.addr_map, 10, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compiler doesn't like that we use integers in place of item pointers */
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wint-conversion"
|
||||||
|
|
||||||
|
int
|
||||||
|
MAXOFF_allowed(const char *addr)
|
||||||
|
/********************************************************
|
||||||
|
* Returns the maximum number of allowed offenses.
|
||||||
|
* -1 means unlimited.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
if(!S.is_init)
|
||||||
|
initialize();
|
||||||
|
|
||||||
|
/* Default is no offenses allowed */
|
||||||
|
int rtn= 0;
|
||||||
|
|
||||||
|
/* Check for by-address specification */
|
||||||
|
rtn= MAP_findStrItem(&S.addr_map, addr);
|
||||||
|
|
||||||
|
/* by-address spec trumps by-country spec */
|
||||||
|
if(!rtn) {
|
||||||
|
const char *cntry;
|
||||||
|
cntry= COUNTRY_get_code(addr);
|
||||||
|
/* if the source country of an address is not known,
|
||||||
|
* then it will be keyed in our map under "unknown".
|
||||||
|
*/
|
||||||
|
cntry= cntry ? cntry : "unknown";
|
||||||
|
rtn= MAP_findStrItem(&S.cntry_map, cntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
MAXOFF_init(CFGMAP *h_map, char *pfix)
|
||||||
|
/**************************************************************
|
||||||
|
* Initialize objects from configuration map.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
if(!S.is_init)
|
||||||
|
initialize();
|
||||||
|
|
||||||
|
int rtn= -1;
|
||||||
|
|
||||||
|
size_t len= strlen(pfix)+1024;
|
||||||
|
char symBuf[len];
|
||||||
|
unsigned arr_sz= CFGMAP_numTuples(h_map);
|
||||||
|
struct CFGMAP_tuple rtn_arr[arr_sz];
|
||||||
|
int nAllowed;
|
||||||
|
|
||||||
|
/* Get the allowed number from pfix */
|
||||||
|
const char *str= strrchr(pfix, '\\');
|
||||||
|
++str;
|
||||||
|
if(1 != sscanf(str, "%d", &nAllowed)) {
|
||||||
|
eprintf("ERROR: \"%s\" is not an integer number.", str);
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
|
||||||
|
{ /*--- Register IP entries ---*/
|
||||||
|
snprintf(symBuf, len, "%s\\IP", pfix);
|
||||||
|
|
||||||
|
unsigned nFound= CFGMAP_find_tuples(h_map, rtn_arr, symBuf);
|
||||||
|
for(unsigned i= 0; i < nFound; ++i) {
|
||||||
|
const struct CFGMAP_tuple *tpl= rtn_arr + i;
|
||||||
|
|
||||||
|
/* Place in the map the number allowed as if it were
|
||||||
|
* a pointer to an object (superflous in this case).
|
||||||
|
*/
|
||||||
|
MAP_addStrKey(&S.addr_map, tpl->value, (void*)nAllowed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ /*--- Register COUNTRY entries ---*/
|
||||||
|
snprintf(symBuf, len, "%s\\COUNTRY", pfix);
|
||||||
|
unsigned nFound= CFGMAP_find_tuples(h_map, rtn_arr, symBuf);
|
||||||
|
|
||||||
|
for(unsigned i= 0; i < nFound; ++i) {
|
||||||
|
const struct CFGMAP_tuple *tpl= rtn_arr + i;
|
||||||
|
|
||||||
|
/* Place in the map the number allowed as if it were
|
||||||
|
* a pointer to an object (superflous in this case).
|
||||||
|
*/
|
||||||
|
MAP_addStrKey(&S.cntry_map, tpl->value, (void*)nAllowed);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rtn= 0;
|
||||||
|
abort:
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
|
47
maxoff.h
Normal file
47
maxoff.h
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2019 by John D. Robertson *
|
||||||
|
* john@rrci.com *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program 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 *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef MAXOFF_H
|
||||||
|
#define MAXOFF_H
|
||||||
|
|
||||||
|
#include "cfgmap.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int
|
||||||
|
MAXOFF_allowed(const char *addr);
|
||||||
|
/********************************************************
|
||||||
|
* Returns the maximum number of allowed offenses.
|
||||||
|
* -1 means unlimited.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
MAXOFF_init(CFGMAP *h_map, char *pfix);
|
||||||
|
/**************************************************************
|
||||||
|
* Initialize objects from configuration map.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
270
ptrvec.c
Normal file
270
ptrvec.c
Normal file
@ -0,0 +1,270 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2008 by John D. Robertson *
|
||||||
|
* john@rrci.com *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program 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 General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "ptrvec.h"
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
grow (PTRVEC * self)
|
||||||
|
{
|
||||||
|
if (PTRVEC_resize (self, self->maxItems * 2))
|
||||||
|
{
|
||||||
|
if (PTRVEC_resize (self, self->maxItems + self->maxItems / 2))
|
||||||
|
{
|
||||||
|
if (PTRVEC_resize (self, self->maxItems + self->maxItems / 4))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
PTRVEC_find (PTRVEC * self, unsigned int *ndxBuf, void *item)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
void *ptr;
|
||||||
|
|
||||||
|
PTRVEC_loopFwd (self, i, ptr)
|
||||||
|
{
|
||||||
|
if (ptr == item)
|
||||||
|
{
|
||||||
|
if(ndxBuf) *ndxBuf = (self->head + i) % self->maxItems;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
PTRVEC_sinit(PTRVEC *self, unsigned initMaxItems)
|
||||||
|
/***********************************************
|
||||||
|
* Static initialization call.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
int rtn= 1;
|
||||||
|
|
||||||
|
if(!(self->ptrArr)) {
|
||||||
|
if(!(PTRVEC_constructor(self, initMaxItems))) goto abort;
|
||||||
|
} else {
|
||||||
|
PTRVEC_reset(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
rtn= 0;
|
||||||
|
abort:
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
PTRVEC *
|
||||||
|
PTRVEC_constructor (PTRVEC * self, unsigned int initMaxItems)
|
||||||
|
{
|
||||||
|
if (!self) return NULL;
|
||||||
|
memset (self, 0, sizeof (*self));
|
||||||
|
if (!(self->ptrArr = malloc (initMaxItems * sizeof (void*)))) return NULL;
|
||||||
|
|
||||||
|
self->maxItems = initMaxItems;
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
PTRVEC_destructor (PTRVEC * self)
|
||||||
|
{
|
||||||
|
if (self->ptrArr) free (self->ptrArr);
|
||||||
|
if(self->sortBuf) free(self->sortBuf);
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
PTRVEC_sort (PTRVEC * self, int (*cmp) (const void *const*, const void *const*))
|
||||||
|
{
|
||||||
|
void *ptr;
|
||||||
|
unsigned int i, sz;
|
||||||
|
unsigned int numItems = self->numItems;;
|
||||||
|
|
||||||
|
/* Nothing to sort */
|
||||||
|
if(!numItems) return 0;
|
||||||
|
|
||||||
|
/* Compute how large the sort buffer needs to be */
|
||||||
|
sz= numItems * sizeof (void *);
|
||||||
|
|
||||||
|
/* If there is no sort buffer, or it isn't big enough, allocate more */
|
||||||
|
if(sz > self->sortBuf_sz) {
|
||||||
|
if(self->sortBuf) free(self->sortBuf);
|
||||||
|
self->sortBuf_sz= 0;
|
||||||
|
if(!(self->sortBuf= malloc(sz))) return 1;
|
||||||
|
self->sortBuf_sz= sz;
|
||||||
|
}
|
||||||
|
// if (!(block = malloc (numItems * sizeof (void *)))) return 1;
|
||||||
|
|
||||||
|
|
||||||
|
PTRVEC_loopFwd (self, i, ptr) self->sortBuf[i] = ptr;
|
||||||
|
PTRVEC_reset (self);
|
||||||
|
|
||||||
|
qsort(self->sortBuf, numItems, sizeof (void *), (int(*)(const void*, const void*))cmp);
|
||||||
|
for (i = 0; i < numItems; i++) {
|
||||||
|
PTRVEC_addTail (self, self->sortBuf[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
PTRVEC_resize (PTRVEC * self, unsigned int maxItems)
|
||||||
|
{
|
||||||
|
unsigned int headSize;
|
||||||
|
void *tmp;
|
||||||
|
|
||||||
|
if (!maxItems)
|
||||||
|
return 0;
|
||||||
|
if (maxItems < self->numItems)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (!(tmp = realloc (self->ptrArr, maxItems * sizeof (void*))))
|
||||||
|
return 1;
|
||||||
|
self->ptrArr = tmp;
|
||||||
|
|
||||||
|
if (self->head > self->tail)
|
||||||
|
{
|
||||||
|
headSize = self->maxItems - self->head;
|
||||||
|
memmove (self->ptrArr + maxItems - headSize,
|
||||||
|
self->ptrArr + self->maxItems - headSize,
|
||||||
|
headSize * sizeof (*self->ptrArr));
|
||||||
|
self->head = maxItems - headSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
self->maxItems = maxItems;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void *
|
||||||
|
PTRVEC_addHead (PTRVEC * self, void *ptr)
|
||||||
|
{
|
||||||
|
if (self->numItems == self->maxItems && grow (self))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (self->numItems)
|
||||||
|
self->head = (self->head + self->maxItems - 1) % self->maxItems;
|
||||||
|
|
||||||
|
self->ptrArr[self->head] = ptr;
|
||||||
|
self->numItems++;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
PTRVEC_remHead (PTRVEC * self)
|
||||||
|
{
|
||||||
|
void *tmp;
|
||||||
|
|
||||||
|
if (!self->numItems)
|
||||||
|
return NULL;
|
||||||
|
self->numItems--;
|
||||||
|
tmp = self->ptrArr[self->head];
|
||||||
|
if (self->numItems)
|
||||||
|
self->head = (self->head + 1) % self->maxItems;
|
||||||
|
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
PTRVEC_addTail (PTRVEC * self, void *ptr)
|
||||||
|
{
|
||||||
|
if (self->numItems == self->maxItems && grow (self))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (self->numItems)
|
||||||
|
self->tail = (self->tail + 1) % self->maxItems;
|
||||||
|
|
||||||
|
self->ptrArr[self->tail] = ptr;
|
||||||
|
self->numItems++;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
PTRVEC_remTail (PTRVEC * self)
|
||||||
|
{
|
||||||
|
void *tmp;
|
||||||
|
|
||||||
|
if (!self->numItems)
|
||||||
|
return NULL;
|
||||||
|
self->numItems--;
|
||||||
|
tmp = self->ptrArr[self->tail];
|
||||||
|
|
||||||
|
if (self->numItems)
|
||||||
|
self->tail = (self->tail + self->maxItems - 1) % self->maxItems;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
PTRVEC_remove (PTRVEC * self, void *item)
|
||||||
|
{
|
||||||
|
unsigned int blockLen;
|
||||||
|
unsigned int ndx;
|
||||||
|
|
||||||
|
if (!PTRVEC_find (self, &ndx, item))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (self->numItems == 1)
|
||||||
|
{
|
||||||
|
self->head = self->tail = 0;
|
||||||
|
}
|
||||||
|
else if (ndx == self->head)
|
||||||
|
{
|
||||||
|
self->head = (self->head + 1) % self->maxItems;
|
||||||
|
}
|
||||||
|
else if (ndx == self->tail)
|
||||||
|
{
|
||||||
|
self->tail = (self->tail + self->maxItems - 1) % self->maxItems;
|
||||||
|
}
|
||||||
|
else if (ndx < self->tail) /* Non contiguous, top block */
|
||||||
|
{
|
||||||
|
blockLen = self->tail - ndx;
|
||||||
|
memmove (self->ptrArr + ndx,
|
||||||
|
self->ptrArr + ndx + 1, blockLen * sizeof (*self->ptrArr));
|
||||||
|
self->tail--;
|
||||||
|
}
|
||||||
|
else /* Contiguous or non contiguous bottom block */
|
||||||
|
{
|
||||||
|
blockLen = ndx - self->head;
|
||||||
|
memmove (self->ptrArr + self->head + 1,
|
||||||
|
self->ptrArr + self->head, blockLen * sizeof (*self->ptrArr));
|
||||||
|
self->head++;
|
||||||
|
}
|
||||||
|
|
||||||
|
self->numItems--;
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
void
|
||||||
|
PTRVEC_assert_integrity(PTRVEC *self)
|
||||||
|
{
|
||||||
|
char *p, val;
|
||||||
|
unsigned i;
|
||||||
|
PTRVEC_loopFwd(self, i, p) {
|
||||||
|
val= *p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
213
ptrvec.h
Normal file
213
ptrvec.h
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2008 by John D. Robertson *
|
||||||
|
* john@rrci.com *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program 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 General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef PTRVEC_H
|
||||||
|
#define PTRVEC_H
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
void **ptrArr;
|
||||||
|
unsigned int maxItems, numItems, head, tail;
|
||||||
|
|
||||||
|
void **sortBuf;
|
||||||
|
unsigned sortBuf_sz;
|
||||||
|
}
|
||||||
|
PTRVEC;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define PTRVEC_arr(self) \
|
||||||
|
((self)->ptrArr)
|
||||||
|
|
||||||
|
#define PTRVEC_is_init(self) \
|
||||||
|
PTRVEC_arr(self)
|
||||||
|
|
||||||
|
int
|
||||||
|
PTRVEC_sinit(PTRVEC *self, unsigned initMaxItems);
|
||||||
|
/***********************************************
|
||||||
|
* Static initialization call.
|
||||||
|
*/
|
||||||
|
|
||||||
|
PTRVEC *PTRVEC_constructor (PTRVEC * self, unsigned int initMaxItems);
|
||||||
|
/***********************************************
|
||||||
|
* Construct a PTRVEC.
|
||||||
|
*
|
||||||
|
* initMaxItems - a guess at how many items it will need to hold.
|
||||||
|
* returns - pointer to the object, or NULL for failure.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define PTRVEC_create(p, initMaxItems) \
|
||||||
|
((p)=(PTRVEC_constructor((p)=malloc(sizeof(PTRVEC)), initMaxItems) ? (p) : ( p ? realloc(PTRVEC_destructor(p),0) : 0 )))
|
||||||
|
|
||||||
|
void *PTRVEC_destructor (PTRVEC * self);
|
||||||
|
/***********************************************
|
||||||
|
* Destruct a PTRVEC.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define PTRVEC_destroy(self) \
|
||||||
|
{if(PTRVEC_destructor(s)) {free(s);}}
|
||||||
|
|
||||||
|
void *PTRVEC_addHead (PTRVEC * self, void *ptr);
|
||||||
|
/***********************************************
|
||||||
|
* Add an item to the head of the 'list'.
|
||||||
|
*
|
||||||
|
* ptr - pointer to the item to add.
|
||||||
|
* returns - pointer to the node added, or NULL for failure.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void *PTRVEC_remHead (PTRVEC * self);
|
||||||
|
/************************************************
|
||||||
|
* Remove an item from the head of the 'list'.
|
||||||
|
*
|
||||||
|
* returns - pointer to the item, or NULL if the 'list' is emtpy.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void *PTRVEC_addTail (PTRVEC * self, void *ptr);
|
||||||
|
/***********************************************
|
||||||
|
* Add an item to the tail of the 'list'.
|
||||||
|
*
|
||||||
|
* ptr - pointer to the item to add.
|
||||||
|
* returns - pointer to the node added, or NULL for failure.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void *PTRVEC_remTail (PTRVEC * self);
|
||||||
|
/************************************************
|
||||||
|
* Remove an item from the tail of the 'list'.
|
||||||
|
*
|
||||||
|
* returns - pointer to the item, or NULL if the 'list' is emtpy.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int PTRVEC_resize (PTRVEC * self, unsigned int maxItems);
|
||||||
|
/************************************************
|
||||||
|
* Resize the vector. This is normally done automatically
|
||||||
|
* for you.
|
||||||
|
*
|
||||||
|
* maxItems - the new number of items to use in the list.
|
||||||
|
* returns - nonzero if there is not enough memory, or if maxItems < self->numItems.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int PTRVEC_sort (PTRVEC * self, int (*cmp) (const void *const*, const void *const*));
|
||||||
|
/************************************************
|
||||||
|
* Use qsort() to sort the items in the vector according to the cmp function.
|
||||||
|
*
|
||||||
|
* cmp - function pointer to use for comparison.
|
||||||
|
* returns - nonzero for failure (not enough memory for temporary block)
|
||||||
|
*/
|
||||||
|
|
||||||
|
int PTRVEC_find (PTRVEC * self, unsigned int *ndxBuf, void *item);
|
||||||
|
/************************************************
|
||||||
|
* Searches for an item. If found, returns 0 and writes index number of
|
||||||
|
* item into ndxBuf. if ndxBuf is not NULL.
|
||||||
|
* returns 1 if found, 0 if not found.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void *PTRVEC_remove (PTRVEC * self, void *item);
|
||||||
|
/***************************************************
|
||||||
|
* Remove an item from the PTRVEC.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
void
|
||||||
|
PTRVEC_assert_integrity(PTRVEC *self);
|
||||||
|
/***************************************************
|
||||||
|
* Perform internal integrity checks for corruption.
|
||||||
|
*/
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define PTRVEC_reset(self) \
|
||||||
|
(self)->numItems= (self)->head= (self)->tail= 0
|
||||||
|
/************************************************
|
||||||
|
* void PTRVEC_reset(PTRVEC *self);
|
||||||
|
* Reset the 'list' to contain no items.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define PTRVEC_numItems(self) \
|
||||||
|
(self)->numItems
|
||||||
|
/************************************************
|
||||||
|
* unsigned int PTRVEC_numItems(PTRVEC *self);
|
||||||
|
*
|
||||||
|
* Return the number of items in the 'list'.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define PTRVEC_ndxPtr(self, ndx) \
|
||||||
|
(ndx>=(self)->numItems?0:(self)->ptrArr[((self)->head+ndx)%(self)->maxItems])
|
||||||
|
/*************************************************
|
||||||
|
* void *PTRVEC_ndxPtr(PTRVEC *self, unsigned int ndx);
|
||||||
|
*
|
||||||
|
* get a pointer given it's position in the 'array'.
|
||||||
|
*
|
||||||
|
* ndx - index of the position in the 'array'
|
||||||
|
* returns - pointer, or NULL if the ndx is invalid
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define PTRVEC_first(self) \
|
||||||
|
((self)->numItems?(self)->ptrArr[(self)->head]:0)
|
||||||
|
/*******************************************************
|
||||||
|
* void *PTRVEC_first(PTRVEC *self);
|
||||||
|
* gets the first pointer in the vector.
|
||||||
|
*
|
||||||
|
* returns - pointer to the first item, or NULL if the vector is emtpy.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define PTRVEC_last(self) \
|
||||||
|
((self)->numItems?(self)->ptrArr[(self)->tail]:0)
|
||||||
|
/*******************************************************
|
||||||
|
* void *PTRVEC_last(PTRVEC *self);
|
||||||
|
* gets the last pointer in the vector.
|
||||||
|
*
|
||||||
|
* returns - pointer to the last item, or NULL if the vector is emtpy.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
|
||||||
|
/* Macros for traversing vector in list like fashion */
|
||||||
|
#define PTRVEC_loopFwd(self, i, ptr) \
|
||||||
|
for(i=0, ptr= (decltype(ptr))(self)->ptrArr[(self)->head];\
|
||||||
|
i < (self)->numItems;\
|
||||||
|
++i, ptr= (decltype(ptr))(self)->ptrArr[((self)->head+i)%(self)->maxItems])
|
||||||
|
|
||||||
|
#define PTRVEC_loopBkwd(self, i, ptr) \
|
||||||
|
for(i=0, ptr= (decltype(ptr))(self)->ptrArr[(self)->tail];\
|
||||||
|
i < (self)->numItems;\
|
||||||
|
++i, ptr= (decltype(ptr))(self)->ptrArr[((self)->tail+(self)->maxItems-i)%(self)->maxItems])
|
||||||
|
#else
|
||||||
|
|
||||||
|
/* Macros for traversing vector in list like fashion */
|
||||||
|
#define PTRVEC_loopFwd(self, i, ptr) \
|
||||||
|
for(i=0, ptr= (typeof(ptr))(self)->ptrArr[(self)->head];\
|
||||||
|
i < (self)->numItems;\
|
||||||
|
++i, ptr= (typeof(ptr))(self)->ptrArr[((self)->head+i)%(self)->maxItems])
|
||||||
|
|
||||||
|
#define PTRVEC_loopBkwd(self, i, ptr) \
|
||||||
|
for(i=0, ptr= (typeof(ptr))(self)->ptrArr[(self)->tail];\
|
||||||
|
i < (self)->numItems;\
|
||||||
|
++i, ptr= (typeof(ptr))(self)->ptrArr[((self)->tail+(self)->maxItems-i)%(self)->maxItems])
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
537
str.c
Normal file
537
str.c
Normal file
@ -0,0 +1,537 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2019 by John D. Robertson *
|
||||||
|
* john@rrci.com *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program 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 *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#include <assert.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "str.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
STR_sinit(STR *self, size_t sz_hint)
|
||||||
|
/**********************************************************************************
|
||||||
|
* Initialization to be called for static instances of STR each use, but
|
||||||
|
* actual initialization only occurs once.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
int rtn= 1;
|
||||||
|
if(!self->buf) {
|
||||||
|
if(!STR_constructor(self, sz_hint)) goto abort;
|
||||||
|
} else {
|
||||||
|
STR_reset(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
rtn= 0;
|
||||||
|
abort:
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
STR*
|
||||||
|
STR_constructor(STR *self, size_t sz_hint)
|
||||||
|
/**********************************************************************************
|
||||||
|
* Prepare a STR for use with initial size of sz_hint.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
STR *rtn= NULL;
|
||||||
|
|
||||||
|
assert(sz_hint);
|
||||||
|
|
||||||
|
self->sz= sz_hint;
|
||||||
|
if(!(self->buf= malloc(self->sz))) goto abort;
|
||||||
|
STR_reset(self);
|
||||||
|
|
||||||
|
rtn= self;
|
||||||
|
|
||||||
|
abort:
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
STR_destructor(STR *self)
|
||||||
|
/**********************************************************************************
|
||||||
|
* Free resources associated with STR.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
if(self->buf) free(self->buf);
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
growbuf(STR *self)
|
||||||
|
/**********************************************************************************
|
||||||
|
* Attempt to increase the size buffer initially trying to double it, then
|
||||||
|
* backing off 10% at a time.
|
||||||
|
* Returns non-zero for error.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
int rtn= 1;
|
||||||
|
size_t i;
|
||||||
|
/* Initially try do double memory. If that fails, back off 10% at a time */
|
||||||
|
for(i= 20; i > 10; i--) {
|
||||||
|
char *p;
|
||||||
|
size_t new_sz= self->sz * i / 10;
|
||||||
|
/* Try to reallocate the memory */
|
||||||
|
if(!(p= realloc(self->buf, new_sz))) continue;
|
||||||
|
/* Try vsnprintf() again */
|
||||||
|
self->buf= p;
|
||||||
|
self->sz = new_sz;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(i != 10) rtn= 0; /* Not success if we grew the buffer */
|
||||||
|
|
||||||
|
abort:
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
STR_sprintf(STR *self, const char *fmt, ...)
|
||||||
|
/**********************************************************************************
|
||||||
|
* Same as sprintf, except you don't have to worry about buffer overflows.
|
||||||
|
* Returns non-zero for error.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
int is_done, rtn= -1;
|
||||||
|
va_list arglist;
|
||||||
|
|
||||||
|
/* Catch empty strings */
|
||||||
|
if(!strlen(fmt)) return 0;
|
||||||
|
|
||||||
|
/* vsprintf the fmt string */
|
||||||
|
for(is_done= 0; !is_done;) {
|
||||||
|
int rc;
|
||||||
|
va_start (arglist, fmt);
|
||||||
|
rc= vsnprintf(self->buf+self->len, self->sz - self->len, fmt, arglist);
|
||||||
|
if(rc >= (self->sz - self->len)) { /* Buffer isn't large enough */
|
||||||
|
if(growbuf(self)) is_done= 1;
|
||||||
|
} else {
|
||||||
|
if(rc != -1) { /* Successful return */
|
||||||
|
rtn= rc;
|
||||||
|
self->len += rc;
|
||||||
|
}
|
||||||
|
is_done= 1;
|
||||||
|
}
|
||||||
|
va_end (arglist);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
STR_vsprintf(STR *self, const char *fmt, va_list ap)
|
||||||
|
/**********************************************************************************
|
||||||
|
* Same as vsprintf, except you don't have to worry about buffer overflows.
|
||||||
|
* Returns non-zero for error.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
int is_done, rtn= -1;
|
||||||
|
|
||||||
|
/* Catch empty strings */
|
||||||
|
if(!strlen(fmt)) return 0;
|
||||||
|
|
||||||
|
/* vsprintf the fmt string */
|
||||||
|
for(is_done= 0; !is_done;) {
|
||||||
|
int rc;
|
||||||
|
va_list arglist;
|
||||||
|
#if __GNUC__ == 2
|
||||||
|
arglist= ap;
|
||||||
|
#else
|
||||||
|
va_copy(arglist, ap);
|
||||||
|
#endif
|
||||||
|
rc= vsnprintf(self->buf+self->len, self->sz - self->len, fmt, arglist);
|
||||||
|
if(rc >= (self->sz - self->len)) { /* Buffer isn't large enough */
|
||||||
|
if(growbuf(self)) is_done= 1;
|
||||||
|
} else {
|
||||||
|
if(rc != -1) { /* Successful return */
|
||||||
|
rtn= rc;
|
||||||
|
self->len += rc;
|
||||||
|
}
|
||||||
|
is_done= 1;
|
||||||
|
}
|
||||||
|
va_end (arglist);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
STR_append(STR *self, const char *str, size_t str_len)
|
||||||
|
/**********************************************************************************
|
||||||
|
* Append string str to the end of the current buffer.
|
||||||
|
* Returns -1 for error.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
if(str_len == -1) str_len= strlen(str);
|
||||||
|
|
||||||
|
/* Make sure there is enough space to store the string */
|
||||||
|
while(self->len + str_len + 1 >= self->sz) {
|
||||||
|
if(growbuf(self)) return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the string into place */
|
||||||
|
memcpy(self->buf + self->len, str, str_len);
|
||||||
|
/* Update length */
|
||||||
|
self->len += str_len;
|
||||||
|
/* Null terminate string */
|
||||||
|
self->buf[self->len] = '\0';
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
STR_putc(STR *self, int c)
|
||||||
|
/**********************************************************************************
|
||||||
|
* Append a single character to the end of the current buffer.
|
||||||
|
* Returns -1 for error.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
/* Make sure there is enough space to store the string */
|
||||||
|
while(self->len + 1 >= self->sz) {
|
||||||
|
if(growbuf(self)) return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the character into place */
|
||||||
|
self->buf[self->len]= c;
|
||||||
|
/* Update length */
|
||||||
|
++self->len;
|
||||||
|
/* Null terminate string */
|
||||||
|
self->buf[self->len] = '\0';
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
STR_tolower(STR *self)
|
||||||
|
/**********************************************************************************
|
||||||
|
* Convert all characters in buffer to lower case.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
char *c;
|
||||||
|
for(c= self->buf; *c; ++c) {
|
||||||
|
*c= tolower(*c);
|
||||||
|
}
|
||||||
|
return self->buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
STR_XMLencode(STR *self, const char *src)
|
||||||
|
/**************************************************************
|
||||||
|
* encode the src string for XML into self. Return self's buffer.
|
||||||
|
* NOTE: self does not get reset!
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
const char *c;
|
||||||
|
if(!src) return "";
|
||||||
|
|
||||||
|
for(c= src; *c; ++c) {
|
||||||
|
|
||||||
|
const char *str= NULL;
|
||||||
|
unsigned len= 0;
|
||||||
|
|
||||||
|
|
||||||
|
switch(*c) {
|
||||||
|
|
||||||
|
#define doit(litstr) \
|
||||||
|
len= strlen(litstr); str= litstr
|
||||||
|
|
||||||
|
case '"': doit("""); break;
|
||||||
|
case '\'': doit("'"); break;
|
||||||
|
case '<': doit("<"); break;
|
||||||
|
case '>': doit(">"); break;
|
||||||
|
case '&': doit("&"); break;
|
||||||
|
#undef doit
|
||||||
|
}
|
||||||
|
|
||||||
|
if(str) { // Special string was assigned
|
||||||
|
STR_append(self, str, len);
|
||||||
|
} else {
|
||||||
|
STR_putc(self, *c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return STR_str(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
STR_URLencode(STR *self, const char *src)
|
||||||
|
/**************************************************************
|
||||||
|
* encode the src string for URL into self. Return self's buffer.
|
||||||
|
* NOTE: self does not get reset!
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
const char *c;
|
||||||
|
if(!src) return "";
|
||||||
|
|
||||||
|
for(c= src; *c; ++c) {
|
||||||
|
|
||||||
|
const char *str= NULL;
|
||||||
|
switch(*c) {
|
||||||
|
case '!': str= "%21"; break;
|
||||||
|
case '#': str= "%23"; break;
|
||||||
|
case '$': str= "%24"; break;
|
||||||
|
case '&': str= "%26"; break;
|
||||||
|
case '\'': str= "%27"; break;
|
||||||
|
case '(': str= "%28"; break;
|
||||||
|
case ')': str= "%29"; break;
|
||||||
|
case '*': str= "%2A"; break;
|
||||||
|
case '+': str= "%2B"; break;
|
||||||
|
case ',': str= "%2C"; break;
|
||||||
|
// case '/': str= "%2F"; break;
|
||||||
|
case ':': str= "%3A"; break;
|
||||||
|
case ';': str= "%3B"; break;
|
||||||
|
case '=': str= "%3D"; break;
|
||||||
|
case '?': str= "%3F"; break;
|
||||||
|
case '@': str= "%40"; break;
|
||||||
|
case '[': str= "%5B"; break;
|
||||||
|
case ']': str= "%5D"; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(str) { // Special string was assigned
|
||||||
|
STR_append(self, str, 3);
|
||||||
|
} else {
|
||||||
|
STR_putc(self, *c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return STR_str(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
STR_utf8toHTML(STR *self, const char *src)
|
||||||
|
/**************************************************************
|
||||||
|
* place the HTML representation of the utf-8 src string into self.
|
||||||
|
* Return self's buffer.
|
||||||
|
* NOTE: self does not get reset!
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
const unsigned char *c;
|
||||||
|
unsigned code= '?';
|
||||||
|
if(!src) return "";
|
||||||
|
|
||||||
|
for(c= (const unsigned char*)src; *c; ++c) {
|
||||||
|
|
||||||
|
/******* Map UTF-8 to a code point **********/
|
||||||
|
|
||||||
|
if(0xF0 == (*c & 0xF8)) { // first of four bytes
|
||||||
|
|
||||||
|
/* Make sure the string doesn't end too soon */
|
||||||
|
assert(c[1] && c[2] && c[3]);
|
||||||
|
|
||||||
|
code= (*c & ~0xF8) << 18;
|
||||||
|
++c;
|
||||||
|
code |= (*c & ~0xC0) << 12;
|
||||||
|
++c;
|
||||||
|
code |= (*c & ~0xC0) << 6;
|
||||||
|
++c;
|
||||||
|
code |= (*c & ~0xC0);
|
||||||
|
|
||||||
|
} else if(0xE0 == (*c & 0xF0)) { // first of three bytes
|
||||||
|
|
||||||
|
/* Make sure the string doesn't end too soon */
|
||||||
|
assert(c[1] && c[2]);
|
||||||
|
|
||||||
|
code= (*c & ~0xF0) << 12;
|
||||||
|
++c;
|
||||||
|
code |= (*c & ~0xC0) << 6;
|
||||||
|
++c;
|
||||||
|
code |= (*c & ~0xC0);
|
||||||
|
|
||||||
|
} else if(0xC0 == (*c & 0xE0)) { // first of two bytes
|
||||||
|
|
||||||
|
/* Make sure the string doesn't end too soon */
|
||||||
|
assert(c[1]);
|
||||||
|
code= (*c & ~0xE0) << 6;
|
||||||
|
++c;
|
||||||
|
code |= (*c & ~0xC0);
|
||||||
|
|
||||||
|
} else if(0 == (*c & 0x80)) {// first of one byte
|
||||||
|
|
||||||
|
code= *c;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/************** Assign HTML special string if one is defined **********/
|
||||||
|
const char *str= NULL;
|
||||||
|
unsigned len= 0;
|
||||||
|
|
||||||
|
switch(code) {
|
||||||
|
|
||||||
|
#define doit(litstr) \
|
||||||
|
len= strlen(litstr); str= litstr
|
||||||
|
|
||||||
|
case '"': doit("""); break;
|
||||||
|
case '<': doit("<"); break;
|
||||||
|
case '>': doit(">"); break;
|
||||||
|
case '&': doit("&"); break;
|
||||||
|
case 160: doit(" "); break;
|
||||||
|
case 161: doit("¡"); break;
|
||||||
|
case 162: doit("¢"); break;
|
||||||
|
case 163: doit("£"); break;
|
||||||
|
case 164: doit("¤"); break;
|
||||||
|
case 165: doit("¥"); break;
|
||||||
|
case 166: doit("¦"); break;
|
||||||
|
case 167: doit("§"); break;
|
||||||
|
case 168: doit("¨"); break;
|
||||||
|
case 169: doit("©"); break;
|
||||||
|
case 170: doit("ª"); break;
|
||||||
|
case 171: doit("«"); break;
|
||||||
|
case 172: doit("¬"); break;
|
||||||
|
case 173: doit("­"); break;
|
||||||
|
case 174: doit("®"); break;
|
||||||
|
case 175: doit("¯"); break;
|
||||||
|
case 176: doit("°"); break;
|
||||||
|
case 177: doit("±"); break;
|
||||||
|
case 178: doit("²"); break;
|
||||||
|
case 179: doit("³"); break;
|
||||||
|
case 180: doit("´"); break;
|
||||||
|
case 181: doit("µ"); break;
|
||||||
|
case 182: doit("¶"); break;
|
||||||
|
case 183: doit("·"); break;
|
||||||
|
case 184: doit("¸"); break;
|
||||||
|
case 185: doit("¹"); break;
|
||||||
|
case 186: doit("º"); break;
|
||||||
|
case 187: doit("»"); break;
|
||||||
|
case 188: doit("¼"); break;
|
||||||
|
case 189: doit("½"); break;
|
||||||
|
case 190: doit("¾"); break;
|
||||||
|
case 191: doit("¿"); break;
|
||||||
|
case 192: doit("À"); break;
|
||||||
|
case 193: doit("Á"); break;
|
||||||
|
case 194: doit("Â"); break;
|
||||||
|
case 195: doit("Ã"); break;
|
||||||
|
case 196: doit("Ä"); break;
|
||||||
|
case 197: doit("Å"); break;
|
||||||
|
case 198: doit("Æ"); break;
|
||||||
|
case 199: doit("Ç"); break;
|
||||||
|
case 200: doit("È"); break;
|
||||||
|
case 201: doit("É"); break;
|
||||||
|
case 202: doit("Ê"); break;
|
||||||
|
case 203: doit("Ë"); break;
|
||||||
|
case 204: doit("Ì"); break;
|
||||||
|
case 205: doit("Í"); break;
|
||||||
|
case 206: doit("Î"); break;
|
||||||
|
case 207: doit("Ï"); break;
|
||||||
|
case 208: doit("Ð"); break;
|
||||||
|
case 209: doit("Ñ"); break;
|
||||||
|
case 210: doit("Ò"); break;
|
||||||
|
case 211: doit("Ó"); break;
|
||||||
|
case 212: doit("Ô"); break;
|
||||||
|
case 213: doit("Õ"); break;
|
||||||
|
case 214: doit("Ö"); break;
|
||||||
|
case 215: doit("×"); break;
|
||||||
|
case 216: doit("Ø"); break;
|
||||||
|
case 217: doit("Ù"); break;
|
||||||
|
case 218: doit("Ú"); break;
|
||||||
|
case 219: doit("Û"); break;
|
||||||
|
case 220: doit("Ü"); break;
|
||||||
|
case 221: doit("Ý"); break;
|
||||||
|
case 222: doit("Þ"); break;
|
||||||
|
case 223: doit("ß"); break;
|
||||||
|
case 224: doit("à"); break;
|
||||||
|
case 225: doit("á"); break;
|
||||||
|
case 226: doit("â"); break;
|
||||||
|
case 227: doit("ã"); break;
|
||||||
|
case 228: doit("ä"); break;
|
||||||
|
case 229: doit("å"); break;
|
||||||
|
case 230: doit("æ"); break;
|
||||||
|
case 231: doit("ç"); break;
|
||||||
|
case 232: doit("è"); break;
|
||||||
|
case 233: doit("é"); break;
|
||||||
|
case 234: doit("ê"); break;
|
||||||
|
case 235: doit("ë"); break;
|
||||||
|
case 236: doit("ì"); break;
|
||||||
|
case 237: doit("í"); break;
|
||||||
|
case 238: doit("î"); break;
|
||||||
|
case 239: doit("ï"); break;
|
||||||
|
case 240: doit("ð"); break;
|
||||||
|
case 241: doit("ñ"); break;
|
||||||
|
case 242: doit("ò"); break;
|
||||||
|
case 243: doit("ó"); break;
|
||||||
|
case 244: doit("ô"); break;
|
||||||
|
case 245: doit("õ"); break;
|
||||||
|
case 246: doit("ö"); break;
|
||||||
|
case 247: doit("÷"); break;
|
||||||
|
case 248: doit("ø"); break;
|
||||||
|
case 249: doit("ù"); break;
|
||||||
|
case 250: doit("ú"); break;
|
||||||
|
case 251: doit("û"); break;
|
||||||
|
case 252: doit("ü"); break;
|
||||||
|
case 253: doit("ý"); break;
|
||||||
|
case 254: doit("þ"); break;
|
||||||
|
case 255: doit("ÿ"); break;
|
||||||
|
case 8364: doit("€"); break;
|
||||||
|
#undef doit
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/****** Place final representation into our string buffer ******/
|
||||||
|
if(str) { // Special string was assigned
|
||||||
|
|
||||||
|
STR_append(self, str, len);
|
||||||
|
|
||||||
|
} else if(code < 128 && isprint(code)) { // Normal ASCII character
|
||||||
|
|
||||||
|
STR_putc(self, code);
|
||||||
|
|
||||||
|
} else if(65533 == code) {
|
||||||
|
|
||||||
|
// This is the placeholder for unrecognized characters
|
||||||
|
|
||||||
|
} else { // All others
|
||||||
|
|
||||||
|
STR_sprintf(self, "&#%u;", code);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return STR_str(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
STR_escapeJSONstr(STR *self, const char *src)
|
||||||
|
/**************************************************************
|
||||||
|
* Escape any characters such the src can be used in a JSON
|
||||||
|
* string.
|
||||||
|
* Return self's buffer.
|
||||||
|
* NOTE: self does not get reset!
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
const char *pc;
|
||||||
|
for(pc= src; *pc; ++pc) {
|
||||||
|
switch(*pc) {
|
||||||
|
case '\\':
|
||||||
|
STR_sprintf(self, "\\\\");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '"':
|
||||||
|
STR_sprintf(self, "\\\"");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if(iscntrl(*pc)) {
|
||||||
|
STR_sprintf(self, "\\u%4X", (int)(*pc));
|
||||||
|
} else {
|
||||||
|
STR_putc(self, *pc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return STR_str(self);
|
||||||
|
}
|
||||||
|
|
207
str.h
Normal file
207
str.h
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2019 by John D. Robertson *
|
||||||
|
* john@rrci.com *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program 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 *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef STR_H
|
||||||
|
#define STR_H
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
/* STR is a dynamically sized null terminated string buffer which is always
|
||||||
|
* appended until STR_reset() is called. It is particularly useful for
|
||||||
|
* things like creating complex SQL queries.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct _cb {
|
||||||
|
size_t sz,
|
||||||
|
len;
|
||||||
|
|
||||||
|
char *buf;
|
||||||
|
} STR;
|
||||||
|
|
||||||
|
#define STR_str(self) \
|
||||||
|
((const char*)(self)->buf)
|
||||||
|
/**********************************************************************************
|
||||||
|
* Return the pointer to the buffer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define STR_len(self) \
|
||||||
|
((const size_t)(self)->len)
|
||||||
|
/**********************************************************************************
|
||||||
|
* Return the current length of the string in the buffer
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define STR_reset(self) \
|
||||||
|
((self)->buf[((self)->len= 0)]= '\0')
|
||||||
|
/**********************************************************************************
|
||||||
|
* Reset the buffer so that the length is zero.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
STR_sinit(STR *self, size_t sz_hint);
|
||||||
|
/**********************************************************************************
|
||||||
|
* Initialization to be called for static instances of STR each use, but
|
||||||
|
* actual initialization only occurs once.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define STR_create(p)\
|
||||||
|
((p)= (STR_constructor((p)=malloc(sizeof(STR))) ? (p) : ( p ? realloc(STR_destructor(p),0): 0)))
|
||||||
|
STR*
|
||||||
|
STR_constructor(STR *self, size_t sz_hint);
|
||||||
|
/**********************************************************************************
|
||||||
|
* Prepare a STR for use with initial size of sz_hint.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#define STR_destroy(self)\
|
||||||
|
if(STR_destructor(self)){free(self);(self)=NULL;}
|
||||||
|
void*
|
||||||
|
STR_destructor(STR *self);
|
||||||
|
/**********************************************************************************
|
||||||
|
* Free resources associated with STR.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
STR_sprintf(STR *self, const char *fmt, ...);
|
||||||
|
/**********************************************************************************
|
||||||
|
* Same as sprintf, except you don't have to worry about buffer overflows.
|
||||||
|
* Returns -1 for error.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
STR_vsprintf(STR *self, const char *fmt, va_list ap);
|
||||||
|
/**********************************************************************************
|
||||||
|
* Same as vsprintf, except you don't have to worry about buffer overflows.
|
||||||
|
* Returns -1 for error.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
STR_append(STR *self, const char *str, size_t str_len);
|
||||||
|
/**********************************************************************************
|
||||||
|
* Append string str to the end of the current buffer.
|
||||||
|
* Returns -1 for error.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
STR_putc(STR *self, int c);
|
||||||
|
/**********************************************************************************
|
||||||
|
* Append a single character to the end of the current buffer.
|
||||||
|
* Returns -1 for error.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const char*
|
||||||
|
STR_tolower(STR *self);
|
||||||
|
/**********************************************************************************
|
||||||
|
* Convert all characters in buffer to lower case.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const char*
|
||||||
|
STR_XMLencode(STR *self, const char *src);
|
||||||
|
/**************************************************************
|
||||||
|
* encode the src string for XML into self. Return self's buffer.
|
||||||
|
* NOTE: self does not get reset!
|
||||||
|
*/
|
||||||
|
|
||||||
|
const char*
|
||||||
|
STR_URLencode(STR *self, const char *src);
|
||||||
|
/**************************************************************
|
||||||
|
* encode the src string for URL into self. Return self's buffer.
|
||||||
|
* NOTE: self does not get reset!
|
||||||
|
*/
|
||||||
|
|
||||||
|
const char*
|
||||||
|
STR_utf8toHTML(STR *self, const char *src);
|
||||||
|
/**************************************************************
|
||||||
|
* place the HTML representation of the utf-8 src string into self.
|
||||||
|
* Return self's buffer.
|
||||||
|
* NOTE: self does not get reset!
|
||||||
|
*/
|
||||||
|
|
||||||
|
const char*
|
||||||
|
STR_escapeJSONstr(STR *self, const char *src);
|
||||||
|
/**************************************************************
|
||||||
|
* Escape any characters such the src can be used in a JSON
|
||||||
|
* string.
|
||||||
|
* Return self's buffer.
|
||||||
|
* NOTE: self does not get reset!
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
|
||||||
|
// C++ wrapper
|
||||||
|
|
||||||
|
class StrBuf {
|
||||||
|
public:
|
||||||
|
StrBuf(size_t sz_hint)
|
||||||
|
{STR_constructor(&obj, sz_hint);}
|
||||||
|
|
||||||
|
~StrBuf()
|
||||||
|
{STR_destructor(&obj);}
|
||||||
|
|
||||||
|
inline const char *str() const
|
||||||
|
{return STR_str(&obj);}
|
||||||
|
|
||||||
|
inline size_t len() const
|
||||||
|
{return STR_len(&obj);}
|
||||||
|
|
||||||
|
inline void reset()
|
||||||
|
{STR_reset(&obj);}
|
||||||
|
|
||||||
|
inline int sprintf(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
va_start (ap, fmt);
|
||||||
|
int rtn= STR_vsprintf(&obj, fmt, ap);
|
||||||
|
va_end (ap);
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int vsprintf(const char *fmt, va_list ap)
|
||||||
|
{
|
||||||
|
return STR_vsprintf(&obj, fmt, ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int append(const char *str, size_t str_len)
|
||||||
|
{return STR_append(&obj, str, str_len);}
|
||||||
|
|
||||||
|
inline int putc(int c)
|
||||||
|
{return STR_putc(&obj, c);}
|
||||||
|
|
||||||
|
inline const char* tolower()
|
||||||
|
{return STR_tolower(&obj);}
|
||||||
|
|
||||||
|
inline const char* XMLencode(const char *src)
|
||||||
|
{return STR_XMLencode(&obj, src);}
|
||||||
|
|
||||||
|
inline const char* URLencode(const char *src)
|
||||||
|
{return STR_URLencode(&obj, src);}
|
||||||
|
|
||||||
|
inline const char* utf8toHTML(const char *src)
|
||||||
|
{return STR_utf8toHTML(&obj, src);}
|
||||||
|
|
||||||
|
private:
|
||||||
|
STR obj;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
814
util.c
Normal file
814
util.c
Normal file
@ -0,0 +1,814 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2018 by John D. Robertson *
|
||||||
|
* john@rrci.com *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program 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 *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
/***************************************************************************
|
||||||
|
util.h - description
|
||||||
|
Common utility routines needed by most c and c++ applications.
|
||||||
|
|
||||||
|
-------------------
|
||||||
|
begin : Fri Oct 19 10:09:38 EDT 2018
|
||||||
|
email : john@rrci.com
|
||||||
|
***************************************************************************/
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/poll.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include "ez_dirent.h"
|
||||||
|
#include "ez_stdio.h"
|
||||||
|
#include "ez_stdlib.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#define MSGBUF_SZ 4096
|
||||||
|
|
||||||
|
static void
|
||||||
|
dflt_eprintf_line (const char *fmt, va_list ap)
|
||||||
|
/***************************************************************
|
||||||
|
* default line vprintf()'ing function for eprintf() and friends.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
vfprintf(stderr, fmt, ap);
|
||||||
|
fputc ('\n', stderr);
|
||||||
|
fflush (stderr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Static data for all threads */
|
||||||
|
static struct {
|
||||||
|
eprintf_line_f prt_f;
|
||||||
|
} S = {
|
||||||
|
.prt_f= dflt_eprintf_line
|
||||||
|
};
|
||||||
|
|
||||||
|
eprintf_line_f
|
||||||
|
set_eprintf_line (eprintf_line_f newFunc)
|
||||||
|
/****************************************************
|
||||||
|
* Set the global eprintf line vprintf()'ing function.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
eprintf_line_f rtn= S.prt_f;
|
||||||
|
S.prt_f= newFunc;
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Function to print out an error message. Usualy called by eprintf() macro. */
|
||||||
|
void _eprintf(
|
||||||
|
#ifdef DEBUG
|
||||||
|
const char* filename,
|
||||||
|
int lineno,
|
||||||
|
const char *func,
|
||||||
|
#endif
|
||||||
|
const char *fmt,
|
||||||
|
...
|
||||||
|
)
|
||||||
|
/*********************************************************************************
|
||||||
|
* Function to simplify printing error messages.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
char buf[MSGBUF_SZ];
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
/* Put the filename, lineno, and function name into a new format string */
|
||||||
|
snprintf(buf, MSGBUF_SZ-1, "%s line %d, %s(): %s", filename, lineno, func, fmt);
|
||||||
|
#else
|
||||||
|
snprintf(buf, MSGBUF_SZ-1, "%s", fmt);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* make sure buffer is null terminated */
|
||||||
|
buf[MSGBUF_SZ-1]= '\0';
|
||||||
|
|
||||||
|
|
||||||
|
/* Pass on doctored format string and varargs to vfprintf() */
|
||||||
|
va_start(args, fmt);
|
||||||
|
(* S.prt_f) (buf, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Function to print out an error message. Usualy called by sys_eprintf() macro. */
|
||||||
|
void _sys_eprintf(
|
||||||
|
const char* (*strerror_f)(int errnum),
|
||||||
|
#ifdef DEBUG
|
||||||
|
const char* filename,
|
||||||
|
int lineno,
|
||||||
|
const char *func,
|
||||||
|
#endif
|
||||||
|
const char *fmt,
|
||||||
|
...
|
||||||
|
)
|
||||||
|
/*********************************************************************************
|
||||||
|
* Function to simplify printing error messages.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
char buf[MSGBUF_SZ];
|
||||||
|
|
||||||
|
/* Put the filename, lineno, and function name into a new format string */
|
||||||
|
#ifdef DEBUG
|
||||||
|
snprintf(buf, MSGBUF_SZ-1, "%s line %d, %s(): %s [ %s ]", filename, lineno, func, fmt, (*strerror_f)(errno));
|
||||||
|
#else
|
||||||
|
snprintf(buf, MSGBUF_SZ-1, "%s [ %s ]", fmt, (*strerror_f)(errno));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* make sure buffer is null terminated */
|
||||||
|
buf[MSGBUF_SZ-1]= '\0';
|
||||||
|
|
||||||
|
|
||||||
|
/* Pass on doctored format string and varargs to vfprintf() */
|
||||||
|
va_start(args, fmt);
|
||||||
|
(* S.prt_f) (buf, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t
|
||||||
|
timespec_ms(const struct timespec *ts)
|
||||||
|
/**********************************************************************
|
||||||
|
* Convert a timespec structure to integer milliseconds.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
return ts->tv_sec*1000 + ts->tv_nsec/1000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
bits2str(int64_t bits, const struct bitTuple *btArr)
|
||||||
|
/**********************************************************************
|
||||||
|
* Returns a null terminated buffer with OR'd set bits
|
||||||
|
* printed out.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
/* Rotating buffers so this can be used multiple times as arg to printf() */
|
||||||
|
#define N_BUFS 10
|
||||||
|
static _Thread_local char bufArr[N_BUFS][1024];
|
||||||
|
static _Thread_local unsigned count;
|
||||||
|
const struct bitTuple *t;
|
||||||
|
unsigned offset;
|
||||||
|
char *buf= bufArr[++count%N_BUFS];
|
||||||
|
|
||||||
|
/* Need this in case no bits are set */
|
||||||
|
buf[0]= '\0';
|
||||||
|
|
||||||
|
for(offset= 0, t= btArr; t->name; ++t) {
|
||||||
|
if(!(bits & t->bit)) continue;
|
||||||
|
if(offset) offset += sprintf(buf+offset, "|");
|
||||||
|
offset += sprintf(buf+offset, "%s", t->name);
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
#undef N_BUFS
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct bitTuple*
|
||||||
|
findBitTuple(const char *symbol, const struct bitTuple *btArr)
|
||||||
|
/**********************************************************************
|
||||||
|
* brute force search for matching symbol.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
const struct bitTuple *bt;
|
||||||
|
for(bt= btArr; bt->name; ++bt) {
|
||||||
|
if(!strcmp(symbol, bt->name)) return bt;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
str2bits(int64_t *rtnBuf, const char *str, const struct bitTuple *btArr)
|
||||||
|
/**********************************************************************
|
||||||
|
* Convert all OR'd symbolic bits in str into the return value.
|
||||||
|
*
|
||||||
|
* RETURNS: 0 for success, -1 for error.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
*rtnBuf= 0;
|
||||||
|
if(!strlen(str)) return 0;
|
||||||
|
|
||||||
|
int rtn= -1;
|
||||||
|
char symbolArr[20][60];
|
||||||
|
memset(symbolArr, 0, sizeof(symbolArr));
|
||||||
|
|
||||||
|
int rc= sscanf(str,
|
||||||
|
"%59[^|] "
|
||||||
|
"| %59[^|] "
|
||||||
|
"| %59[^|] "
|
||||||
|
"| %59[^|] "
|
||||||
|
"| %59[^|] "
|
||||||
|
"| %59[^|] "
|
||||||
|
"| %59[^|] "
|
||||||
|
"| %59[^|] "
|
||||||
|
"| %59[^|] "
|
||||||
|
"| %59[^|] "
|
||||||
|
"| %59[^|] "
|
||||||
|
"| %59[^|] "
|
||||||
|
"| %59[^|] "
|
||||||
|
"| %59[^|] "
|
||||||
|
"| %59[^|] "
|
||||||
|
"| %59[^|] "
|
||||||
|
"| %59[^|] "
|
||||||
|
"| %59[^|] "
|
||||||
|
"| %59[^|] "
|
||||||
|
"| %59[^|] "
|
||||||
|
,symbolArr[0]
|
||||||
|
,symbolArr[1]
|
||||||
|
,symbolArr[2]
|
||||||
|
,symbolArr[3]
|
||||||
|
,symbolArr[4]
|
||||||
|
,symbolArr[5]
|
||||||
|
,symbolArr[6]
|
||||||
|
,symbolArr[7]
|
||||||
|
,symbolArr[8]
|
||||||
|
,symbolArr[9]
|
||||||
|
,symbolArr[10]
|
||||||
|
,symbolArr[11]
|
||||||
|
,symbolArr[12]
|
||||||
|
,symbolArr[13]
|
||||||
|
,symbolArr[14]
|
||||||
|
,symbolArr[15]
|
||||||
|
,symbolArr[16]
|
||||||
|
,symbolArr[17]
|
||||||
|
,symbolArr[18]
|
||||||
|
,symbolArr[19]
|
||||||
|
);
|
||||||
|
|
||||||
|
if(-1 == rc) {
|
||||||
|
sys_eprintf("ERROR: sscanf() failed");
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i= 0; i < rc; ++i) {
|
||||||
|
const struct bitTuple *bt= findBitTuple(symbolArr[i], btArr);
|
||||||
|
if(!bt) {
|
||||||
|
eprintf("ERROR: \"%s\" not found in bitTuple array.", symbolArr[i]);
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
*rtnBuf |= bt->bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rtn= 0;
|
||||||
|
|
||||||
|
abort:
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
printBuffer(FILE *fh, const char *buf)
|
||||||
|
/************************************************************************************
|
||||||
|
* Print out the supplied buffer, replacing unprintable characters with the corresponding
|
||||||
|
* hex value in pointy brackets, e.g. <0x01>
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
const char *pc;
|
||||||
|
/* Print something for each character */
|
||||||
|
for(pc= buf; pc && *pc; ++pc) {
|
||||||
|
|
||||||
|
if(isprint(*pc)) { /* Character is printable */
|
||||||
|
|
||||||
|
fputc(*pc, fh);
|
||||||
|
|
||||||
|
} else { /* Character is NOT printable, show hex number instead */
|
||||||
|
|
||||||
|
fprintf(fh, "<0x%02X>", *pc);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t
|
||||||
|
clock_gettime_ms(clockid_t whichClock)
|
||||||
|
/**********************************************************************
|
||||||
|
* Returns current value of whichClock in milliseconds, avoiding the
|
||||||
|
* need for struct timespec.
|
||||||
|
* See man clock_gettime for more information.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
struct timespec ts;
|
||||||
|
if(-1 == clock_gettime(whichClock, &ts)) {
|
||||||
|
sys_eprintf("\tclock_gettime() failed");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
return timespec_ms(&ts);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
local_strftime (const time_t *pWhen, const char *fmt)
|
||||||
|
/***************************************************
|
||||||
|
* Get local time in a static string buffer
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
/* Rotating buffers so this can be used multiple times as arg to printf() */
|
||||||
|
#define N_BUFS 5
|
||||||
|
#define BUF_SZ 64
|
||||||
|
static _Thread_local char bufArr[N_BUFS][BUF_SZ];
|
||||||
|
static _Thread_local unsigned count;
|
||||||
|
char *buf= bufArr[++count%N_BUFS];
|
||||||
|
|
||||||
|
/* Print the local time to a buffer */
|
||||||
|
struct tm *tm= localtime (pWhen);
|
||||||
|
if (!tm) {
|
||||||
|
sys_eprintf ("localtime() failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strftime (buf, BUF_SZ-1, fmt, tm)) {
|
||||||
|
sys_eprintf ("strftime(\"%s\") failed", fmt);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
#undef BUF_SZ
|
||||||
|
#undef N_BUFS
|
||||||
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
strbits(int64_t bits, unsigned nBytes)
|
||||||
|
/**********************************************************************
|
||||||
|
* Convert a bits to a null terminated string of '1' and '0' characters.
|
||||||
|
* Uses rotating per-thread static buffer for return, so it is safe
|
||||||
|
* to call multiple times in a single printf()ish invocation.
|
||||||
|
*
|
||||||
|
* bits: bit field of interest.
|
||||||
|
* nBytes: Number of bytes to consider.
|
||||||
|
*
|
||||||
|
* RETURNS:
|
||||||
|
* null terminated buffer with a string representing bits as '0' or '1'
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
/* Rotating buffers so this can be used multiple times as arg to printf() */
|
||||||
|
#define N_BUFS 5
|
||||||
|
#define BUF_SZ 65
|
||||||
|
static _Thread_local char bufArr[N_BUFS][BUF_SZ];
|
||||||
|
static _Thread_local unsigned count;
|
||||||
|
char *buf= bufArr[++count%N_BUFS];
|
||||||
|
unsigned pos= 0;
|
||||||
|
|
||||||
|
/* order bits from MSbit -> LSbit */
|
||||||
|
for(unsigned n= nBytes; n--;) {
|
||||||
|
unsigned char byte= (bits >>(8*n)) << 56 >> 56;
|
||||||
|
for(unsigned bit= 7; bit--;) {
|
||||||
|
buf[pos]= byte & 1<<bit ? '1' : '0';
|
||||||
|
++pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[pos]= '\0';
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
#undef BUF_SZ
|
||||||
|
#undef N_BUFS
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
fd_setNONBLOCK (int fd)
|
||||||
|
/***************************************************
|
||||||
|
* Set a file descriptor to non-blocking mode.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
int rtn= -1;
|
||||||
|
|
||||||
|
/* Set for non-blocking I/O */
|
||||||
|
int fcntlFlgs;
|
||||||
|
/* This sets 'status' flags */
|
||||||
|
if((fcntlFlgs= fcntl(fd, F_GETFL)) == -1 ||
|
||||||
|
fcntl(fd, F_SETFL, fcntlFlgs | O_NONBLOCK) == -1 ||
|
||||||
|
(fcntlFlgs= fcntl(fd, F_GETFD)) == -1 ||
|
||||||
|
fcntl(fd, F_SETFD, fcntlFlgs | FD_CLOEXEC) == -1) {
|
||||||
|
|
||||||
|
sys_eprintf("fcntl() failed");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This sets 'descriptor' flags */
|
||||||
|
fcntlFlgs= fcntl(fd, F_GETFD);
|
||||||
|
if(fcntl(fd, F_SETFD, fcntlFlgs | FD_CLOEXEC) < 0) {
|
||||||
|
sys_eprintf("fcntl() failed");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
rtn= 0;
|
||||||
|
|
||||||
|
abort:
|
||||||
|
return rtn;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct enumTuple*
|
||||||
|
str2enum(const char *str, const struct enumTuple *etArr)
|
||||||
|
/**********************************************************************
|
||||||
|
* Try to match str with an entry in the enumTupeArr.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
const struct enumTuple *et;
|
||||||
|
for(et= etArr; et->name; ++et) {
|
||||||
|
if(!strcmp(str, et->name)) return et;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
enum2str(int enumVal, const struct enumTuple *etArr)
|
||||||
|
/**********************************************************************
|
||||||
|
* Return a the string representing enumVal, or NULL.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
const struct enumTuple *et;
|
||||||
|
for(et= etArr; et->name; ++et) {
|
||||||
|
if(enumVal == et->enumVal) return et->name;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
sleep_ms(unsigned msec)
|
||||||
|
/***************************************************
|
||||||
|
* Sleep for the specified number of milliseconds.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
struct timespec ts;
|
||||||
|
ts.tv_sec= msec/1000;
|
||||||
|
ts.tv_nsec= (msec%1000)*1000000;
|
||||||
|
return nanosleep(&ts, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
tcp_connect(const char *hostName, unsigned short port)
|
||||||
|
/***************************************************
|
||||||
|
* Blocking TCP connect for convenience.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
int rtn= -1, sock;
|
||||||
|
struct hostent *hp;
|
||||||
|
struct sockaddr_in sin;
|
||||||
|
|
||||||
|
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if(-1 == sock) {
|
||||||
|
sys_eprintf("ERROR: socket() failed.");
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize socket address structure
|
||||||
|
hp = gethostbyname(hostName);
|
||||||
|
if(!hp) {
|
||||||
|
sys_eprintf("ERROR: gethostbyname(\"%s\") failed.", hostName);
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&sin, 0, sizeof(sin));
|
||||||
|
sin.sin_family = AF_INET;
|
||||||
|
sin.sin_port = htons(port);
|
||||||
|
memcpy(&(sin.sin_addr.s_addr), hp->h_addr, hp->h_length);
|
||||||
|
|
||||||
|
int err= connect(sock, (struct sockaddr *)&sin, sizeof(sin));
|
||||||
|
if(-1 == err) {
|
||||||
|
sys_eprintf("ERROR: connect(%s:%hu) failed.", hostName, port);
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
|
||||||
|
rtn= sock;
|
||||||
|
|
||||||
|
abort:
|
||||||
|
if(-1 == rtn) {
|
||||||
|
if(-1 != sock) {
|
||||||
|
ez_close(sock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
tm_normalize(struct tm *buf)
|
||||||
|
/***************************************************
|
||||||
|
* Normalize buf so member values are corrected.
|
||||||
|
* Returns 0 for success, -1 for failure.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
buf->tm_isdst= -1;
|
||||||
|
time_t tt= mktime(buf);
|
||||||
|
if(!localtime_r(&tt, buf)) {
|
||||||
|
sys_eprintf ("localtime() failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
secs2tod(const time_t *pFrom, int tod_sec)
|
||||||
|
/***************************************************
|
||||||
|
* Return the smallest number of seconds in the future
|
||||||
|
* remaining between from and tod_sec time-of-day, without
|
||||||
|
* respect to which day of the week/month/year.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
assert(0 <= tod_sec && (23*3600+59*60+59) >= tod_sec);
|
||||||
|
|
||||||
|
if(0 > tod_sec || (23*3600+59*60+59) < tod_sec) return -1;
|
||||||
|
|
||||||
|
/* Get the local time breakdown in a buffer */
|
||||||
|
struct tm tm_from;
|
||||||
|
if(!localtime_r(pFrom, &tm_from)) {
|
||||||
|
sys_eprintf ("localtime_r() failed");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We'll look at today and tomorrow */
|
||||||
|
for(int day= 0; day <= 1; ++day) {
|
||||||
|
|
||||||
|
struct tm tm= tm_from;
|
||||||
|
|
||||||
|
tm.tm_mday += day;
|
||||||
|
if(-1 == tm_normalize(&tm)) assert(0);
|
||||||
|
|
||||||
|
tm.tm_hour= tod_sec / 3600;
|
||||||
|
tm.tm_min= (tod_sec % 3600) / 60;
|
||||||
|
tm.tm_sec= (tod_sec % 3600) % 60;
|
||||||
|
|
||||||
|
time_t dptime= timelocal(&tm);
|
||||||
|
if(dptime > *pFrom) return (int)(dptime - *pFrom);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(0);
|
||||||
|
|
||||||
|
/* Can't find a time (should be impossible to get here) */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
indentStr(unsigned lvl, const char *pfix)
|
||||||
|
/***************************************************
|
||||||
|
* Return a string with lvl concatenated pfix strings.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
#define N_BUFS 10
|
||||||
|
#define BUF_SZ 128
|
||||||
|
static _Thread_local char bufArr[N_BUFS][BUF_SZ];
|
||||||
|
static _Thread_local unsigned count;
|
||||||
|
char *buf= bufArr[++count%N_BUFS];
|
||||||
|
size_t len= strlen(pfix);
|
||||||
|
|
||||||
|
buf[0]= '\0';
|
||||||
|
for(unsigned i= 0; (i+1)*len < BUF_SZ && i < lvl; ++i) {
|
||||||
|
strncpy(buf+i*len, pfix, len+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
|
||||||
|
#undef BUF_SZ
|
||||||
|
#undef N_BUFS
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
regex_compile(regex_t *preg, const char *pattern, int cflags)
|
||||||
|
/***************************************************
|
||||||
|
* Regular expression compile with error reporting.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
int rc, rtn= -1;
|
||||||
|
|
||||||
|
rc= regcomp(preg, pattern, cflags);
|
||||||
|
if(rc) {
|
||||||
|
#define BUF_SZ 1024
|
||||||
|
char buf[BUF_SZ];
|
||||||
|
regerror(rc, preg, buf, BUF_SZ);
|
||||||
|
eprintf("ERROR: %s", buf);
|
||||||
|
goto abort;
|
||||||
|
#undef BUF_SZ
|
||||||
|
}
|
||||||
|
|
||||||
|
rtn= 0;
|
||||||
|
|
||||||
|
abort:
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
prefix_home(const char *fname)
|
||||||
|
/***************************************************
|
||||||
|
* return $HOME/fname in a static buffer.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
#define N_BUFS 4
|
||||||
|
#define BUF_SZ PATH_MAX+1
|
||||||
|
static _Thread_local char bufArr[N_BUFS][BUF_SZ];
|
||||||
|
static _Thread_local unsigned count;
|
||||||
|
char *buf = bufArr[++count % N_BUFS];
|
||||||
|
|
||||||
|
const char *home_env= getenv("HOME");
|
||||||
|
|
||||||
|
if(home_env) {
|
||||||
|
snprintf(buf, BUF_SZ-1, "%s/%s", home_env, fname);
|
||||||
|
} else {
|
||||||
|
snprintf(buf, BUF_SZ-1, "%s", fname);
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
|
||||||
|
#undef BUF_SZ
|
||||||
|
#undef N_BUFS
|
||||||
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
pthread_t_str(pthread_t tid)
|
||||||
|
/***************************************************
|
||||||
|
* return a hexidecimal representation of tid in
|
||||||
|
* a rotating static buffer.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
#define N_BUFS 10
|
||||||
|
#define BUF_SZ (sizeof(tid)*2+3)
|
||||||
|
static _Thread_local char bufArr[N_BUFS][BUF_SZ];
|
||||||
|
static _Thread_local unsigned count;
|
||||||
|
char *buf = bufArr[++count % N_BUFS];
|
||||||
|
|
||||||
|
strcpy(buf, "0x");
|
||||||
|
char *dst= buf+2;
|
||||||
|
|
||||||
|
unsigned i, byte;
|
||||||
|
size_t sz= sizeof(tid);
|
||||||
|
for(i= 0; i < sz; ++i) {
|
||||||
|
byte= *((unsigned char *)(&tid) + sz - i - 1);
|
||||||
|
dst += sprintf(dst, "%02x", byte);
|
||||||
|
}
|
||||||
|
*dst= '\0';
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
|
||||||
|
#undef BUF_SZ
|
||||||
|
#undef N_BUFS
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char*
|
||||||
|
skipspace(char *str)
|
||||||
|
/***************************************************
|
||||||
|
* return first character in str which is not
|
||||||
|
* whitespace, which could be the terminating null.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
for(; *str && isspace(*str); ++str);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
skipspacec(const char *str)
|
||||||
|
/***************************************************
|
||||||
|
* return first character in str which is not
|
||||||
|
* whitespace, which could be the terminating null.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
for(; *str && isspace(*str); ++str);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
char*
|
||||||
|
trimend(char *str)
|
||||||
|
/***************************************************
|
||||||
|
* Trim space on end of string by replacing it with
|
||||||
|
* null bytes.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
size_t len= strlen(str);
|
||||||
|
for(; len && isspace(str[len-1]); str[--len]= '\0');
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
julian_2_gregorian(int *year, int *month, int *day, uint32_t julianDay)
|
||||||
|
/************************************************************************
|
||||||
|
* Gregorian calendar starting from October 15, 1582
|
||||||
|
* This algorithm is from Henry F. Fliegel and Thomas C. Van Flandern
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
uint64_t ell, n, i, j;
|
||||||
|
|
||||||
|
ell = (uint64_t)julianDay + 68569;
|
||||||
|
n = (4 * ell) / 146097;
|
||||||
|
ell = ell - (146097 * n + 3) / 4;
|
||||||
|
i = (4000 * (ell + 1)) / 1461001;
|
||||||
|
ell = ell - (1461 * i) / 4 + 31;
|
||||||
|
j = (80 * ell) / 2447;
|
||||||
|
*day = ell - (2447 * j) / 80;
|
||||||
|
ell = j / 11;
|
||||||
|
*month = j + 2 - (12 * ell);
|
||||||
|
*year = 100 * (n - 49) + i + ell;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t
|
||||||
|
gregorian_2_julian(int year, int month, int day)
|
||||||
|
/* Gregorian calendar starting from October 15, 1582
|
||||||
|
* Algorithm from Henry F. Fliegel and Thomas C. Van Flandern
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
return (1461 * (year + 4800 + (month - 14) / 12)) / 4
|
||||||
|
+ (367 * (month - 2 - 12 * ((month - 14) / 12))) / 12
|
||||||
|
- (3 * ((year + 4900 + (month - 14) / 12) / 100)) / 4
|
||||||
|
+ day - 32075;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
bytes_2_hexStr(
|
||||||
|
char *rtn_sbuf,
|
||||||
|
unsigned rtn_sz,
|
||||||
|
const unsigned char *src,
|
||||||
|
unsigned src_len
|
||||||
|
)
|
||||||
|
/***************************************************************
|
||||||
|
* Convert bytes to hex characters, place in rtn_sbuf.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
if(src_len*2 >= rtn_sz)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
unsigned i;
|
||||||
|
for(i= 0; i < src_len; ++i) {
|
||||||
|
snprintf(rtn_sbuf+i*2, rtn_sz-i*2, "%02x", (int)src[i]);
|
||||||
|
}
|
||||||
|
/* Null terminate the result */
|
||||||
|
rtn_sbuf[i*2]= '\0';
|
||||||
|
return rtn_sbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
rmdir_recursive(const char *path)
|
||||||
|
/***************************************************************
|
||||||
|
* recursively remove a directory and all of it's contents.
|
||||||
|
* RETURNS:
|
||||||
|
* 0 for success
|
||||||
|
* -1 for error
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
int rtn= -1;
|
||||||
|
|
||||||
|
struct stat st;
|
||||||
|
DIR *dir= ez_opendir(path);
|
||||||
|
struct dirent *entry;
|
||||||
|
STR sb;
|
||||||
|
STR_constructor(&sb, PATH_MAX);
|
||||||
|
|
||||||
|
while((entry= ez_readdir(dir))) {
|
||||||
|
/* Skip uninteresting entries */
|
||||||
|
if(!strcmp(".", entry->d_name) ||
|
||||||
|
!strcmp("..", entry->d_name)) continue;
|
||||||
|
|
||||||
|
STR_reset(&sb);
|
||||||
|
STR_sprintf(&sb, "%s/%s", path, entry->d_name);
|
||||||
|
|
||||||
|
ez_stat(STR_str(&sb), &st);
|
||||||
|
if (S_ISDIR(st.st_mode)) {
|
||||||
|
int rc= rmdir_recursive(STR_str(&sb));
|
||||||
|
if(rc)
|
||||||
|
goto abort;
|
||||||
|
} else {
|
||||||
|
ez_unlink(STR_str(&sb));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rtn= 0;
|
||||||
|
|
||||||
|
abort:
|
||||||
|
if(!rtn)
|
||||||
|
ez_rmdir(path);
|
||||||
|
|
||||||
|
STR_destructor(&sb);
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _ez_rmdir_recursive (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
const char *pathname
|
||||||
|
)
|
||||||
|
/***************************************************************
|
||||||
|
* ez version of rmdir_recursive().
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
int rtn= rmdir_recursive (pathname);
|
||||||
|
if (-1 == rtn) {
|
||||||
|
_eprintf(fileName, lineNo, funcName, "rmdir_recursive(\"%s\") failed", pathname);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
return rtn;
|
||||||
|
}
|
374
util.h
Normal file
374
util.h
Normal file
@ -0,0 +1,374 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2018 by John D. Robertson *
|
||||||
|
* john@rrci.com *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program 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 *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
/***************************************************************************
|
||||||
|
util.h - description
|
||||||
|
Common utility routines needed by most c and c++ applications.
|
||||||
|
|
||||||
|
-------------------
|
||||||
|
begin : Fri Oct 19 10:09:38 EDT 2018
|
||||||
|
email : john@rrci.com
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef UTIL_H
|
||||||
|
#define UTIL_H
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <regex.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "str.h"
|
||||||
|
|
||||||
|
#ifndef MAX
|
||||||
|
# define MAX(a,b) \
|
||||||
|
((a) > (b) ? (a) : (b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MIN
|
||||||
|
# define MIN(a,b) \
|
||||||
|
((a) < (b) ? (a) : (b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef stringify
|
||||||
|
# define _stringify(a) #a
|
||||||
|
# define stringify(a) _stringify(a)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef member_size
|
||||||
|
# define member_size(type,member) \
|
||||||
|
sizeof(((type*)0)->member)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
# define ERRNO_CHECK \
|
||||||
|
if(errno) { \
|
||||||
|
sys_eprintf("ERRNO= %d", errno);\
|
||||||
|
fflush(NULL);\
|
||||||
|
abort();\
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
# define ERRNO_CHECK
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* For readability */
|
||||||
|
typedef void (*eprintf_line_f) (const char*, va_list);
|
||||||
|
|
||||||
|
eprintf_line_f
|
||||||
|
set_eprintf_line (eprintf_line_f newFunc);
|
||||||
|
/****************************************************
|
||||||
|
* Set the global eprintf line vprintf()'ing function.
|
||||||
|
* This is useful for sending error messages to places
|
||||||
|
* other than stderr.
|
||||||
|
*
|
||||||
|
* RETURNS: the previous global eprintf line vprintf()'ing function.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* Macro to conveniently create error messages which contain source filename, lineno, and funcname. */
|
||||||
|
#ifdef DEBUG
|
||||||
|
# define eprintf(fmt, ...) \
|
||||||
|
_eprintf(__FILE__, __LINE__, __FUNCTION__, fmt, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
# define eprintf(fmt, ...) \
|
||||||
|
_eprintf(fmt, ##__VA_ARGS__)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Function to print out an error message. Usually called by eprintf() macro. */
|
||||||
|
void _eprintf(
|
||||||
|
#ifdef DEBUG
|
||||||
|
const char* filename,
|
||||||
|
int lineno,
|
||||||
|
const char *func,
|
||||||
|
#endif
|
||||||
|
const char *fmt,
|
||||||
|
...
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/* Macro to conveniently create error messages which contain source filename, lineno, and funcname. */
|
||||||
|
#ifdef DEBUG
|
||||||
|
# define sys_eprintf(fmt, ...) \
|
||||||
|
_sys_eprintf((const char*(*)(int))strerror, __FILE__, __LINE__, __FUNCTION__, fmt, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
# define sys_eprintf(fmt, ...) \
|
||||||
|
_sys_eprintf((const char*(*)(int))strerror, fmt, ##__VA_ARGS__)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Function to print out an error message and strerror(errno). Usualy called by sys_eprintf() macro. */
|
||||||
|
void _sys_eprintf(
|
||||||
|
const char* (*strerror_f)(int errnum), /* pass in which strerror() to use, for ZeroMQ support */
|
||||||
|
#ifdef DEBUG
|
||||||
|
const char* filename,
|
||||||
|
int lineno,
|
||||||
|
const char *func,
|
||||||
|
#endif
|
||||||
|
const char *fmt,
|
||||||
|
...
|
||||||
|
);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/* Special verion for working with ZeroMQ */
|
||||||
|
#ifdef DEBUG
|
||||||
|
# define zys_eprintf(fmt, ...) \
|
||||||
|
_sys_eprintf(zmq_strerror, __FILE__, __LINE__, __FUNCTION__, fmt, ##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
# define zys_eprintf(fmt, ...) \
|
||||||
|
_sys_eprintf(zmq_strerror, fmt, ##__VA_ARGS__)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Forward declaration */
|
||||||
|
struct timespec;
|
||||||
|
|
||||||
|
int64_t
|
||||||
|
timespec_ms(const struct timespec *ts);
|
||||||
|
/**********************************************************************
|
||||||
|
* Convert a timespec structure to integer milliseconds.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int64_t
|
||||||
|
clock_gettime_ms(clockid_t whichClock);
|
||||||
|
/**********************************************************************
|
||||||
|
* Returns current value of whichClock in milliseconds, avoiding the
|
||||||
|
* need for struct timespec.
|
||||||
|
* See man clock_gettime for more information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Need to fill out an array of these to use bitsString() */
|
||||||
|
struct bitTuple {
|
||||||
|
const char *name; // Make this NULL to terminate your array
|
||||||
|
int64_t bit; /* Not bit position; one and only one bit set */
|
||||||
|
};
|
||||||
|
|
||||||
|
const char*
|
||||||
|
bits2str(int64_t bits, const struct bitTuple *btArr);
|
||||||
|
/**********************************************************************
|
||||||
|
* Convert a bit field into a readable string.
|
||||||
|
* Uses rotating per-thread static buffer for return, so it is safe
|
||||||
|
* to call multiple times in a single printf()ish invocation.
|
||||||
|
*
|
||||||
|
* bits: bit field of interest.
|
||||||
|
* btArr: array of struct bitTuple to map bits to strings.
|
||||||
|
*
|
||||||
|
* RETURNS:
|
||||||
|
* null terminated buffer with a string representing the OR'd set bits
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
str2bits(int64_t *rtnBuf, const char *str, const struct bitTuple *btArr);
|
||||||
|
/**********************************************************************
|
||||||
|
* Convert all OR'd symbolic bits in str into the return value.
|
||||||
|
*
|
||||||
|
* RETURNS: 0 for success, -1 for error.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* Need to fill out an array of these to use str2enum() */
|
||||||
|
struct enumTuple {
|
||||||
|
const char *name; // Make this NULL to terminate your array
|
||||||
|
int enumVal; /* enum corresponding to name */
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct enumTuple*
|
||||||
|
str2enum(const char *str, const struct enumTuple *etArr);
|
||||||
|
/**********************************************************************
|
||||||
|
* Try to match str with an entry in the enumTupeArr.
|
||||||
|
*
|
||||||
|
* RETURNS: address of match struct enumTuple, or NULL if none are found.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const char*
|
||||||
|
enum2str(int enumVal, const struct enumTuple *etArr);
|
||||||
|
/**********************************************************************
|
||||||
|
* Return a the string representing enumVal, or NULL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
printBuffer(FILE *fh, const char *buf);
|
||||||
|
/************************************************************************************
|
||||||
|
* Print out the supplied buffer, replacing unprintable characters with the corresponding
|
||||||
|
* hex value in pointy brackets, e.g. <0x01>
|
||||||
|
*/
|
||||||
|
|
||||||
|
const char*
|
||||||
|
local_strftime (const time_t *pWhen, const char *fmt);
|
||||||
|
/***************************************************
|
||||||
|
* Get local time in a static string buffer. Format
|
||||||
|
* string is passed to strftime().
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
fd_setNONBLOCK (int fd);
|
||||||
|
/***************************************************
|
||||||
|
* Set a file descriptor to non-blocking mode.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
sleep_ms(unsigned msec);
|
||||||
|
/***************************************************
|
||||||
|
* Sleep for the specified number of milliseconds.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
tcp_connect(const char *hostName, unsigned short port);
|
||||||
|
/***************************************************
|
||||||
|
* Blocking TCP connect for convenience.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
tm_normalize(struct tm *buf);
|
||||||
|
/***************************************************
|
||||||
|
* Normalize buf so member values are corrected.
|
||||||
|
* Returns 0 for success, -1 for failure.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
secs2tod(const time_t *pFrom, int tod_sec);
|
||||||
|
/***************************************************
|
||||||
|
* Return the smallest number of seconds in the future
|
||||||
|
* remaining between from and tod_sec time-of-day, without
|
||||||
|
* respect to which day of the week/month/year.
|
||||||
|
* RETURN -1 for error, or seconds until tod_secs.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const char*
|
||||||
|
indentStr(unsigned lvl, const char *pfix);
|
||||||
|
/***************************************************
|
||||||
|
* Return a string with lvl concatenated pfix strings.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
regex_compile(regex_t *preg, const char *pattern, int cflags);
|
||||||
|
/***************************************************
|
||||||
|
* Regular expression compile with error reporting.
|
||||||
|
*/
|
||||||
|
|
||||||
|
FILE*
|
||||||
|
pager_open();
|
||||||
|
/***************************************************
|
||||||
|
* popen() the caller's pager.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const char*
|
||||||
|
prefix_home(const char *fname);
|
||||||
|
/***************************************************
|
||||||
|
* return $HOME/fname in a static buffer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
char*
|
||||||
|
skipspace(char *str);
|
||||||
|
/***************************************************
|
||||||
|
* return first character in str which is not
|
||||||
|
* whitespace, which could be the terminating null.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const char*
|
||||||
|
skipspacec(const char *str);
|
||||||
|
/*************************************************
|
||||||
|
* same as skipspace(), except using const types.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
char*
|
||||||
|
trimend(char *str);
|
||||||
|
/***************************************************
|
||||||
|
* Trim space on end of string by replacing it with
|
||||||
|
* null bytes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define trim(str) \
|
||||||
|
skipspace(trimend(str))
|
||||||
|
|
||||||
|
const char*
|
||||||
|
pthread_t_str(pthread_t tid);
|
||||||
|
/***************************************************
|
||||||
|
* return a hexidecimal representation of tid in
|
||||||
|
* a rotating static buffer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
julian_2_gregorian(int *year, int *month, int *day, uint32_t julianDay);
|
||||||
|
/************************************************************************
|
||||||
|
* Gregorian calendar starting from October 15, 1582
|
||||||
|
* This algorithm is from Henry F. Fliegel and Thomas C. Van Flandern
|
||||||
|
*/
|
||||||
|
|
||||||
|
int32_t
|
||||||
|
gregorian_2_julian(int year, int month, int day);
|
||||||
|
/* Gregorian calendar starting from October 15, 1582
|
||||||
|
* Algorithm from Henry F. Fliegel and Thomas C. Van Flandern
|
||||||
|
*/
|
||||||
|
|
||||||
|
const char*
|
||||||
|
strbits(int64_t bits, unsigned nBytes);
|
||||||
|
/**********************************************************************
|
||||||
|
* Convert a bits to a null terminated string of '1' and '0' characters.
|
||||||
|
* Uses rotating per-thread static buffer for return, so it is safe
|
||||||
|
* to call multiple times in a single printf()ish invocation.
|
||||||
|
*
|
||||||
|
* bits: bit field of interest.
|
||||||
|
* nBytes: Number of bytes to consider.
|
||||||
|
*
|
||||||
|
* RETURNS:
|
||||||
|
* null terminated buffer with a string representing bits as '0' or '1'
|
||||||
|
*/
|
||||||
|
|
||||||
|
const char*
|
||||||
|
bytes_2_hexStr(
|
||||||
|
char *rtn_sbuf,
|
||||||
|
unsigned rtn_sz,
|
||||||
|
const unsigned char *src,
|
||||||
|
unsigned src_len
|
||||||
|
);
|
||||||
|
/***************************************************************
|
||||||
|
* Convert bytes to hex characters, place null terminated string
|
||||||
|
* in rtn_sbuf.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
rmdir_recursive(const char *path);
|
||||||
|
/***************************************************************
|
||||||
|
* recursively remove a directory and all of it's contents.
|
||||||
|
* RETURNS:
|
||||||
|
* 0 for success
|
||||||
|
* -1 for error
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ez_rmdir_recursive(path) \
|
||||||
|
_ez_rmdir_recursive(__FILE__, __LINE__, __FUNCTION__, path)
|
||||||
|
int _ez_rmdir_recursive (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
const char *path
|
||||||
|
);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user