#!/usr/bin/awk
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
#  
#  
# Licensed Materials - Property of IBM 
#  
# (C) COPYRIGHT International Business Machines Corp. 2000,2019 
# All Rights Reserved 
#  
# US Government Users Restricted Rights - Use, duplication or 
# disclosure restricted by GSA ADP Schedule Contract with IBM Corp. 
#  
# IBM_PROLOG_END_TAG 
# sccsid = "@(#)66   1.2   src/rsct/ffdc/bin/fcparse.awk, ffdc, rsct_rady, rady2035a 3/9/15 09:58:14"
# =============================================================================
# Module Name:	fc_parse.awk
#
# Component:	ffdc
#
# Description:	Script for "awk" command to identify selectors within a Syslog
#		configuration file (ex: /etc/syslog.conf) whose action is to
#		record only to a file.
#
#		This "awk" script is to be executed after another facility has
#		preprocessed the Syslog configuration file to remove comments
#		and to collapse multiple lined entries.  Although this script
#		could handle basic comments, it cannot handle multiple line
#		entries, nor comments embedded within multiple line entries.
#
# Usage:	sed -f fc_strip.sed <Syslog_configuration_file> | \
#		sed -f fc_join.sed | \
#		awk -f fc_parse.awk
#
# Input:	Preprocessed Syslog configuration file, with comments removed
#		and multiple lined entries collapsed into single lines.
#
# Output:	Zero or more lines in the following format:
#			<base_64_code>\t<file_name>
#		where:
#			<base_64_code>	A 6-digit base-64 encoding that
#					indicates the facility and the priority
#					associated with a specific log file
#			<log_file>	Was obtained from the action field of
#					the Syslog configuration file entry for
#					this selector
#
# Exit Status:	Set by "awk"
# =============================================================================
# ------------------------- #
# Global value declarations #
# ------------------------- #
BEGIN {
	# Used for converting upper case charatecters to lower case
	upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
	lower = "abcdefghijklmnopqrstuvwxyz"
	# Used to convert decimal values to base-64 values
	base64 = "./0123456789ABCEDFGHIJKLMNOPQRSTUVWXZYabcdefghijklmnopqrstuvwxyz"
	# Used to convert facilities and priorities
	#
	#  ------    The list of facilities and priorities MUST match the
	# | NOTE |   c_name values specified in the /usr/include/sys/syslog.h
	#  ------    header arrays facilitynames[] and prioritynames[]
	prioritylist[1] = "emerg"	;	prioritylist[2] = "alert"
	prioritylist[3] = "crit"	;	prioritylist[4] = "err"
	prioritylist[5] = "warning"	;	prioritylist[6] = "notice"
	prioritylist[7] = "info"	;	prioritylist[8] = "debug"
	prioritylist[9] = "none"
	oldprilist[1] = "panic"		;	oldprilist[4] = "error"
	oldprilist[5] = "warn"
	facilitylist[1] = "kern"	;	facilitylist[2] = "user"
	facilitylist[3] = "mail"	;	facilitylist[4] = "daemon"
	facilitylist[5] = "auth"	;	facilitylist[6] = "syslog"
	facilitylist[7] = "lpr"		;	facilitylist[8] = "news"
	facilitylist[9] = "uucp"	;	facilitylist[10] = "cron"
	facilitylist[11] = "authpriv"	;	facilitylist[12] = "ftp"
	facilitylist[13] = "mark"	;	facilitylist[14] = "reserved"
	facilitylist[15] = "reserved"	;	facilitylist[16] = "reserved"
	facilitylist[17] = "local0"	;	facilitylist[18] = "local1"
	facilitylist[19] = "local2"	;	facilitylist[20] = "local3"
	facilitylist[21] = "local4"	;	facilitylist[22] = "local5"
	facilitylist[23] = "local6"	;	facilitylist[24] = "local7"
	oldfaclist[5] = "security"
	# Maximum number of logfile array elements
	entrytable[1,1] = ""		;	entrytable[21,8] = ""
	logfiletable[1,1] = ""		;	logfiletable[21,8] = ""
	maxfacilities = 24		;	maxpriorities = 8
}
# -------------------------------------- #
# Mainline /etc/syslog.conf Parsing Code #
# -------------------------------------- #
# Process non-comments in /etc/syslog.conf (should have been removed by now)
!/^$/ && !/^#/ 	{
	# Work on entries sending messages to files only
	if ( $2 ~ /-?\/+/ ) {
		# Strip any "no sync" chars from the log file name
		logfilestart = index($2, "-")
		if (0 == logfilestart) {
			newlogfile = $2
		}
		else {
			logfilestart++
			newlogfile = substr($2, logfilestart)
		}
		# Construct temporary array containing list of all selectors
		# (facility and priority pairs) that apply.  The selector
		# field may have more than one selector within it, and some
		# subsequent selectors may change the actions taken by previos
		# ones in the same entry (ex: the "none" and "!" markers).
		for (h = 1 ; h <= maxfacilities ; h++) {
			for (i = 1 ; i <= maxpriorities ; i++ ) {
				entrytable[h,i] = ""
			}
		}
		numsels = split($1, selectors, ";")
		totalsels = numsels
		for (i = 1 ; i <= numsels ; i++) {
			# Each individual selector may have multiple facilities
			# associated with the same priority.
			numfacs = split(selectors[i], facilities, ",")
			if (1 == numfacs) {
				newselector = lower_selector(selectors[i])
				expand_and_list(newselector, newlogfile)
			}
			else {
				totalsels += numfacs - 1
				prioritystart = index(selectors[i], ".")
				priority = substr(selectors[i], prioritystart)
				for (j = 1 ; j < numfacs ; j++) {
					newselector = facilities[j] priority
					newselector = \
					       lower_selector(newselector)
					expand_and_list(newselector, \
					       newlogfile)
				}
				numfacs = split(facilities[j], lastfac, ".")
				newselector = lastfac[1] priority
				newselector = lower_selector(newselector)
				expand_and_list(newselector, newlogfile)
			}
		}
		# Now that entry has been fully expanded and the selectors
		# stored, update the global array with the results.
		for (h = 1 ; h <= maxfacilities ; h++) {
			for (i = 1 ; i <= maxpriorities ; i++) {
				if ( entrytable[h,i] !~ /^$/ ) {
					record_logfile(logfiletable, h, i, \
					               entrytable[h,i])
				}
			}
		}
#DEBUG		printf("Contents of Log File Array after processing %s:\n", \
#DEBUG		       $2)
#DEBUG		dump_array(logfiletable, maxfacilities, maxpriorities)
	}
}
# ---------------------------------------- #
# Print Out the Results of This Processing #
# ---------------------------------------- #
END {
	for (h = 1 ; h <= maxfacilities ; h++) {
		for (i = 1 ; i <= maxpriorities ; i++) {
			if ( logfiletable[h,i] !~ /^$/ ) {
				fac64 = convert_to_base64(h)
				pri64 = convert_to_base64(i)
				printf("%s%s....\t%s\n", fac64, pri64, \
				       logfiletable[h,i])
			}
		}
	}
}
# ------------------------------------- #
# Function to Dump Contents of An Array #
# ------------------------------------- #
function dump_array (array, rowlimit, columnlimit) {
	for (a = 1 ; a <= rowlimit ; a++) {
		for (b = 1 ; b <= columnlimit ; b++) {
			if ( array[a,b] !~ /^$/ ) {
				printf("\tElement [%2d,%2d]: \t Value %s\n", \
				       a,b, array[a,b])
			}
			else {
				printf("\tElement [%2d,%2d]: \t [ empty ]\n", \
				       a, b)
			}
		}
	}
}
# -------------------------------------------------- #
# Function to Convert Selector Strings to Lower Case #
# -------------------------------------------------- #
function lower_selector (selector) {
	workselector = selector
	for (k = 1 ; k <= length(workselector) ; k++) {
		thischar = substr(selector, k, 1)
		if (character = index(upper, thischar)) {
			workselector = substr(workselector, 1, k-1) \
			               substr(lower, character, 1) \
			               substr(selector, k+1)
		}
	}
	return workselector
}
# ----------------------------------------------- #
# Function to Locate Selector Name Numeric Values #
# ----------------------------------------------- #
function get_index (which, codename) {
	if ("facility" == which) {
		if (codename == oldfaclist[5]) {
			return 5
		}
		for (m = 1 ; m <= 21 ; m++) {
			if (codename == facilitylist[m]) {
				return m
			}
		}
	}
	else {
		for (m = 1 ; m <= 9 ; m++) {
			if (codename == prioritylist[m]) {
				return m
			}
		}
		for (m = 1 ; m <= 5 ; m++) {
			if (codename == oldprilist[m]) {
				return m
			}
		}
	}
	return 0
}
# -------------------------------------------------------------- #
# Function to Store All Identified Selectors and Their Log Files #
# -------------------------------------------------------------- #
function record_logfile (tableparam, rowindex, columnindex, lfile) {
#DEBUG	if ( tableparam[rowindex,columnindex] !~ /^$/ ) {
#DEBUG		printf("\t Overwriting value %s w/ %s at element [%d,%d]\n", \
#DEBUG		       tableparam[selectorsindex], lfile, \
#DEBUG		       rowindex, columnindex)
#DEBUG	}
	tableparam[rowindex, columnindex] = lfile
}
# ------------------------------------------------------------ #
# Function to Identify All Priorities Affected By the Selector #
# ------------------------------------------------------------ #
function expand_priority (selectorcode, facilityindex, lfile) {
	# Obtain priority value from the provided selector
	selectnum = split(selectorcode, selectcomps, ".")
	# Find what range of priorities are impacted: all (*), just one (=),
	# or the normal function of "everything up to..."
	usefile = lfile
	if ( selectcomps[2] ~ /^\*/ ) {
		ylow = 1
		yhigh = 8
	}
	else {
		if ("none" == selectcomps[2]) {
			ylow = 1
			yhigh = 8
			usefile = ""
		}
		else {
			onlyone = 0
			while (1) {
				if ( selectcomps[2] ~ /^!/ ) {
					usefile = ""
					selectcomps[2] = substr(selectcomps[2],\
					                        2)
					continue
				}
				if ( selectcomps[2] ~ /^=/ ) {
					onlyone = 1
					selectcomps[2] = substr(selectcomps[2],\
					                        2)
					continue
				}
				break
			}
			yhigh = get_index("priority", selectcomps[2])
			if (onlyone) {
				ylow = yhigh
			}
			else {
				ylow = 1
			}
		}
	}
	# Expand the selector into its full list and process it
	for (y = ylow ; y <= yhigh ; y++) {
		expandedsel = selectcomps[1] "." prioritylist[y]
#DEBUG		printf("\t expanded to %s [ code %d, %d ] - file %s\n", \
#DEBUG		       expandedsel, facilityindex, y, usefile)
		# Record this selector's log file in the global array
		record_logfile(entrytable, facilityindex, y, usefile)
	}
}
# ------------------------------------------------------------ #
# Function to Identify All Facilities Affected By the Selector #
# ------------------------------------------------------------ #
function expand_and_list (selectcde, lfile) {
	# Obtain facility value from the provided selector
	selectno = split(selectcde, selectcmps, ".")
	# Find out if all facilities or only one are affected, expand the
	# facility if necessary, and process it
	if ( selectcmps[1] ~ /^\*/ ) {
		xlow = 1
		xhigh = 21
	}
	else {
		xlow = get_index("facility", selectcmps[1])
		xhigh = xlow
	}
	for (x = xlow ; x <= xhigh ; x++ ) {
		expselector = facilitylist[x] "." selectcmps[2]
#DEBUG		printf("%s expanded to %s, log file %s\n", selectcde, \
#DEBUG		       expselector, lfile)
		expand_priority(expselector, x, lfile)
	}
}
#----------------------------------------------------------#
# Function to Convert Decimal Values Into Base-64 Notation #
# !! NOTE !!    Assumes decimal values are 0 >= x >= 63    #
#----------------------------------------------------------#
function convert_to_base64 (decimalval) {
	counterpart = substr(base64, decimalval, 1)
	return counterpart
}