Snippets

Autor : Gerd Raudenbusch
Stand : 26.12.2023

Contents

Matrix Bot

#!/bin/bash

botmessages="./matrixbot-messages.txt"

python3 --version >/dev/null 2>&1
if [ "$?" != "0" ]; then
	echo "Must install python3"
	sudo apt update && sudo apt -y upgrade && sudo apt install -y python3 python3-pip
fi

matrix-commander --version >/dev/null 2>&1
if [ "$?" != "0" ]; then
	echo "Must install matrix-commander"
	sudo pip3 install matrix-commander
fi

inotifywait >/dev/null 2>&1
if [ "$?" != "1" ]; then
	echo "Must install inotify tools"
	sudo apt update && sudo apt -y upgrade && sudo apt-get install inotify-tools
fi

processmsg () {
	if [ "${1}" == "Ping" ]; then
		echo "${0} : PROCESSING ${1}"
		matrix-commander -m "Voila!" >/dev/null 2>&1
	else
		echo "The message '${1}' has no scripted reactions"
	fi
}

killold () {
	echo "Removing old instances of matrix-commander..."
	kill -9 $(ps axn | grep matrix-commander | grep -v grep | sed "s/^ *//g" | cut -d " " -f1 | tr '\n' ' ')
}

trap 'killold' SIGINT SIGTERM

if [ ! -f ${HOME}/.config/matrix-commander/credentials.json ]; then
	echo "There are no credentials saved, yet. Please create a default room for the bot and register credentials :"
	matrix-commander --login password
	if [ "$?" == "0" ] && [ -f ./credentials.json ]; then
		mkdir -p ${HOME}/.config/matrix-commander
		mv -i ./credentials.json $HOME/.config/matrix-commander
		mkdir -p ${HOME}/.local/share/matrix-commander 
		mv -i ./store ${HOME}/.local/share/matrix-commander
	else
		echo "Exitting due to errors"
		exit 1
	fi
else
	echo "Logging in"
	matrix-commander --credentials ${HOME}/.config/matrix-commander/credentials.json >/dev/null 2>&1
	if [ "$?" != "0" ]; then
		echo "Error logging in"
		exit 1
	fi
	echo "Starting listener for messages, dropping files in ${botmessages}"
	matrix-commander --listen forever --listen-self >${botmessages} 2>/dev/null &
	while inotifywait -e modify "${botmessages}" >/dev/null 2>&1; do
		lastline="$(tail -1 ${botmessages})"
		operation="$(echo ${lastline} | cut -d "|" -f1)"
		sender="$(echo ${lastline} | cut -d "|" -f2 | sed "s/^ //g; s/sender //g")"
		timestamp="$(echo ${lastline} | cut -d "|" -f3 | sed "s/^ //g")"
		message="$(echo ${lastline} | cut -d "|" -f4 | sed "s/^ //g")"
		if [ "$(echo "${operation}" | grep -c "Message received")" != "0" ]; then
			echo "${0}: [${timestamp} ${sender}] : ${message}"
			processmsg "${message}"
		fi
	done
fi

RSS File writer

#!/bin/bash
#
# This script creates RSS Feed Files
# for webpages and adds new feed entries.
#
# @author: gerd@raudenbusch.net
#

if test -t 1; then
        ncolors=$(tput colors)
        if test -n "$ncolors" && test $ncolors -ge 8; then
                BLACK=`tput setaf 0`
		RED=`tput setaf 1`
		GREEN=`tput setaf 2`
		YELLOW=`tput setaf 3`
		BLUE=`tput setaf 4`
		MAGENTA=`tput setaf 5`
		CYAN=`tput setaf 6`
		WHITE=`tput setaf 7`

		BOLD=`tput bold`
		RESET=`tput sgr0`
        fi
fi

log () {
        >&2 echo "${1}"
}

printInfo () {
    log "${BOLD}${WHITE}${1}${RESET}"
}

printWarning () {
    log "${BOLD}${YELLOW}${1}${RESET}"
}

printSuccess () {
    log "${BOLD}${GREEN}${1}${RESET}"
}

printError () {
    log "${BOLD}${RED}${1}${RESET}"
}

createFeed () {
    local TITLE="${1}"
    local DOMAIN="${2}"
    local DESCRIPTION="${3}"
    local FILENAME="${4}"
    cat << EOF >${FILENAME}
<rss version="2.0">
	<channel>
		<title>${TITLE}</title>
		<link>${DOMAIN}</link>
		<description>${DESCRIPTION}</description>
		<!-- ENTRIES -->
	</channel>
</rss>
EOF
    printSuccess "Success !"
}

addEntry () {
    local TITLE="${1}"
    local LINK="${2}"
    local DESCRIPTION="${3}"
    local FILENAME="${4}"
    feedentry="\\\t<item>\n\t\t<title>${TITLE}</title>\n\t\t<link>${LINK}</link>\n\t\t<description>${DESCRIPTION}</description>\n\t</item>\n"
    sed "/<\!-- ENTRIES -->/a ${feedentry}" -i ${FILENAME}
    if [ "$?" == "0" ]; then
	    printSuccess "Success !"
    else
	    printError "Failed !"
    fi
}

printUsage () {
    printInfo "RSS Feed writer"
    log "This script can create RSS feed XML files and add new entries to them."
    log "The XML file has to be placed on the webserver."
    log "Users will be able to follow with a feed reader."
    log ""
    printInfo "Usage :"
    log ""
    printInfo "create <options> <RSS feed output XML filename>"
    log "creates a new RSS feed XML file."
    log "   -t or --title        : The title of the webpage"
    log "   -D or --domain       : The domain of the feed channel"
    log "   -d or --description  : The description of the feed channel"
    log ""
    printInfo "add <option> <RSS feed output XML filename>"
    log "adds a new entry to an existing RSS feed XML file."
    log "    -t or --title        : The title of the feed entry"
    log "    -l or --link         : The URL to be announced by the new feed entry"
    log "    -d or --description  : The description of the feed entry"
}



# Evaluate command line options
POSITIONAL_ARGS=()
while [[ $# -gt 0 ]]; do
  case $1 in
    -h|--help)
      printUsage
      exit 1
      ;;
    -D|--domain)
      DOMAIN="${2}"
      shift # past argument
      shift # past value
      ;;      
    -t|--title)
      TITLE="${2}"      
      shift # past argument
      shift # past value
      ;;
    -l|--link)
      LINK="${2}"
      shift # past argument
      shift # past value
      ;;
    -d|--description)
      DESCRIPTION="${2}"
      shift # past argument
      shift # past value
      ;;
    -*|--*)
      log "Unknown option $1"
      (return 0 2>/dev/null) && return 1 || exit 1
      ;;
    *)
      POSITIONAL_ARGS+=("$1") # save positional arg
      shift # past argument
      ;;
  esac
done
set -- "${POSITIONAL_ARGS[@]}" # restore positional parameters

# Process operations
case ${1} in
     create)
        if [ "${TITLE}" == "" ]; then
            printError "Title is mandatory !"
            printUsage
            (return 0 2>/dev/null) && return 1 || exit 1
        elif [ "${DOMAIN}" == "" ]; then
            printError "Domain is mandatory !"
            printUsage
            (return 0 2>/dev/null) && return 1 || exit 1
        elif [ "${DESCRIPTION}" == "" ]; then
            printError "Domain is mandatory !"
            printUsage
            (return 0 2>/dev/null) && return 1 || exit 1
        elif [ "${2}" == "" ]; then
            printError "RSS XML output file name is mandatory !"
            printUsage
            (return 0 2>/dev/null) && return 1 || exit 1
        elif [ -f ${2} ]; then
            printError "File ${FILENAME} already exists!"
        else
            createFeed "${TITLE}" "${DOMAIN}" "${DESCRIPTION}" "${2}" 
        fi
      ;;
     add)
        if [ "${TITLE}" == "" ]; then
            printError "Title of feed entry is mandatory !"
            printUsage
            (return 0 2>/dev/null) && return 1 || exit 1
        elif [ "${LINK}" == "" ]; then
            printError "Link of webpage to be feeded is mandatory !"
            printUsage
            (return 0 2>/dev/null) && return 1 || exit 1
        elif [ "${DESCRIPTION}" == "" ]; then
            printError "Description of feed entry mandatory !"
            printUsage
            (return 0 2>/dev/null) && return 1 || exit 1
        elif [ "${2}" == "" ]; then
            printError "File name of RSS feed XML file is mandatory !"
            printUsage
            (return 0 2>/dev/null) && return 1 || exit 1
        elif [ ! -f ${2} ]; then
            printError "File ${FILENAME} does not exist !"
        else
            addEntry "${TITLE}" "${LINK}" "${DESCRIPTION}" "${2}"
        fi             
      ;;
    *)
      printUsage
	  (return 0 2>/dev/null) && return 1 || exit 1
      ;;
esac
(return 0 2>/dev/null) && return 0 || exit 0

Control script for dockered apps

#!/bin/bash
tag="latest"
if [ "${2}" != "" ]; then
	tag="${2}"
fi
name=$(basename ${0} |cut -d "." -f1)
img="ubuntu"
options="-d -t"

mkdir -p /etc/containers/${name}
mkdir -p /var/www/${name}
mkdir -p /var/log/containers/${name}
#########################
echo "Container: ${name}"
if [ "${1}" == "start" ]; then
	echo "Starting"
	docker run --name ${name} ${options} ${img}:${tag} sleep infinity
elif [ "${1}" == "stop" ]; then 
	echo "Stopping"
	docker rm -f ${name}
elif [ "${1}" == "restart" ]; then
	docker rm -f ${name} && docker run --name ${name} ${options} ${img}:${tag}
elif [ "${1}" == "login" ]; then
	docker exec -it ${name} /bin/bash
elif [ "${1}" == "commit" ]; then
	docker commit ${name} ${img}:${tag}
elif [ "${1}" == "load" ]; then
	echo "Loading"
	docker load < ${name}.tar.gz
elif [ "${1}" == "save" ]; then
	echo "Saving"
	docker save ${img}:${tag} | gzip > ${name}.tar.gz
else
	echo "Unknown : ${1}"
	exit 1
fi

Extract GitHub snippets in file

####################################################################
# Snippet 61 : "get_snippets.sh"
# Get your personal Git snippets via the Git-API
# - Using curl for http requests
# - Using jq to parse json
####################################################################
#!/bin/bash
personal_gittoken="your-personal-git-api-token"
jsonout=$(curl --header "PRIVATE-TOKEN: ${personal_gittoken}" "https://git-intern2.ppc-ag.de/api/v4/snippets" 2>/dev/null)
length=$(echo ${jsonout} | jq "length")
for (( id=0; id<${length}; id++ ))
do
	snippetid=$(echo ${jsonout} | jq ".[${id}].id")
	echo "####################################################################"
	echo ${jsonout} | jq -r ".[${id}] | \"# Snippet \(.id) : \\\"\(.file_name)\\\"\n# \(.title)\n# \(.description)\""
	echo "####################################################################"
	curl --header "PRIVATE-TOKEN: ${personal_gittoken}" "https://git-intern2.ppc-ag.de/api/v4/snippets/${snippetid}/raw" 2>/dev/null
	echo ""
done

Python functions for log file filtering

####################################################################
# Snippet 60 : "filterlog.py"
# Logfilter
# To improve : Make `startmatch` sed-compatible
####################################################################
    def get_latest_logline(self, servicelogfile="/var/log/messages.log"):
        """
        @return The latest log line of a log file
        """
        return self.cm.run(f"tail -n1 {servicelogfile}").output.decode('utf-8').strip()

    def wait_for_servicelog(self, searchstring, timeout=180, sleeptime=5, servicelogfile="/var/log/messages.log", startmatch=None):
        """
        Waits for a new line in a log file that contains the given search string
        @param searchstring the string to be found
        @param timeout maximum time in seconds so scan for
        @param sleeptime pause time in seconds between single checks
        @param servicelogfile the full filename of the logfile to scanned
        @param startmatch The search considers all lines AFTER startmatch. If not given, the last logline will be taken
        @return the whole line containing the searchstring if found, else None
        """
        starttime = time.time()
        if startmatch is not None:
            #self.log.info(f"Taking given startmatch {startmatch}")
            latestline = startmatch
        else:
            #self.log.info("Gathering latest log line as start match")
            latestline = self.get_latest_logline(servicelogfile)
        #self.log.info(f"Using Start match : {latestline}")
        while True:
            now = time.time()
            output = self.cm.run(f"tail -n100 {servicelogfile} | sed -n '/{latestline}/,$p' | grep \"{searchstring}\" | tail -n1").output.decode('utf-8').strip()
            if len(output)>0:
                self.log.info(f"Search string \"{searchstring}\" FOUND in log {servicelogfile} : {output}")
                return output
            else:
                if (now-starttime) > timeout:
                    self.log.info(f"Search string \"{searchstring}\" NOT FOND in log {servicelogfile}, timeout!")
                    return None
                else:
                    self.log.info(f"Search string \"{searchstring}\" not found in log {servicelogfile}, remaining {timeout-now+starttime} secs")
                time.sleep(sleeptime)

Logging Macro for C

//####################################################################
//# Snippet 57 : "logging.h"
//# Logger Makro for C
//# 
//####################################################################
#define errout(msg, ...) fprintf(stderr, "%s:%d (%s) : " msg, \
    __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__)

Match a regular expression in C

//####################################################################
//# Snippet 56 : "regexmatch.c"
//# Get regex group match in C
//# 
//####################################################################
int getmatch(char *searchstring, char *regex, char *result, int maxsize)
{
	size_t maxGroups = 2;
	regex_t regexCompiled;
	regmatch_t groupArray[maxGroups];
	int len = 0;
	
	if (result == NULL)
	{
		perror("Invalid result pointer for regex\n");
		return -1;
	}

	memset(result, 0, maxsize);
	if (regcomp(&regexCompiled, regex, REG_EXTENDED))
	{
		perror("Could not compile regular expression\n");
		return -1;
	};

	if (regexec(&regexCompiled, searchstring, maxGroups, groupArray, 0) == 0)
	{
		if (groupArray[1].rm_so != (size_t)-1)
		{
			len = groupArray[1].rm_eo - groupArray[1].rm_so;
			if (len > maxsize)
			{
				len = maxsize - 1;
			}
			memcpy(result, searchstring + groupArray[1].rm_so, len);
		}
		else
		{
			perror("Regex did not match\n");
		}
	}

	regfree(&regexCompiled);
	return len;
}

Execute shell command and consume output in C

//####################################################################
//# Snippet 55 : "readcommand.c"
//# Execute shell command in C with catching results into string buffer
//# 
//####################################################################
int readcommand(char *command, char *buff, int maxlen)
{
	char ch;
	int i;
	FILE *fp;

	i = 0;
	fp = popen(command, "r"); // read mode
	if (fp == NULL)
	{
		perror("Error while opening command\n");
		return -1;
	}
	while ((ch = fgetc(fp)) != EOF)
	{
		if (i < maxlen)
		{
			buff[i] = ch;
			i++;
		}
		else
		{
			perror("Buffer full\n");
			break;
		}
	}
	fclose(fp);
	return 0;
}

MAC address calculations

####################################################################
# Snippet 54 : "calc_macaddr.sh"
# MAC address calculations and transformations
# 
####################################################################
#
# This function adds an offset to a MAC address
# ${1} = MAC address
# ${2} = offset to be added to the MAC address
function add_to_macaddr {
    mac=$(echo ${1} |  /bin/tr '[:lower:]' '[:upper:]' | /bin/tr -d ':') # upper case and remove :
    macdec=$( /bin/printf '%d\n' 0x${mac} )                              # convert to decimal
    macadd=$( expr ${macdec} + ${2} )                                    # add offset
    machex=$( /bin/printf '%012X\n' ${macadd} )                          # convert to hex
    macnew=$(echo ${machex} | /bin/sed 's/../&:/g;s/:$//')               # put it in the right notation.
    echo ${macnew}
}

Simple socket implementation in C

//####################################################################
//# Snippet 52 : "sockets.c"
//# TCP / UDP socket communication
//# This snippet is a suggestion for some TCP or UDP clients or servers.
//Additionally to the standard snippets which you can easily find in the internet I have worked out solutions for some pitfalls here (especially in the UDP communication) that I met during the clshks3proxy implementation in the libCLS
//####################################################################
//////////////////////////////////////////////////////////////////////////////////
//                                                                              //
//  Simple TCP / UDP socket communication snippet                               //
//  @author : g.raudenbusch                                                     //
//                                                                              //  
//////////////////////////////////////////////////////////////////////////////////

#include <unistd.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/time.h>

#define TCP_PROTOCOL_ID 6
#define UDP_PROTOCOL_ID 17

// Note: The very small packet size here ist just used for testing purposes,
// practically something like 16384 or 65536 speeds up the transfer
#define PKT_SIZE 128

/**
 * Note: The OS can sometimes prevent correct UDP transfer of large data.
 * To fix that, the adaption of the following sysctl parameters has 
 * helped me :
 * 
 *  echo 26214400 >/proc/sys/net/core/rmem_max
 *  echo 26214400 >/proc/sys/net/core/rmem_default
**/

/**
 * This structue contains all variables that are needed 
 * for the basic socket communication
 */
typedef struct socketParams
{
    int protocol_id;             // The protocol id
    char *ipaddr;                // IP address
    int port;                    // Port number
    int sockfd;                  // Socket descriptor
    int connfd;                  // Socket descriptor for TCP connections
    struct sockaddr_in sockaddr; // Socket address
} socketParameters;

// [ Library functions ] //////////////////////////////////////////////////////////////////

/**
 * This helper function dumps out the socket structure content
 * @param params pointer to socket structure
 */
#ifdef DEBUG
static void sock_dumpSocketParams(socketParameters *params)
{
    if (!params)
    {
        printf("Params = NULL!\n");
        return;
    }

    if (params->protocol_id == TCP_PROTOCOL_ID)
    {
        printf("Protocol = TCP\n");
    }
    else if (params->protocol_id == UDP_PROTOCOL_ID)
    {
        printf("Protocol = UDP\n");
    }
    else
    {
        printf("Unknown protocol ID!\n");
    }

    printf("ipaddr = %s\n", params->ipaddr);
    printf("port = %d\n", params->port);
    printf("sockfd = %d\n", params->sockfd);
    printf("connfd = %d\n", params->connfd);
}
#endif // DEBUG

/**
 * This function initializes the socket, binds it to an IP and port and sets the receive timeout 
 * @param pSocketParams pointer to the structure containing the socket configuration
 * @param asServer if set > 0 the socket will be bound for further usage as server 
 * @return socket descriptor on success, else negative value
 */
static int sock_init(socketParameters *pSocketParams, int asServer)
{
    int sockfd = -1;
    int retval = 0;
    struct timeval tv;

    if (pSocketParams == NULL)
    {
        fprintf(stderr, "Error, no thread params!\n");
        return -1;
    }
    pSocketParams->connfd = -1;

    do
    {
        // Use timeout of 1 sec.
        tv.tv_sec = 1;
        tv.tv_usec = 0;
        // Create the socket
        if (pSocketParams->protocol_id == TCP_PROTOCOL_ID)
        {
            fprintf(stderr, "Initializing TCP socket\n");
            sockfd = socket(AF_INET, SOCK_STREAM, pSocketParams->protocol_id);
        }
        else if (pSocketParams->protocol_id == UDP_PROTOCOL_ID)
        {
            fprintf(stderr, "Initializing UDP socket\n");
            sockfd = socket(AF_INET, SOCK_DGRAM, pSocketParams->protocol_id);
        }
        else
        {
            fprintf(stderr, "Invalid protocol id %d\n", pSocketParams->protocol_id);
            break;
        }

        if (sockfd < 0)
        {
            fprintf(stderr, "Cannot create socket: %s", strerror(errno));
            break;
        }

        memset(&(pSocketParams->sockaddr), 0, sizeof(struct sockaddr_in));
        pSocketParams->sockaddr.sin_family = AF_INET;
        pSocketParams->sockaddr.sin_addr.s_addr = inet_addr(pSocketParams->ipaddr);
        pSocketParams->sockaddr.sin_port = htons(pSocketParams->port);

        if (asServer > 0)
        {
            // Bind to the address to the socket
            fprintf(stderr, "Binding socket\n");
            retval = bind(sockfd, (const struct sockaddr *)&(pSocketParams->sockaddr), sizeof(struct sockaddr_in));
            if (retval != 0)
            {
                fprintf(stderr, "Could not bind socket to %s:%u, error %s, aborting\n", pSocketParams->ipaddr, pSocketParams->port, strerror(errno));
                break;
            }

            // Set the socket option: timeout on receive
            fprintf(stderr, "Setting receive timeout of %ld seconds for socket\n", tv.tv_sec);
            retval = setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval));

            // Enable socket reuse (optional)
            int optval = 1;
            setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval, sizeof(int));

            // For testing purposes : Set nonblocking
            //int status = fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL, 0) | O_NONBLOCK);
        }
    } while (0);

    // If mandatory socket operations failed, close it and retun -1
    if (retval != 0)
    {
        fprintf(stderr, "Error occured, closing socket finally\n");
        shutdown(sockfd, SHUT_RDWR);
        close(sockfd);
        sockfd = -1;
    }
    pSocketParams->sockfd = sockfd;
    if (pSocketParams->protocol_id == UDP_PROTOCOL_ID)
    {
        // UDP isn't connection based
        pSocketParams->connfd = sockfd;
    }
    return sockfd;
}

/**
 * Sends the buffer content to the destination
 * @param pSocketParams pointer to the structure containing the socket configuration
 * @param buf pointer to the message to be sent
 * @param lentosend length in bytes to send
 * @return the length of successfully sent bytes or -1 on errors
 */
static int sock_send(socketParameters *pSocketParams, char *buf, int lentosend)
{
    ssize_t len = 0;
    socklen_t socklen = sizeof(struct sockaddr);

    if (pSocketParams->protocol_id == TCP_PROTOCOL_ID)
    {
        len = write(pSocketParams->connfd, (void *)buf, lentosend);
    }
    else if (pSocketParams->protocol_id == UDP_PROTOCOL_ID)
    {
        len = sendto(pSocketParams->connfd, (void *)buf, lentosend, 0, (struct sockaddr *)&(pSocketParams->sockaddr), socklen);
    }
    else
    {
        fprintf(stderr, "Invalid protocol id %d\n", pSocketParams->protocol_id);
    }
    return len;
}

/**
 * Receives content from socket into the destinated buffer
 * @param pSocketParams pointer to the structure containing the socket configuration
 * @param buf pointer to receive buffer
 * @param tries amount of tries in case of errors
 * @return the length of received bytes or -1 on errors
 */
static int sock_recv(socketParameters *pSocketParams, char *buf, int tries)
{
    ssize_t len = -1;
    socklen_t socklen = sizeof(struct sockaddr);
    if (tries < 1)
    {
        tries = 1;
    }

    while (len < 0)
    {
        if (pSocketParams->protocol_id == TCP_PROTOCOL_ID)
        {
            fprintf(stderr, "sock_recv : read() from TCP socket\n");
            errno = 0;
            len = read(pSocketParams->connfd, (void *)buf, PKT_SIZE);
        }
        else if (pSocketParams->protocol_id == UDP_PROTOCOL_ID)
        {
            fprintf(stderr, "sock_recv : read() from UDP socket\n");
            errno = 0;
            // NOTE : When the source sends a datagram bigger than your receive buffer size,
            // the rest of the UDP datagram will be lost forever!! But it is possible that
            // the source sends multiple datagrams smaller/equal than your receive buffer size.
            // These can be get by calling recvfrom multiple times.
            len = recvfrom(pSocketParams->connfd, (void *)buf, PKT_SIZE, 0, (struct sockaddr *)&(pSocketParams->sockaddr), &socklen);
        }
        else
        {
            fprintf(stderr, "Invalid protocol id %d\n", pSocketParams->protocol_id);
        }

        if (len < 0)
        {
            // Do some error handling
            if (EAGAIN == errno && --tries)
            {
                fprintf(stderr, "sock_recv : Socket timeout, %d tries left\n", tries);
            }
            else if (EINTR == errno)
            {
                fprintf(stderr, "sock_recv : Interrupted by signal\n");
            }
            else
            {
                // client has nothing (more) to say
                fprintf(stderr, "sock_recv : Unhandled errno %s\n", strerror(errno));
                break;
            }
        }
    }
    return len;
}

/**
 * Listens for TCP connections 
 * @param pSocketParams pointer to the structure containing the socket configuration
 * @return 0 on success, else -1
 */
static int sock_listen(socketParameters *pSockparams)
{
    return listen(pSockparams->sockfd, 1);
}

/**
 * Accepts a new TCP connection on the server side
 * @param pSocketParams pointer to the structure containing the socket configuration
 * @return the file descriptor of the new connection on success, else -1
 */
static int sock_accept(socketParameters *pSockparams)
{
    pSockparams->connfd = accept(pSockparams->sockfd, NULL, NULL);
    return pSockparams->connfd;
}

/**
 * Starts a new TCP connection on the client side
 * @param pSocketParams pointer to the structure containing the socket configuration
 * @return 0 on success, else -1
 */
static int sock_connect(socketParameters *pSockparams)
{
    int retval = -1;
    retval = connect(pSockparams->sockfd, (const struct sockaddr *)&(pSockparams->sockaddr), sizeof(struct sockaddr_in));
    if (retval >= 0)
    {
        pSockparams->connfd = pSockparams->sockfd;
    }
    return retval;
}

// [ Example implementations ] //////////////////////////////////////////////////////////////////

/**
 * Opens a TCP server
 * @param addr IP adress of server
 * @param port TCP port of server
 * @return -1 on errors
 */
static int sock_tcpserver(char *addr, int port)
{
    socketParameters sockparams;
    int len = -1;
    char buf[PKT_SIZE];

    sockparams.protocol_id = TCP_PROTOCOL_ID;
    sockparams.ipaddr = addr;
    sockparams.port = port;
    memset(buf, 0, PKT_SIZE);

    if (sock_init(&sockparams, 1) < 0)
    {
        return -1;
    }

    if (sock_listen(&sockparams) < 0)
    {
        return -1;
    }

    while (1) // Run server until CTRL-C pressed
    {
        while (1) // Waiting for valid client connection
        {
            if (sock_accept(&sockparams) < 0)
            {
                // Timeout
                fprintf(stderr, "No new client connection: %s\n", strerror(errno));
                sleep(1);
                continue;
            }
            break;
        }

        // Here we should have a new connection
        while (1) // Run as long as the client keeps the connection up
        {
            if (sockparams.connfd < 0)
            {
                fprintf(stderr, "Client connection has been closed in between\n");
                break;
            }

            fprintf(stderr, "Reading from client\n");
            memset(buf, 0, PKT_SIZE);
            len = sock_recv(&sockparams, buf, 3);
            if (len <= 0)
            {
                // client has nothing (more) to say
                fprintf(stderr, "No more packets from client\n");
                break;
            }
            else
            {
                // Here you can to different stuff, i.E. appending the packet content
                // to a global buffer. For testing purposes we are just printing it here
                fprintf(stdout, "Client sent (%d): %s\n", len, buf);
            }
        }
        close(sockparams.connfd);
    }
    close(sockparams.sockfd);
    return 0;
}

/**
 * Connects to a TCP server and sends some data
 * @param addr IP adress of server
 * @param port TCP port of server
 * @param msg some message
 * @param msglen the length of the message to send
 * @return -1 on errors, else 0
 */
static int sock_tcpclient(char *addr, int port, char *msg, int msglen)
{
    socketParameters sockparams;
    int totalsent = 0;
    int retval = 0;

    sockparams.protocol_id = TCP_PROTOCOL_ID;
    sockparams.ipaddr = addr;
    sockparams.port = port;

    if (sock_init(&sockparams, 0) < 0)
    {
        return -1;
    }

    // connect the client socket to server socket
    retval = sock_connect(&sockparams);
    if (retval < 0)
    {
        fprintf(stderr, "No connection: %s\n", strerror(errno));
        return -1;
    }
    else
    {
        fprintf(stderr, "Connected to server\n");
    }

    printf("msg = %s, msglen = %d, totalsent = %d\n", msg, msglen, totalsent);
    while (totalsent < msglen)
    {
        // Because this is TCP, we can use the full message length here in sock_send
        retval = sock_send(&sockparams, &msg[totalsent], msglen);
        if (retval < 0)
        {
            fprintf(stderr, "Send error: %s\n", strerror(errno));
            break;
        }
        else
        {
            fprintf(stderr, "Sent %d bytes\n", retval);
            totalsent += retval;
        }
    }
    fprintf(stderr, "Closing socket\n");
    close(sockparams.sockfd);
    return 0;
}

/**
 * Opens a UDP server
 * @param addr IP adress of server
 * @param port UDP port of server
 * @return -1 on errors
 */
static int sock_udpserver(char *addr, int port)
{
    socketParameters sockparams;
    int len = -1;
    char buf[PKT_SIZE];

    sockparams.protocol_id = UDP_PROTOCOL_ID;
    sockparams.ipaddr = addr;
    sockparams.port = port;

    if (sock_init(&sockparams, 1) < 0)
    {
        return -1;
    }

    while (1) // Run server until CTRL-C pressed
    {
        if (sockparams.sockfd < 0)
        {
            sock_init(&sockparams, 1);
            if (sockparams.sockfd < 0)
            {
                // Failed to initialize socket
                fprintf(stderr, "Could not initialize socket: %s\n", strerror(errno));
                sleep(1);
                continue;
            }
        }
        else
        {
            fprintf(stderr, "Reusing UDP socket %d\n", sockparams.sockfd);
        }

        memset(buf, 0, PKT_SIZE);
        len = sock_recv(&sockparams, buf, 3);
        if (len == 0)
        {
            fprintf(stderr, "Read 0 bytes, peer has performed an orderly shutdown\n");
            break;
        }
        else if (len < 0)
        {
            fprintf(stderr, "Nothing read from client\n");
            sleep(1);
        }

        // Do what you like with the data here :
        fprintf(stdout, "Client sent (%d): %s\n", len, buf);
    }
    close(sockparams.sockfd);
    return 0;
}

/**
 * Connects to a UDP server and sends some data
 * @param addr IP adress of server
 * @param port UDP port of server
 * @param msg some message
 * @param msglen the length of the message to send
 * @return -1 on errors, else 0
 */
static int sock_udpclient(char *addr, int port, char *msg, int msglen)
{
    socketParameters sockparams;
    int totalsent = 0;
    int tosend = msglen;
    int retval = 0;

    sockparams.protocol_id = UDP_PROTOCOL_ID;
    sockparams.ipaddr = addr;
    sockparams.port = port;

    if (sock_init(&sockparams, 0) < 0)
    {
        return -1;
    }

    while (totalsent < msglen)
    {
        // NOTE: The overlength data of a UDP datagram (when the sent datagram is greater 
        // than the receive buffer for it on the other side) will NEVER be processed by 
        // the receiver and gets lost forever!
        // This is why we use PKT_SIZE here in sock_send as maximum and not msglen 
        tosend = (msglen - totalsent) > PKT_SIZE ? PKT_SIZE : (msglen - totalsent);
        retval = sock_send(&sockparams, &msg[totalsent], tosend);
        if (retval < 0)
        {
            fprintf(stderr, "Send error: %s\n", strerror(errno));
            break;
        }
        else
        {
            fprintf(stderr, "Sent %d bytes\n", retval);
            totalsent += retval;
        }
    }
    close(sockparams.sockfd);
    return 0;
}

// [ Main function to test the example implementations ] ////////////////////////////////////////
// Example calls :
// ./yourfilename server tcp 127.0.0.1 12345
// ./yourfilename client tcp 127.0.0.1 12345 Hello123
int main(int argc, char **argv)
{
    if (argc < 5)
    {
        fprintf(stderr, "Too few arguments\n");
        return -1;
    }

    if (strcmp(argv[1], "server") == 0)
    {
        if (strcmp(argv[2], "tcp") == 0)
        {
            return sock_tcpserver(argv[3], atoi(argv[4]));
        }
        else if (strcmp(argv[2], "udp") == 0)
        {
            return sock_udpserver(argv[3], atoi(argv[4]));
        }
        else
        {
            fprintf(stderr, "Argument 2 must be 'tcp' or 'udp'\n");
        }
    }
    else if (strcmp(argv[1], "client") == 0)
    {
        if (strcmp(argv[2], "tcp") == 0)
        {
            return sock_tcpclient(argv[3], atoi(argv[4]), argv[5], strlen(argv[5]));
        }
        else if (strcmp(argv[2], "udp") == 0)
        {
            return sock_udpclient(argv[3], atoi(argv[4]), argv[5], strlen(argv[5]));
        }
        else
        {
            fprintf(stderr, "Argument 2 must be 'tcp' or 'udp'\n");
        }
    }
    else
    {
        fprintf(stderr, "Argument 1 must be 'client' or 'server'\n");
    }
}
//####################################################################
//# Snippet 51 : "bufferdump.c"
//# Output hexdump
//# This snippet outputs a hexdump of a memory area. It is very useful for debugging purposes.
//####################################################################
/**
 * Prints out a hexdump
 */
void bufferdump(const unsigned char *buff, int size, char* title)
{
	int col, line, linecount, linelen;

	printf("************* HEXDUMP (%s) *************\n", title);
	linecount = size / 16 + (size % 16 > 0);
	for (line = 0; line < linecount; line++)
	{
		linelen = (line == linecount - 1) ? 16 * (size % 16 == 0) + size % 16 : 16;
		printf("%p | ", buff + line * 16);
		for (col = 0; col < 16; col++)
		{
			if (col < linelen)
			{
				printf("%02x ", buff[16 * line + col]);
			}
			else
			{
				printf("   ");
			}
		}
		printf(" | ");

		for (col = 0; col < 16; col++)
		{
			char c;

			if (col < linelen)
			{
				c = buff[16 * line + col];
			}
			else
			{
				c = ' ';
			}

			if (c < 32)
			{
				c = '.';
			}
			printf("%c", c);

		}
		printf("\n");

	}
	printf("*********** HEXDUMP END (%s) ***********\n", title);
}
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <mqueue.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/if.h>

/**
 * This function gets the hardware address (MAC) of a named ethernet interface.
 * @param  intf_asc    input parameter, string containing the interface name (i.e. "eth0")
 * @param  mac_asc     output parameter, pointer to the hex ascii MAC address string, minimum length 13 char.
 * @return             0 on success else error code
 */
int32_t get_macaddr( const char* intf_asc, char* mac_asc)
{
    int iRet = 0;
    int sock = -1;
    int i    = 0;
    struct ifreq sintf;
    size_t len = 0;

    do{
        /* Checking parameters. */
        if(!intf_asc && !mac_asc){
            iRet = -EINVAL;
            break;
        }
        len = strlen(intf_asc);
        /* Special check for the interface name. */
        if((len < 1) || (len > IFNAMSIZ)){
            iRet = -EINVAL;
            break;
        }
        /* Open a socket file descriptor just to get the interface parameters. */
        sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
        if(sock < 0){
            iRet = -EIO;
            break;
        }
        /* Get the interface MAC address from the lowest depth of the kernel. */
        strcpy(sintf.ifr_name, intf_asc);
        iRet = ioctl(sock, SIOCGIFHWADDR, &sintf);
        if(iRet != EXIT_SUCCESS){
            break;
        }
        /* Build the hex ascii reprezentation of the MAC address. */
        for(i = 0; i < 6; i++){
            sprintf((mac_asc+(2*i)), "%02x", (unsigned char)sintf.ifr_addr.sa_data[i]);
        }
    }while(0);
    /* Close the socket to not leak descriptors. */
    if( sock >= 0) close(sock);
    return iRet;
}

Parse file and process functions with bash

####################################################################
# Snippet 49 : "testrunner.sh"
# LyraBox
# This script implements # some basic functions. Then it reads in a textfile which calls that basic functions like organ pipes in a lyrabox as scripted in the textfile
# 
# Very useful for functional integration testing with different permutations of the function order.
####################################################################
#!/bin/bash

# [ Functions to be triggered ] ######################################################
function setmode {
    echo "Setting mode ${1}"
    return $?
}

# [ Main processing ] ######################################################

# All parameters present ?
if [ $# -lt 1 ]; then
    echo "Parameters missing"
    echo "Usage $0 <text file containing script commands>"
    exit 1
fi
testscript=${1}
test_failed=0

# Start reading script
while IFS= read -r line
do
    # Ignore too short lines
    if [ "${#line}" -lt "4" ]; then
        echo ${line}
        continue
    fi
    
    # Ignore comment lines starting with '#'
    if [[ ${line:0:1} == "#" ]]; then
        echo ${line}
        continue
    fi
    
    # Process mode change command
    # Syntax : MODE=X
    if [[ ${line:0:5} == "MODE=" ]]; then
        # This reads only one character
        mode=${line:5:1}
        # This reads all remaining chars till end
        mode=${line:5}
        setmode ${mode}
        result=$?
        if [ "${result}" != "0" ]; then
            test_failed=1   
            break
        fi
        continue
    fi
done < ${testscript}

if [[ "${test_failed}" != "0" ]]; then
    echo "A test has failed!"
    exit 1
else
    echo "All tests executed without errors"
fi
exit 0

Longtime recording of top outputs

####################################################################
# Snippet 48 : "topit.sh"
# Record longtime trace of CPU load for selected processes
# 
####################################################################
#!/bin/sh

# Traces the CPU load for selected services

SERVICES="Service1 Service2 Service3"  
RESULTFILE="/usr/local/tmp/topresult.txt"

write_headline() {
	RESULT="timestamp"
        for s in $SERVICES                                                                                                   
        do                
		RESULT="${RESULT};${s}"               
        done                     
        echo $RESULT >$RESULTFILE
}


get_topvalues() {
	TOPFILE="/tmp/top-snapshot.txt"
	RESULT=""
	rm -f ${TOPFILE}
	TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
	top -b -n1 >$TOPFILE
	RESULT=${TIMESTAMP}
	for s in $SERVICES
	do
		SINGLERES=$(cat $TOPFILE | grep "/usr/local/bin/$s" | grep -v "grep" | grep -v "tail" | awk ' { print $8 } ')
		RESULT="${RESULT};${SINGLERES}"
	done
	echo $RESULT >>$RESULTFILE
}

write_headline
while true
do 
	get_topvalues
	sleep 5
done

FIFO implementation in C

//####################################################################
//# Snippet 47 : "fifo_read.c"
//# Sending data via FIFO from command line console to daemonized processes
//# While a simple command line program can read data piped into it ( i.E. with `echo "blabla" | myprogram` ) from console by reading stdin ( i.E. `while (!std::getline(std::cin, inputline).eof())` ), this is not possible for a daemon process. For that purpose the daemon process can open a FIFO instead to receive data from the command line. The suggested function is destinated to be implemented into the daemon process. The FIFO node will then appear in the /tmp folder and you can directly echo or cat something to it.
####################################################################
#define FIFONODE "/tmp/myinput"

/**
 * This function returns the current time in usecs
 * @return time in usecs
 */
uint64_t get_usecs()
{
    uint64_t result;
    struct timeval tv;
    gettimeofday(&tv, NULL);
    result = tv.tv_sec * (uint64_t)1000000 + tv.tv_usec;
    return result;
}

/**
 * This function reads from FIFO and initially also creates it.
 * @param fifofd pointer to FIFO file descriptor
 * @param serbuf the receive buffer
 * @param uSampleSize the awaited count of bytes to be read
 * @param uSampleRate the time in usecs until the read times out
 * @return number of bytes read or -1 when timed out
 */
int fifo_read(int *fifofd, uint8_t *serbuf, uint32_t uSampleSize, uint32_t uSampleRate)
{
    int iGet = 0;       // Return value
    uint32_t total = 0; // Count of bytes read from FIFO
    uint64_t starttime = get_usecs();

    // Read from FIFO
    if (*fifofd < 0)
    {
        printf("Creating FIFO '%s'\n", FIFONODE);
        mkfifo(FIFONODE, 0666);
        *fifofd = open(FIFONODE, O_RDONLY | O_NONBLOCK);
    }

    total = 0;
    iGet = -1;
    memset(serbuf, 0, MAX_DATA_LEN);
    while ((iGet <= 0) && (total < uSampleSize) && (get_usecs() - starttime) < uSampleRate)
    {
        iGet = read(*fifofd, &serbuf[total], uSampleSize);
        if (iGet > 0)
        {
            total += iGet;
        }
    }
    return iGet;
}

// Example Usage :
int fifofd = -1;
uint8_t serbuf[MAX_DATA_LEN] = { 0 };
char* debug_serial = getenv("DEBUGFLAG"); // to set with 'export DEBUGFLAG=1'

if (debug_serial)
{
    int iGet = fifo_read(&fifofd, serbuf, 123, 1000*1000*1000);
    if (iGet > 0)
    {
        printf("Read %d chars from '%s' : %s\n", iGet, FIFONODE, serbuf);
    }
}

Get expiration dates of certificates

####################################################################
# Snippet 46 : "grabCertDates.sh"
# Get validity window of TLS certificates
# 
####################################################################
#!/bin/sh
#
# Copyright OpenLimit SignCubes AG, 2019
#
# Helper script to grab certificate validity period(s)


prg="$0"

optCSV="n"
optDir=""
optFile=""
dateNow=""

showHelp()
{
cat <<EOF

Helper script to find certificates and grab their validity periods

Usage: ${prg} [options]
    -h, --help  ........  show this help
    -c, --csv  .........  create comma-separated list items for csv import
  * -d <dir>  ..........  base directory for searching (recursively)
  or
  * -f <file>  .........  single file to be used
    -m, --mark  ........  mark expired items

  * ........  required parameter
EOF
}

while [ $# -ne 0 ] ; do
  case ${1} in
    "-h"|"--help")
      showHelp
      exit 0
      ;;
    "-c"|"--csv")
      optCSV="y"
      ;;
    "-d")
      optDir="${2}"
      if [ ! -d "${optDir}" ] ; then
        echo "Error - directory not found: '${optDir}'"
        exit 1
      fi
      shift 1
      ;;
    "-f")
      optFile="${2}"
      if [ ! -r "${optFile}" ] ; then
        echo "Error - file not found: '${optFile}'"
        exit 1
      fi
      shift 1
      ;;
    "-m"|"--mark")
      dateNow="`date -u +\"%Y-%m-%d %H:%M:%S\"`"
      ;;
    *)
      showHelp
      exit 1
      ;;
  esac
  shift 1
done


OSSL="`which openssl`"
OSSLOPT="x509 -noout -dates"
OSSLOPTDER="-inform DER"
OSSLOPTPEM="-inform PEM"
if [ -z "${OSSL}" ] ; then
  echo "Error - openssl binary not found but required, please install and/or adopt PATH"
  exit 1
fi

listFile="`mktemp`"
optQuit="n"

createListFile()
{
  if [ ! -z "${optFile}" ] ; then
    echo "${optFile}" > ${listFile}
  else
    find ${optDir} -type f | sort > ${listFile}
  fi
  #echo "`ls -lsa ${listFile}`" >&2
  #cat ${listFile} >&2
}

checkExpiration()
{
  dtChk=$(date -d "${1}" +%s)
  dtNow=$(date -d "${dateNow}" +%s)
  #echo "Checking expiration of date '${1} - ${dtChk} against now (${dtNow})'" >&2
  if [ ${dtChk} -lt ${dtNow} ] ; then
    echo "expired"
  else
    if [ "y" = "${optCSV}" ] ; then
      echo ""
    else
      echo "       "
    fi
  fi
}

grabDate()
{
  if [ ! -r "${1}" ] ; then
    echo "Failed read of '${1}'"
    return
  fi
  osslCmdDER="${OSSL} ${OSSLOPT} ${OSSLOPTDER} -in ${1}"
  osslCmdPEM="${OSSL} ${OSSLOPT} ${OSSLOPTPEM} -in ${1}"
  dates="`${osslCmdDER} 2>/dev/null`"
  if [ -z "${dates}" ] ; then
    dates="`${osslCmdPEM} 2>/dev/null`"
  fi
  if [ -z "${dates}" ] ; then
    return
  fi
  #echo "dates: '${dates}'"
  notBefore="`echo -n ${dates} | sed -e 's/notBefore=//g' -e 's/ notAfter.*//g' | date -u +\"%Y-%m-%d %H:%M:%S\" -f -`"
  notAfter="`echo -n ${dates} | sed -e 's/.*notAfter=//g' | date -u +\"%Y-%m-%d %H:%M:%S\" -f -`"
  markExp=""
  if [ ! -z "${dateNow}" ] ; then
    markExp=$(checkExpiration "${notAfter}")
  fi
  if [ "y" = "${optCSV}" ] ; then
    echo "${markExp},${notBefore},${notAfter},${1}"
  else
    echo "${markExp}  ${notBefore}  ${notAfter}  ${1}"
  fi
}

prtHeader()
{
  if [ "y" = "${optCSV}" ] ; then
    if [ ! -z "${dateNow}" ] ; then
      echo "Called at,${dateNow},,pwd: `pwd`"
      echo ",,,"
      echo "Expired,Not before,Not after,File name"
    else
      echo "Not before,Not after,File name"
    fi
  else
    if [ ! -z "${dateNow}" ] ; then
      echo "Expired  Not before           Not after            File name"
    else
      echo "Not before           Not after            File name"
    fi
  fi
}

grabDates()
{
  if [ ! -s ${listFile} ] ; then
    return
  fi

  prtHeader

  while IFS=  read -r filename ; do
    if [ "y" = "${optQuit}" ] ; then
      break
    fi
    grabDate "${filename}"
  done < ${listFile}
}

stopScript()
{
  optQuit="y"
  #echo "${prg}: stopScript called" >&2
}

trap stopScript INT QUIT TERM

createListFile
grabDates

rm -f ${listFile}


# EOF

Get git logs

####################################################################
# Snippet 45 : "get_gitlogs.sh"
# Get Git logs
# 
####################################################################
#!/bin/bash
echo "Date               |Author              |Hash   |Subject"
git log --no-merges --date=format:'%Y-%m-%d %H:%M:%S' --pretty=format:"%C(green)%ad|%C(yellow)%<(20)%cn|%C(reset)%h|%C(white bold)%s" $@

Plot 1-dimensional cellular automata in python

####################################################################
# Snippet 44 : "cellular.py"
# Wolfram automata
# 
####################################################################
#!/usr/bin/python3
from __future__ import division
import sys
import numpy as np
import matplotlib.pyplot as plt

if __name__ == "__main__":
    rule = sys.argv[1]
    w = 1000
    r = s = [0] * w
    r[int(w/2)] = 1
    d = 0
    xlist = []
    ylist = []
    fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(18, 10))

    for j in range(0, int(w/2)):
        n = (r[0] << 1) + r[1]
        for i in range(1, w):
            if r[i] == 1:
                xlist.append(i)
                ylist.append(d)
        for i in range(2, w):
            n = (n << 1) + r[i]
            if n >= 8:
                n -= 8
            s[i-1] = (int(rule) >> n) % 2
        r = s
        d += 1
    plt.plot(xlist, ylist, ",k")
    plt.savefig("cellular.png")
    plt.show()

Perceptron in python

####################################################################
# Snippet 43 : "perceptron.py"
# Perceptron
# 
####################################################################
#!/usr/bin/python3
from numpy import array, random, dot
from random import choice
from pylab import ylim, plot
from matplotlib import pyplot as plt

# Aktivierungsfunktion

def step_function(x): return 0 if x < 0 else 1

# Trainingsdaten
training_dataset = [
    (array([0, 0, 1]), 0),
    (array([0, 1, 1]), 1),
    (array([1, 0, 1]), 1),
    (array([1, 1, 1]), 1),
]
weights = random.rand(3)
error = []
learning_rate = 0.2
n = 100
# Training
for j in range(n):
    x, expected = choice(training_dataset)  # Zufälligen Datensatz wählen
    result = dot(weights, x)               # Skalarprodukt bilden
    err = expected - step_function(result)  # Fehler berechnen
    error.append(err)
    weights += learning_rate * err * x     # Gewichte anpassen
# Abrufen der gelernten Inhalte
for x, _ in training_dataset:
    result = dot(x, weights)
    print("{}: {} -> {}".format(x[:2], result, step_function(result)))
# Plot der Fehler
ylim([-1, 1])
plot(error)
plt.show()

Shortest crashing C program

//####################################################################
//# Snippet 42 : "crashtest.c"
//# Shortest crashing C program
//# 
//####################################################################
main;

Plot mandelbrot in python

####################################################################
# Snippet 41 : "plot_mandelbrot_readable.py"
# Mandelbrot (more readable)
# 
####################################################################
#!/usr/bin/python3


import matplotlib.pyplot as plt
import numpy as np

def mandelbrot_set(width, height, zoom=1, x_off=0, y_off=0, niter=256):
    """ A mandelbrot set of geometry (width x height) and iterations 'niter' """

    w,h = width, height
    pixels = np.arange(w*h, dtype=np.uint16).reshape(h, w)

    # The mandelbrot set represents every complex point "c" for which
    # the Julia set is connected or every julia set that contains
    # the origin (0, 0). Hence we always start with c at the origin.

    for x in range(w): 
        for y in range(h):
            # calculate the initial real and imaginary part of z,
            # based on the pixel location and zoom and position values
            # We use (x-3*w/4) instead of (x-w/2) to fully visualize
            # the fractal along the x-axis
            
            px = 1.5*(x + x_off - 3*w/4)/(0.5*zoom*w)
            py = 1.0*(y + y_off - h/2)/(0.5*zoom*h)
            
            c = complex(px, py)
            z = complex(0, 0)
            
            # Julia :
            #z = complex(px, py)
            #c = complex(-0.4, 0.6)
            
            for i in range(niter):
                if abs(z) > 4: break
                # Iterate till the point c is outside
                # the circle with radius 2.             
                # Calculate new positions
                z = z**2 + c

            color = (i << 21) + (i << 10)  + i * 8
            pixels[y,x] = color
  
    return pixels

def display(width=1024, height=768, zoom=1.0, x_off=0, y_off=0, cmap='magma'):
    """ Display a mandelbrot set of width `width` and height `height` and zoom `zoom`
    and offsets (x_off, y_off) """

    pixels = mandelbrot_set(width, height, zoom=zoom, x_off=x_off, y_off=y_off)
    # Let us turn off the axes
    plt.axis('off')
    # to display the created fractal 
    plt.imshow(pixels, cmap=cmap)
    plt.show()


if __name__== "__main__":
    display()

Plot julia in python

####################################################################
# Snippet 40 : "plot_julia.py"
# Julia
# 
####################################################################
#!/usr/bin/python3

from __future__ import division
 
import numpy as np
import matplotlib.pyplot as plt
 
m = 1024
n = 768
 
s = 600  # Scale.
x = np.linspace(-m / s, m / s, num=m).reshape((1, m))
y = np.linspace(-n / s, n / s, num=n).reshape((n, 1))
Z = np.tile(x, (n, 1)) + 1j * np.tile(y, (1, m))
 
C = np.full((n, m), -0.4 + 0.6j)
M = np.full((n, m), True, dtype=bool)
N = np.zeros((n, m))
for i in range(256):
    Z[M] = Z[M] * Z[M] + C[M]
    M[np.abs(Z) > 2] = False
    N[M] = i
 
# Save with Matplotlib using a colormap.
fig = plt.figure()
fig.set_size_inches(m / 100, n / 100)
ax = fig.add_axes([0, 0, 1, 1], frameon=False, aspect=1)
ax.set_xticks([])
ax.set_yticks([])
plt.imshow(np.flipud(N), cmap='hot')
plt.savefig('julia-plt.png')
plt.show()
#plt.close()

Plot another mandelbrot in python

####################################################################
# Snippet 39 : "plot_mandelbrot.py"
# Mandelbrot
# 
####################################################################
#!/usr/bin/python3

from __future__ import division
 
import numpy as np
import matplotlib.pyplot as plt
 
m = 1024
n = 768
 
s = 600  # Scale.
x = np.linspace(-m / s, m / s, num=m).reshape((1, m))
y = np.linspace(-n / s, n / s, num=n).reshape((n, 1))
C = np.tile(x, (n, 1)) + 1j * np.tile(y, (1, m))
 
Z = np.full((n, m), -0.0 + 0.0j)
M = np.full((n, m), True, dtype=bool)
N = np.zeros((n, m))
for i in range(256):
    Z[M] = Z[M] * Z[M] + C[M]
    M[np.abs(Z) > 2] = False
    N[M] = i
 
# Save with Matplotlib using a colormap.
fig = plt.figure()
fig.set_size_inches(m / 100, n / 100)
ax = fig.add_axes([0, 0, 1, 1], frameon=False, aspect=1)
ax.set_xticks([])
ax.set_yticks([])
plt.imshow(np.flipud(N), cmap='hot')
plt.savefig('mandel-plt.png')
plt.show()
#plt.close()

Plot feigenbaum diagram

#####################################################################
# Snippet 38 : "plot_feigenbaum.py"
# Feigenbaum
# 
####################################################################
#!/usr/bin/python3

import numpy as np
import matplotlib.pyplot as plt

def plot_feigenbaum():
    MU_MIN = 2.7
    MU_MAX = 4.0
    MU_DELTA = 0.001
    NUM_IT = 400
    X_INIT = 0.05
    fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(18, 10))
    x = X_INIT
    x_list = np.arange(MU_MIN, MU_MAX, MU_DELTA).tolist()
    y_list = []
    for k in x_list:
        y = []
        for it in range(NUM_IT):
            x = k * x * (1.0 - x)
            y.append(x)
        y_list.append(y)

    ax.plot(x_list, y_list, ",k")
    ax.set_xlabel('Wachstumsfaktor K')
    ax.set_ylabel('{} x-Werte'.format(NUM_IT))
    plt.savefig("feigenbaum.png")
    plt.show()

if __name__== "__main__":
    plot_feigenbaum()

Extract tgz without leading directories to target directory

####################################################################
# Snippet 37 : "snippetfile1.txt"
# Extract tgz without leading directories to specific target directory
# 
####################################################################
#!/bin/bash
tar zxf yourfile.tgz --xform='s#^.+/##x' -C your_existing_targetdirectory

Copy only new files and keep the old

####################################################################
# Snippet 36 : "snippetfile1.txt"
# Copy only new files
# Keep the old files in the target directory untouched
####################################################################
#!/bin/bash
false | cp -i /fromdir/* /todir/ > /dev/null 2>&1 

Creates and mounts a new virtual loop file system

####################################################################
# Snippet 35 : "createloopfs.sh"
# Create and mount virtual loop file system
# 
####################################################################
#!/bin/bash
#
# Handle virtual log container
#
VARLOG_MOUNTED=$(/bin/mount | grep -c "/var/log type ext4")
if [ "${VARLOG_MOUNTED}" -gt "0" ]; then
	echo "The log container was aready mounted successfully" > /dev/kmsg
else
	# Mount image for log files and create it before, if not existing
	if [ ! -f /opt/logfs.img ]; then
			echo "No log container found, creating it now" > /dev/kmsg
			/bin/dd if=/dev/zero of=/opt/logfs.img bs=1M count=512
			echo 'type=83' | /sbin/sfdisk /opt/logfs.img
			echo "y" | /sbin/mkfs.ext4 /opt/logfs.img
	fi

	/sbin/losetup /dev/loop0 /opt/logfs.img
	/bin/mount /opt/logfs.img /var/log/
	ERRORCODE=$?                                                                        
    if [ "${ERRORCODE}" == "0" ]; then                                                                              
            echo "Successfully mounted the log container" > /dev/kmsg
    else                                                                                
            echo "Mounting the log container returned errorcode ${ERRORCODE}, Stop!" > /dev/kmsg                                 
            exit ${ERRORCODE}                                
    fi
fi

Generate a test report from a Unit test XML result output

 <project name="genTestReport" default="gen" basedir=".">
        <description>
                Generate the HTML report from JUnit XML files
        </description>

        <target name="gen">
                <property name="genReportDir" location="${basedir}/unitTestReports"/>
                <delete dir="${genReportDir}"/>
                <mkdir dir="${genReportDir}"/>
                <junitreport todir="${basedir}/unitTestReports">
                        <fileset dir="${basedir}">
                                <include name="**/TEST-*.xml"/>
                        </fileset>
                        <report format="frames" todir="${genReportDir}/html"/>
                </junitreport>
        </target>
</project>

Simple AES encryption and decryption of files

####################################################################
# Snippet 29 : "cipher.sh"
# Encrypt and decrypt files with AES-256-CBC
# A simple openssl wrapper
####################################################################
#!/bin/bash
if [ $# -ne 3 ]; then
        echo "Usage: $0 <encode / decode> <filename> <passphrase>"
        exit 1
fi

if [ ! -e $2 ]; then
        echo "File $2 does not exist"
        exit 1
fi

if [ "$1" == "encode" ]; then
        openssl enc -aes-256-cbc -e -in $2 -out $2.encoded -k $3
        echo "Encoded fie is : $2.encoded"
        exit 0
elif [ "$1" == "decode" ]; then
        openssl enc -aes-256-cbc -d -in $2 -out $2.decoded -k $3
        if [ "$?" -eq "0" ]; then
                echo "Decoded file is : $2.decoded"
                exit 0
        else
                exit 1
        fi
else
        echo "Unknown parameter: $1 (must be 'encode' or 'decode')"
        exit 1
fi

Send an Email in python

####################################################################
# Snippet 28 : "sendemail.py"
# Send automated Email
# 
####################################################################
#!/usr/bin/python3
import smtplib, ssl
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import sys
import os
import argparse

def send(sender, receivers, subject, message, password):
	port = 25  # For starttls
	smtp_server = "mail.mailserver.de"
	
	msg = MIMEMultipart()
	msg['From'] = sender
	msg['To'] = receivers
	msg['Subject'] = subject
	msg.attach(MIMEText(message, 'plain'))
	recvlist=receivers.split(", ")

	context = ssl.create_default_context()
	server = smtplib.SMTP(smtp_server, port)
	server.ehlo()  # Can be omitted
	server.starttls(context=context)
	server.ehlo()  # Can be omitted
	server.login(sender, password)
	server.sendmail(sender, recvlist, msg.as_string())
	server.quit()

def main():
	parser = argparse.ArgumentParser(description='My Email sender"\n')
	parser.add_argument("--sender", default="", help="Sender email address")
	parser.add_argument("--to", default="", help="Receiver email address")
	parser.add_argument("--subject", default="", help="Subject of email")
	parser.add_argument("--message", default="", help="Email message content")
	parser.add_argument("--password", default="", help="Password for email account of sender")
	args = parser.parse_args()
	password=args.password
	if len(password)<=0:
		password = input("Type password of your email account :")
	send(args.sender, args.to, args.subject, args.message, password)
	sys.exit(0)

if __name__== "__main__":
    main()

Convert textfile to UTF-8

####################################################################
# Snippet 27 : "convert_to_utf8.sh"
# Convert a text file to UTF-8
# 
####################################################################
#!/bin/bash
vim '+set fileencoding=utf-8' '+wq' $1

Calculates the seconds until the next quarter hour in bash

####################################################################
# Snippet 26 : "nextreftime.sh"
# Calculate seconds to next quarter hour
# 
####################################################################
#!/bin/bash

now_clear=$(date '+%Y-%m-%d %H:%M:%S')
now_epoch=$(date '+%s' -d "$now_clear")

nextref_epoch=$(($now_epoch / 900 * 900 + 900))
nextref_clear=$(date '+%Y-%m-%d %H:%M:%S' -d @$nextref_epoch)
echo "now = $now_clear ( $now_epoch ), next reference time = $nextref_clear ( $nextref_epoch )"

secs_to_sleep=$(($nextref_epoch - $now_epoch))
echo "Time to sleep : $secs_to_sleep seconds"


Conversion between DER and ASCII

####################################################################
# Snippet 23 : "convert_der_ascii.sh"
# Conversion between DER and human readable HEX
# 
####################################################################
#!/bin/bash
#DER-TO-ASCII :
cat <yourfilename>.der | od -tx1 -An | sed -e 's/\ //g' | tr -d '\n'

#ASCII-TO-DER :
echo -n 1234abcdef | perl -e 'print pack("H*", <>),' > <yourfilename>.der

Colorful text outputs in bash

####################################################################
# Snippet 22 : "colors.sh"
# Colorful shell outputs
# 
####################################################################
#!/bin/bash
if test -t 1; then
        ncolors=$(tput colors)
        if test -n "$ncolors" && test $ncolors -ge 8; then
                BLACK=`tput setaf 0`
		RED=`tput setaf 1`
		GREEN=`tput setaf 2`
		YELLOW=`tput setaf 3`
		BLUE=`tput setaf 4`
		MAGENTA=`tput setaf 5`
		CYAN=`tput setaf 6`
		WHITE=`tput setaf 7`

		BOLD=`tput bold`
		RESET=`tput sgr0`
        fi
fi

echo -e "hello ${RED}some red text${RESET} world"
echo -n "Testresult : "
echo -e "${GREEN}${BOLD}PASSED${RESET}"
echo -n "Testresult : "
echo -e "${RED}${BOLD}FAILED${RESET}"

Open image and play sound in ununtu bash

#!/bin/bash
xdg-open ~/Bilder/miracoli.png
paplay /usr/share/sounds/ubuntu/notifications/Amsterdam.ogg

Backup public media contents

#!/bin/sh
#
# To run this script in the
# Alpine Linux (iSH) on iOS
# you need to install bash,
# python3, pip3 and youtube-dl
# in it with these commands :
#
# apk add python3
# apk add pip
# apk add py3-pip
# pip install yt-dlp
# apk add ffmpeg
# apk add bash
#
# To use 'tput' :
# apk add ncurses
#
#
if test -t 1; then
    ncolors=$(tput colors)
    if test -n "$ncolors" && test $ncolors -ge 8; then
        bold="$(tput bold)"
        underline="$(tput smul)"
        standout="$(tput smso)"
        normal="$(tput sgr0)"
        black="$(tput setaf 0)"
        red="$(tput setaf 1)"
        green="$(tput setaf 2)"
        yellow="$(tput setaf 3)"
        blue="$(tput setaf 4)"
        magenta="$(tput setaf 5)"
        cyan="$(tput setaf 6)"
        white="$(tput setaf 7)"
		fi
fi
echo "${bold}${yellow}§ 53 Abs. 1 des Urheberrechtsgesetzes (UrhG) beschreibt, wann die Kopie eines fremden Werkes erlaubt ist. Sinngemäß lautet es dort: \"Wenn ein Nutzer einzelne Vervielfältigungen (auch das Herunterladen) eines fremden Werks für den eigenen privaten Gebrauch ohne Erwerbszweck herstellt und diese weder verbreitet noch veröffentlicht und die benutzte Vorlage nicht offensichtlich rechtswidrig ist oder offensichtlich rechtswidrig öffentlich zugänglich gemacht wurde, ist das Kopieren grundsätzlich erlaubt.\"${normal}"

while [ true ]; do
	echo "-------------------"
	# postprocessing not needed for m4a
	#-x --audio-format m4a \
	#--add-metadata \
	yt-dlp --no-post-overwrites -ciw \
	-f bestaudio[ext=m4a] \
	--add-metadata \
	-o '%(playlist_title)s/%(playlist_index)s-%(title)s.%(ext)s' \
	$@
	if [ "$?" == "0" ]; then
		echo "==================="
		echo "${green}${bold}Success!${normal}"
		exit 0
	else
		echo "${bold}${yellow}Continuing after errors${normal}"
	fi
	sleep 2
done
#
# Use --playlist-start x to append/update at position x

Webserver 127.0.0.1:8000

#!/bin/bash
python3 -m http.server

Website downloader

#!/bin/bash
domain=$(echo "${1}" | sed -En "s/^http[s]?:\/\/(.*\.)
*(.*\..*)\/.*/\2/p")
wget --no-parent --recursive --no-clobber --page-requisites --convert-links -e robots=off --domains ${domain} ${1}

Soundcloud downloader

#!/bin/sh
#
# To run this script in the
# Alpine Linux (iSH) on iOS
# you need to install bash,
# python3, pip3 and youtube-dl
# in it with these commands :
#
# apk add python3
# apk add pip
# apk add py3-pip
# pip install youtube-dl
# apk add ffmpeg
# apk add bash
#
# To use 'tput' :
# apk add ncurses
#
#
if test -t 1; then
    ncolors=$(tput colors)
    if test -n "$ncolors" && test $ncolors -ge 8; then
        bold="$(tput bold)"
        underline="$(tput smul)"
        standout="$(tput smso)"
        normal="$(tput sgr0)"
        black="$(tput setaf 0)"
        red="$(tput setaf 1)"
        green="$(tput setaf 2)"
        yellow="$(tput setaf 3)"
        blue="$(tput setaf 4)"
        magenta="$(tput setaf 5)"
        cyan="$(tput setaf 6)"
        white="$(tput setaf 7)"
		fi
fi
echo "${bold}${yellow}§ 53 Abs. 1 des Urheberrechtsgesetzes (UrhG) beschreibt, wann die Kopie eines fremden Werkes erlaubt ist. Sinngemäß lautet es dort: \"Wenn ein Nutzer einzelne Vervielfältigungen (auch das Herunterladen) eines fremden Werks für den eigenen privaten Gebrauch ohne Erwerbszweck herstellt und diese weder verbreitet noch veröffentlicht und die benutzte Vorlage nicht offensichtlich rechtswidrig ist oder offensichtlich rechtswidrig öffentlich zugänglich gemacht wurde, ist das Kopieren grundsätzlich erlaubt.\"${normal}"

while [ true ]; do
	echo "-------------------"
	# postprocessing not needed for mp3
	#-x --audio-format mp3 \
	#--add-metadata \
	youtube-dl --no-post-overwrites -ciw \
	-f bestaudio[ext=mp3] \
	--add-metadata \
	-o '%(playlist_title)s/%(playlist_index)s-%(title)s.%(ext)s' \
	$@
	if [ "$?" == "0" ]; then
		echo "==================="
		echo "${green}${bold}Success!${normal}"
		exit 0
	else
		echo "${bold}${yellow}Continuing after errors${normal}"
	fi
	sleep 2
done
#
# Use --playlist-start x to append/update at position x

Display PHP environment

<?php
ini_set('display_errors', 1);
error_reporting(E_ALL);
var_dump(get_defined_vars())
?>

Pretty print in shell

#
# Pretty print function
# Can be skipped with optional parameter 'simple'
# (Jenkins cannot display archived text which was pretty printed)
#

pprint () {
        echo "#"
        if [ "${format}" != "simple" ] && [ -x /usr/bin/toilet ]; then
                toilet -w 160 -f future ${1} | sed -E "s/^/#   /g"
        else
                echo "#   ${1}"
        fi
        echo "#"
}
export -f pprint

Extract opkg package (.ipk)

_openipk () {
	local filename="${1}"
	local tmpdir="$(basename ${filename}).extracted"
	rm -rf "${tmpdir}" &&
	mkdir "${tmpdir}"
	(
		cd ${tmpdir}
		log "Unpack ipk ${filename} in $(pwd)/${tmpdir}"
		ar x ${filename} && _opentars
		local retval=$?
		# For combi packets :
		moreipks=$(find . -iname "*.ipk" 2>/dev/null | tr '\n' ' ')
		for i in ${moreipks}; do
			_openipk "$(pwd)/${i}"
		done
		exit ${retval}
	)
	local retval=$?
	(return 0 2>/dev/null) && return ${retval} || exit ${retval}
}

#
# Unpacks ipk packet and subpackets
#
packet-extract-ipk () {
	local retval=0
	local filename="${1}"
	if [ "${filename}" == "" ]; then
		log "Unpacks an ipk packet and subpackets"
		log "Give filename as first parameter !"
		retval=1
	else
		if [ -f ${filename} ]; then
			if [ "$(dirname ${filename})" == "." ]; then
				filename="${PWD}/${filename}"
			fi
			_openipk ${filename}
			retval=$?
		else
			log "Unknown file '${filename}"
			retval=1
		fi
	fi
	(return 0 2>/dev/null) && return ${retval} || exit ${retval}
}
export -f packet-extract-ipk

Shell execution capsuler

# This function runs a command within its own context
# of stdout and stderr to not disturb the outter sourcing scripts.
# The SSH command that we use here to gather the BSPNAME, 
# destroys old contents of stdout and stderr.
# When sourcing scripts exchange data via pipes, then these data could 
# be destroyed. 
# ( The described problem was observed when running 'autoinit force'; 
#   only the first line of the piped meter config was processed,
#   the remaining lines got lost after gathering the BSPNAME right here. )
#
capsule () {
  local PIPE_DIRECTORY=$(mktemp -d)
  trap "rm -rf '$PIPE_DIRECTORY'" EXIT

  mkfifo "$PIPE_DIRECTORY/stdout"
  mkfifo "$PIPE_DIRECTORY/stderr"

  "$@" >"$PIPE_DIRECTORY/stdout" 2>"$PIPE_DIRECTORY/stderr" &
  local CHILD_PID=$!

  sed 's/^//' "$PIPE_DIRECTORY/stdout" &
  sed 's/^//' "$PIPE_DIRECTORY/stderr" >&2 &
  wait "$CHILD_PID"
  rm -rf "$PIPE_DIRECTORY"
}
export -f capsule

Generate big HTTP POST data

#!/bin/bash
size=$1
sendfile=$2
blocks=$((size / 16))
rm -f ${sendfile}
echo "Writing HTTP header to $sendfile"
printf "POST /test HTTP/1.1\r\n" >$sendfile
printf "Content-Length: $size\r\n" >>$sendfile
printf "\r\n" >>$sendfile
echo "Writing ${blocks} 16-byte-blocks (=${size} bytes total) to ${sendfile}"
for i in `seq 1 ${blocks}`;
do
       printf %s "0123456789abcdef" >>${sendfile}
done

Display all toilet fonts

#!/bin/bash
toiletfonts=$(ls /usr/share/figlet/* | sed -En "s,.*/(.*).tlf,\1,p"); for font in $toiletfonts; do echo "toilet -f $font $(echo $font | rev)"; toilet -f $font $(echo $font | rev); echo ""; echo ""; done

Time tracker for test cases

#!/bin/bash

#set -x
DBPATH="/usr/share//var/db"
TIMEDB="${DBPATH}/timetracking-tests.sqlite"

######################################
#
# Lower functions
#
######################################

log () {
        >&2 echo "${1}"
}

assuredb () {
	mkdir -p ${DBPATH}
	sqlite3 ${TIMEDB} "create table if not exists runtimes(version text, tcs text, mintime int, avgtime int, maxtime int, primary key(version, tcs));"
}

getsubquery () {
	local version="${1}"
	local tcs="${2}"
	local whereclause=""
	local joinclause=""
	if [ "${tcs}" != "" ]; then
		# We want to evaluate also double entries
		local intcs="$(echo "${tcs}" | sed "s/ /\" as tcs union all select \"/g;s/^/\"/;s/$/\" as tcs/")"
		joinclause=" join (select ${intcs}) matches using(tcs)"		
	fi
	if [ "${version}" != "" ]; then
		whereclause=" where version=\"${version}\" "
	fi
	echo "${joinclause} ${whereclause}"
}

removetcs () {
        local version="${1}"
        local tcs="${2}"
	local intcs="$(echo "${tcs}" | sed "s/ /\", \"/g;s/^/(\"/g;s/$/\")/g")"
	query="delete from runtimes where tcs in ${intcs};"
	#log "Query: \"${query}\""
	sqlite3 ${TIMEDB} "${query}"
	return $?
}


converttime () {
	TIMES="${1}"
	FORMAT="${2}"
	CONVERTED=""
	TIMES=$(echo "${TIMES}" | tr '|' ' ')
	for time in ${TIMES}; do
		if [ "${CONVERTED}" == "" ]; then
			CONVERTED="$(date -d@${time} -u +${FORMAT})"
		else
			CONVERTED="${CONVERTED}|$(date -d@${time} -u +${FORMAT})"
		fi
	done
	echo "${CONVERTED}"
}

getmintime () {
	assuredb
	query="select ${BATCHSLEEP}+(select ${TCSLEEP}*count(*) from runtimes $(getsubquery "${1}" "${2}"))+(select sum(mintime) from runtimes $(getsubquery "${1}" "${2}"));"
	#log "Query: \"${query}\""
	local testtime=$(sqlite3 ${TIMEDB} "${query}")
	if [ "${3}" != "" ]; then
		testtime=$(converttime "${testtime}" "${3}")
	fi
	echo "${testtime}"
}

getavgtime () {
	assuredb
	query="select ${BATCHSLEEP}+(select ${TCSLEEP}*count(*) from runtimes $(getsubquery "${1}" "${2}"))+(select sum(avgtime) from runtimes $(getsubquery "${1}" "${2}"));"
	#log "Query: \"${query}\""
	local testtime=$(sqlite3 ${TIMEDB} "${query}")
        if [ "${3}" != "" ]; then
                testtime=$(converttime "${testtime}" "${3}")
        fi
	echo "${testtime}"
}

getmaxtime () {
	assuredb
	query="select ${BATCHSLEEP}+(select ${TCSLEEP}*count(*) from runtimes $(getsubquery "${1}" "${2}"))+(select sum(maxtime) from runtimes $(getsubquery "${1}" "${2}"));"
	#log "Query: \"${query}\""
	local testtime=$(sqlite3 ${TIMEDB} "${query}")
        if [ "${3}" != "" ]; then
                testtime=$(converttime "${testtime}" "${3}")
        fi
	echo "${testtime}"
}

getalltimes () {
	assuredb
	minquery="${BATCHSLEEP}+(select ${TCSLEEP}*count(*) from runtimes $(getsubquery "${1}" "${2}"))+(select sum(mintime) from runtimes $(getsubquery "${1}" "${2}"))"
	avgquery="${BATCHSLEEP}+(select ${TCSLEEP}*count(*) from runtimes $(getsubquery "${1}" "${2}"))+(select sum(avgtime) from runtimes $(getsubquery "${1}" "${2}"))"
	maxquery="${BATCHSLEEP}+(select ${TCSLEEP}*count(*) from runtimes $(getsubquery "${1}" "${2}"))+(select sum(maxtime) from runtimes $(getsubquery "${1}" "${2}"))"
	query="select ${minquery}, ${avgquery}, ${maxquery}"
	#log "Query: \"${query}\""
	local testtime=$(sqlite3 ${TIMEDB} "${query}")
        if [ "${3}" != "" ]; then
                testtime=$(converttime "${testtime}" "${3}")
        fi
	echo "${testtime}"
}

listtcs () {
        assuredb
        query="select tcs, ${TCSLEEP}+mintime, ${TCSLEEP}+avgtime, ${TCSLEEP}+maxtime from runtimes $(getsubquery "${1}" "${2}")"
        #log "Query: \"${query}\""
        local lines=$(sqlite3 ${TIMEDB} "${query}")
        if [ "${3}" != "" ]; then
		lines=$(echo "${lines}" | tr '\n' ' ')
		newlines=""
		for line in ${lines}; do
			tcs=$(echo "${line}" | cut -d "|" -f1)
			testtimes=$(echo "${line}" | sed "s/[^|]*|//")
			testtimes=$(converttime "${testtimes}" "${3}")
			if [ "${newlines}" == "" ]; then
				newlines="${tcs}|${testtimes}"
			else
				newlines="${newlines} ${tcs}|${testtimes}"
			fi
		done
		lines=$(echo "${newlines}" | tr ' ' '\n')
        fi
        echo "${lines}"

}

updatetime () {
	assuredb
	local version="${1}"
	local tcs="${2}"
	local newtime="${3}"
	local oldavgtime=$(getavgtime "${version}" "${tcs}")
	local oldmintime=$(getmintime "${version}" "${tcs}")
        local oldmaxtime=$(getmaxtime "${version}" "${tcs}")
	if [ "${oldavgtime}" == "" ]; then
		oldavgtime="${newtime}"
		oldmintime="${newtime}"
		oldmaxtime="${newtime}"
		query="insert into runtimes values (\"${version}\", \"${tcs}\", ${newtime}, ${newtime}, ${newtime});"
		#log "Query: \"${query}\""
		sqlite3 ${TIMEDB} "${query}"
	fi
	local mintime=$(python -c "print(min(${oldmintime}, ${newtime}))")
	local maxtime=$(python -c "print(max(${oldmaxtime}, ${newtime}))")
	local avgtime=$(python -c "print((${oldavgtime}+${newtime})/2)")
	#local avgtime=$(echo "scale=0;(${oldavgtime}+${newtime})/2" | bc)
	query="update runtimes set mintime=${mintime}, avgtime=${avgtime}, maxtime=${maxtime} where version=\"${version}\" and tcs=\"${tcs}\""
	#log "Query : \"${query}\""
	sqlite3 ${TIMEDB} "${query}"
	return $?
}

######################################
#
# Upper functions
#
######################################

printusage () {
	log ""
	log "This script reads or updates testcase duration times."
	log "Available options :"
	log "-v or --version  : Specifies the SMGW version (1 or 2)"
	log "-t or --testcase : Specifies the testcase(s) (TCS), separated by spaces"
	log "-d or --duration : Specifies the duration in seconds"
	log "-f or --format   : Specifies the time output format, i.E. '%H:%M:%S'. Default output is in seconds"
	log "--sleep-tc       : Sleep time between testcases"
	log "--sleep-run      : Sleep time after testrun"
	log ""
	log "Available operations :"
	log "get              : Returns all times (min, avg, max)"
	log "getmin           : Returns the minimal measured execution time"
	log "getavg           : Returns the average execution time"
	log "getmax           : Returns the maximal measured execution time"
	log "update           : Feeds a new execution time for a test case into the database"
	log "delete           : Deletes testcase(s) from the database"
	log "list             : Returns detailed list of tescase times"
	log ""
}

update () {
	local VERSION="${1}"
	local TCS="${2}"
	local DURATION="${3}"
	local retval=0
	if [ "${VERSION}" == "" ] || [ "${TCS}" == "" ] || [ "${DURATION}" == "" ]; then
		log "Give version, testcase and duration for update !"
		retval=1
	else
		updatetime "${VERSION}" "${TCS}" "${DURATION}"
		retval=$?
	fi
	(return 0 2>/dev/null) && return ${retval} || exit ${retval}
}

getmin () {
	local VERSION="${1}"
	local TCS="${2}"
        local FORMAT="${3}"
	if [ "${VERSION}" == "" ]; then
		log "Specify the  version !"
		retval=1
	else
		if [ "${TCS}" != "" ]; then
			echo "$(getmintime "${VERSION}" "${TCS}" "${FORMAT}")"
			retval=$?
		fi
	fi
	(return 0 2>/dev/null) && return ${retval} || exit ${retval}
}


getavg () {
	local VERSION="${1}"
	local TCS="${2}"
	local FORMAT="${3}"
	if [ "${VERSION}" == "" ]; then
		log "Specify the  version !"
		retval=1
	else
		if [ "${TCS}" != "" ]; then
			echo "$(getavgtime "${VERSION}" "${TCS}" "${FORMAT}")"
			retval=$?
		fi
	fi
	(return 0 2>/dev/null) && return ${retval} || exit ${retval}
}

getmax () {
	local VERSION="${1}"
	local TCS="${2}"
        local FORMAT="${3}"
	if [ "${VERSION}" == "" ]; then
		log "Specify the  version !"
		retval=1
	else
		if [ "${TCS}" != "" ]; then
			echo "$(getmaxtime "${VERSION}" "${TCS}" "${FORMAT}")"
			retval=$?
		fi
	fi
	(return 0 2>/dev/null) && return ${retval} || exit ${retval}
}

getall () {
	local VERSION="${1}"
	local TCS="${2}"
        local FORMAT="${3}"
	if [ "${VERSION}" == "" ]; then
		log "Specify the  version !"
		retval=1
	else
		if [ "${TCS}" != "" ]; then
			echo "$(getalltimes "${VERSION}" "${TCS}" "${FORMAT}")"
			retval=$?
		fi
	fi
	(return 0 2>/dev/null) && return ${retval} || exit ${retval}
}

getlist () {
        local VERSION="${1}"
        local TCS="${2}"
        local FORMAT="${3}"
        if [ "${VERSION}" == "" ]; then
                log "Specify the  version !"
                retval=1
        else
                if [ "${TCS}" != "" ]; then
                        echo "$(listtcs "${VERSION}" "${TCS}" "${FORMAT}")"
			retval=$?
                fi
        fi
        (return 0 2>/dev/null) && return ${retval} || exit ${retval}
}

delete () {
        local VERSION="${1}"
        local TCS="${2}"
        if [ "${VERSION}" == "" ]; then
                log "Specify the  version !"
                retval=1
        else
                if [ "${TCS}" != "" ]; then
                        removetcs "${VERSION}" "${TCS}"
			retval=$?
                fi
        fi
        (return 0 2>/dev/null) && return ${retval} || exit ${retval}

}





##########
## main ##
##########

TCSLEEP="0"
BATCHSLEEP="0"

# Evaluate command line options
POSITIONAL_ARGS=()
while [[ $# -gt 0 ]]; do
  case $1 in
    -h|--help)
      printusage
      exit 1
      ;;
    -v|--version)
      VERSION="${2}"
      shift # past argument
      shift # past value
      ;;      
    -t|--testcase)
      TCS="${2}"      
      shift # past argument
      shift # past value
      ;;
    -d|--duration)
      DURATION="${2}"
      shift # past argument
      shift # past value
      ;;
    -f|--format)
      TIMEFORMAT="${2}"
      shift # past argument
      shift # past value
      ;;
    --sleep-tc)
      TCSLEEP="${2}"
      shift # past argument
      shift # past value
      ;;
    --sleep-run)
      BATCHSLEEP="${2}"
      shift # past argument
      shift # past value
      ;;
    -*|--*)
      log "Unknown option $1"
      (return 0 2>/dev/null) && return 1 || exit 1
      ;;
    *)
      POSITIONAL_ARGS+=("$1") # save positional arg
      shift # past argument
      ;;
  esac
done
set -- "${POSITIONAL_ARGS[@]}" # restore positional parameters


# Process script operations
case ${1} in
     update)
        update "${VERSION}" "${TCS}" "${DURATION}"
      ;;
     getmin)
        getmin "${VERSION}" "${TCS}" "${TIMEFORMAT}"
      ;;
     getavg)
        getavg "${VERSION}" "${TCS}" "${TIMEFORMAT}"
      ;;
     getmax)
        getmax "${VERSION}" "${TCS}" "${TIMEFORMAT}"
      ;;
     get)
        getall "${VERSION}" "${TCS}" "${TIMEFORMAT}"
      ;;
     delete)
        delete "${VERSION}" "${TCS}"
      ;;
     list)
        getlist "${VERSION}" "${TCS}" "${TIMEFORMAT}"
      ;;
    *)
      printusage
	  (return 0 2>/dev/null) && return 1 || exit 1
      ;;
esac
(return 0 2>/dev/null) && return 0 || exit 0


Zurück zur Hauptseite