Archive for category Operating Systems

One half of a Windows Sockets test

This is the client side of a Windows Sockets test in C++.

#ifndef _WINSOCK_TEST_H
#define _WINSOCK_TEST_H

#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <stdio.h>

WSADATA wsaData;

int initWinsock();

#endif
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

#include "winsock_test.h"

int initWinsock()
{
	int iResult;

	puts("initWinsock()");

	if (iResult = WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
		return 0;

	printf("WSAStartup(MAKRWORD(2, 2), 0x%x) returned %d\n", &wsaData, iResult);
	return 1
}
#include "winsock_test.h"

#define TCP_SOCKET_PORT 27015
#define TCP_SOCKET_ADDR "127.0.0.1"
#define BUFLEN		512

int client()
{
	int    iResult;
	int    recvbuflen       = DEFAULT_BUFLEN;
	struct addrinfo *result = NULL;
	struct addrinfo *ptr    = NULL,
	struct addrinfo hints;
	char   port[5];
	char   *sendbuf         = "this is a test";
	char   recvbuf[DEFAULT_BUFLEN];

	puts("client()");

	printf("ZeroMemory(0x%x, 0x%x)\n", &hints, sizeof (hints));
	ZeroMemory(&hints, sizeof (hints));
	hints.ai_family   = AF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = IPPROTO_TCP;

	itoa(TCP_SOCKET_PORT, port, 10);
	printf("getaddrinfo(%s, %s, 0x%x, 0x%x)\n", TCP_SOCKET_ADDR, port, &hints, &result);
	if (iResult = getaddrinfo(TCP_SOCKET_ADDR, port, &hints, &result) != 0)
	{
		printf("getaddrinfo(%s, %s, 0x%x, 0x%x) returned %d\n", TCP_SOCKET_ADDR, port, &hints, &result, iResult);
		WSACleanup();
		return 1;
	}

	SOCKET ConnectSocket = INVALID_SOCKET;
	ptr = result;
	puts("socket(AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP)\n");
	if (ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol) == INVALID_SOCKET)
	{
		printf("Error on socket(): %ld\n", WSAGetLastError());
		freeaddrinfo(result);
		WSACleanup();
		return 1;
	}

	puts("connect(ConnectSocket, ptr->ai_addr, (int) ptr->ai_addrlen)\n");
	if (iResult = connect(ConnectSocket, ptr->ai_addr, (int) ptr->ai_addrlen) == SOCKET_ERROR)
	{
		printf("connect(ConnectSocket, ptr->ai_addr, (int) ptr->ai_addrlen) returned %d\n", iResult);
		closesocket(ConnectSocket);
		ConnectSocket = INVALID_SOCKET;
	}

	freeaddrinfo(result);

	if (ConnectSocket == INVALID_SOCKET)
	{
		puts("Socket connection failed.\n");
		WSACleanup();
		return 1;
	}

	printf("send(ConnectSocket, %s, (int) %d, 0)\n", sendbuf, (int) strlen(sendbuf));
	if (iResult = send(ConnectSocket, sendbuf, (int) strlen(sendbuf), 0) == SOCKET_ERROR)
	{
		printf("send failed: %d\n", WSAGetLastError());
		closesocket(ConnectSocket);
		WSACleanup();
		return 1;
	{

	printf("Bytes sent: %ld\n", iResult);

	puts("shutdown(ConnectSocket, SD_SEND)\n");
	if (iResult = shutdown(ConnectSocket, SD_SEND) == SOCKET_ERROR)
	{
		printf("shutdown failed: %d\n", WSAGetLastError());
		closesocket(ConnectSocket);
		WSACleanup();
		return 1;
	}

	// receive data
	do
	{
		puts("recv(ConnectSocket, recvbuf, recvbuflen, 0)\n");
		iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
		if (iResult > 0)
			printf("Bytes received: %d\n", iResult);
		else if (iResult == 0)
			puts("Connection closed"\n);
		else
			printf("recv failed: %d\n", WSAGetLastError());
	}
	while (iresult > 0);

	// no more data, shut down
	puts("shutdown(ConnectSocket, SD_SEND)\n");
	if (iResult = shutdown(ConnectSocket, SD_SEND) == SOCKET_ERROR)
	{
		printf("shutdown failed: %d\n", WSAGetLastError());
		closesocket(ConnectSocket);
		WSACleanup();
		return 1;
	}

	closesocket(ConnectSocket);
	WSACleanup();
	return 0;
}

Leave a comment

Quote Database Screen Scraper

I wanted to make fortune(6) cookie files out of the major internet quote databases. So I came up with a Bash script that uses lynx and sed to do it. It includes throttling by default because it’s not nice to suck up all the site’s bandwidth.

#!/bin/bash
# Scrapes a qdb and dumps output to a file
# and tokenizes it into a fortune cookie file
#
LYNX="/usr/bin/lynx"
DEFSLEEP="30"
PNUM_DELIM="%pnum%"

# parse command line args
# look for -s to specify sleep_int period
# look for -p to specify number of pages
# treat everything else like a URL
# %pnum% is page number delimiter
sleep_int=$DEFSLEEP
URLS=()
ARGV=("$@")
for (( thisarg = 0; thisarg < ${#ARGV[*]}; thisarg++ ))
do
	arg="${ARGV[$thisarg]}"
	if [ "$arg" = "-s" ]
	then
		thisarg=$(( $thisarg + 1 ))
		sleep_int=${ARGV[$thisarg]}
	elif [ "$arg" = "-p" ]
	then
		thisarg=$(( $thisarg + 1 ))
		pages=${ARGV[$thisarg]}
	else
		URLS=("${URLS[@]}" "$arg")
	fi
done

LYNXOPTS="-accept_all_cookies -assume_charset=iso-88591 -nolist -dump"

# debug
echo ${URLS[@]}
echo "Sleep is $sleep_int"

for url in "$URLS"
do
	name=`echo $url | cut -d / -f 3`
	mkdir "$name"

	for (( page = 1; page <= $pages; page++ ))
	do
		n_url=`echo $url | sed -e "s/$PNUM_DELIM/$page/g"`
		# debug
		echo "$LYNX $LYNXOPTS $n_url > $name/page_$page"
		$LYNX $LYNXOPTS $n_url > $name/page_$page
		sleep $sleep_int
	done

	# postprocess scraped text files
	cd "$name"

	# remove quote IDs and put in fortune delimiters
	for file in *
	do
		sed -e "s/^\s*#.*$/%/g" < "$file" >> "$name.txt"
	done

	# remove page navigation links
	sed -e "s/^.*[1-9][0-9]* of [1-9][0-9]*.*$//g" < "$name.txt" > "$name"

	# make the database
	strfile "$name"
	rm "$name.txt"

done

Leave a comment

aliases-request.pl

A short Perl script I wrote that responds to e-mails with the excerpts of /etc/aliases relevant to the domain to which the request was addressed.

#!/usr/bin/perl
use strict;
use warnings;

# aliases-request.pl
# Returns the relevant parts of /etc/aliases (or specified file)
# Delimited by the requested domain
# ##aliases-request@<domain>
# ##aliases-end@<domain>
#

use constant ALIASES => "/etc/aliases";

# save and parse message
local $/ = undef;    # clear line-ending string
my $msg      = <>;                    # slurp in message
my $domain   = "";
my $dumpfile = "/var/tmp/dumpfile";
open( DUMPFILE, ">$dumpfile" ) or die $!;

# slurp in aliases
open( FILE, ALIASES ) or die $!;
my $aliases = <FILE>;
close FILE;

# reset line-ending string
local $/ = '\n';

for ( split /^/, $msg ) {

    # extract To: domain
    if ( $_ =~ m/^To:.*@(.*)(?:\s|$)/ ) {
        $domain = $1;
        print DUMPFILE "To: Matched " . length(@-) . " items.\n";
        print DUMPFILE "\$domain = $domain\n";
    }

    if ( $_ =~ m/^From:\s+(.*)$/ ) {
        print DUMPFILE "From: Matched " . length(@-) . " items.\n";
        $return_address = $1;
        print DUMPFILE "\$return_address = $return_address\n";
    }

    if ( $_ =~ m/^Reply-to:\s+(.*)$/ ) {
        print DUMPFILE "Reply-to: Matched " . length(@-) . " items.\n";
        $return_address = $1;
        print DUMPFILE "\$return_address = $return_address\n";
    }

    if ( $_ =~ m/^Subject:\s+(.*)$/ ) {
        print DUMPFILE "Subject: Matched " . length(@-) . " items.\n";
        $subject = $1;
        print DUMPFILE "\$subject = $subject\n";
    }
}

# find delimiters and extract relevant chunk
my $delim_string   = "##aliases-request\@$domain";
my $delim_end      = "##aliases-end\@$domain";
my $start_index    = ( index $aliases, $delim_string ) + length($delim_string);
my $end_index      = index $aliases, $delim_end;
my $offset         = $end_index - $start_index;
my $relevant_chunk = substr $aliases, $start_index, $offset;

# create return mail
my $return_address = "";
my $subject        = "";
my $sendmail       = "/usr/sbin/sendmail -t";
my $reply_to = "Reply-to: mailer-daemon\@kitesfear.lakemasoniccenter.org\n";
$subject = "Subject: RE: $subject\n";
my $from = "From: " . "mailer-daemon\@kitesfear.lakemasoniccenter.org\n";
my $to   = "To: " . "$return_address\n";

print DUMPFILE $reply_to;
print DUMPFILE $subject;
print DUMPFILE $from;
print DUMPFILE $to;
print DUMPFILE "Content-type: text/plain\n\n";    # Don't forget extra \n!
print DUMPFILE "$relevant_chunk\n\n.\n";
close(DUMPFILE);

open( SENDMAIL, "|$sendmail" ) or die $!;
print SENDMAIL $reply_to;
print SENDMAIL $subject;
print SENDMAIL $from;
print SENDMAIL $to;
print SENDMAIL "Content-type: text/plain\n\n";    # Don't forget extra \n!
print SENDMAIL "$relevant_chunk\n\n.\n";
close(SENDMAIL);

Leave a comment

Daily Archive Script

#!/usr/bin/ksh
cd ~/Pictures
for dir in `find ./ -maxdepth 1 -type d -mtime 7`
do
	tar cvjpf "${dir}.tar.bz2" "${dir}"
	rm -rf "${dir}"
done
		
ftp -v -n "ftp.lakemasoniccenter.org" <<EOF
user "user" "password"
cd /var/ftp/incoming/media/archive
lcd /home/user/Pictures
mput *.tar.bz2
quit
EOF

rm -rf *.tar.bz2

Leave a comment

Disk Space Monitor

I used to have a script copied from UNIX Hints and Hacks for monitoring disk space but that one didn’t work on my box so I deleted it.  I finally got around to finding a better one.  It was originally copied from ‘NixCraft but I modified it heavily so it’s a bit more user friendly and doesn’t break on long device names:

    #!/bin/sh
    # Shell script to monitor or watch the disk space
    # It will send an email to $ADMIN, if the (free avilable) percentage
    # of space is >= 90%
    # -------------------------------------------------------------------------
    # Copyright (c) 2005 nixCraft project <http://cyberciti.biz/fb/>
    # This script is licensed under GNU GPL version 2.0 or above
    # -------------------------------------------------------------------------
    # This script is part of nixCraft shell script collection (NSSC)
    # Visit http://bash.cyberciti.biz/ for more information.
    # ----------------------------------------------------------------------
    # Linux shell script to watch disk space (should work on other UNIX oses )
    # SEE URL: http://www.cyberciti.biz/tips/shell-script-to-watch-the-disk-space.html
    # set admin email so that you can get email
    ADMIN="operator@lakemasoniccenter.org"
    # set alert level 90% is default
    ALERT=90
    df -PH | grep -vE '^Filesystem|tmpfs|cdrom' | awk '{ print $5 " " $1 " " $6 }' | while read output;
    do
            #echo $output
            usep=$(echo $output | awk '{ print $1}' | cut -d'%' -f1 )
            partition=$(echo $output | awk '{ print $2 " mounted on " $3}' )
            if [ $usep -ge $ALERT ]; then
                    echo "Running out of space \"$partition ($usep%)\" on $(hostname) as on $(date)" |
                    mail -s "Alert: Almost out of disk space $partition" $ADMIN
            fi
    done

Leave a comment

The system works

I decided to go the “traditional” route and set root’s shell to “/bin/sh” instead of “/bin/bash” because on old school Unices, root always used the Bourne shell. So I added another user “toor,” the recommended Bourne-Again superuser to use “/bin/bash.” I knew it would trip a script I have running nightly to check for backdoor logins:

********************************************************************************
*                                                                              *
*                ALERT! Login ID toor has uid 0                        *
*                Detected On Date :08/09/12 Time :12:00:03 AM                       *
*                                                                              *
********************************************************************************

I’ll be updating the script to ignore the ‘toor’ login.

Leave a comment

Minecraft Server is coming back

UPDATE 20120806 0746 hours:  Since some folks have asked, here’s the init script I’m using to control the minecraft server.  It runs on CentOS (royalty-free rebranding of Red Hat Enterprise Linux):

#!/bin/bash
# /etc/init.d/minecraft
# version 0.3.7 2012-03-06 (YYYY-MM-DD)

### BEGIN INIT INFO
# Provides:   minecraft
# Required-Start: $local_fs $remote_fs
# Required-Stop:  $local_fs $remote_fs
# Should-Start:   $network
# Should-Stop:    $network
# Default-Start:  2 3 4 5
# Default-Stop:   0 1 6
# Short-Description:    Minecraft server
# Description:    Starts the minecraft server
### END INIT INFO

#Settings
SERVICE='minecraft_server.jar'
OPTIONS='nogui'
USERNAME='miner'
WORLD='world'
MCPATH='/opt/minecraft'
BACKUPPATH='/media/archive/minecraft.backup'
CPU_COUNT=1
INVOCATION="java -Xmx1024M -Xms1024M -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalPacing -XX:ParallelGCThreads=$CPU_COUNT -XX:+AggressiveOpts -jar $SERVICE $OPTIONS"

ME=`whoami`
as_user() {
  if [ $ME == $USERNAME ] ; then
    bash -c "$1"
  else
    su - $USERNAME -c "$1"
  fi
}

mc_start() {
  if  pgrep -u $USERNAME -f $SERVICE > /dev/null
  then
    echo "$SERVICE is already running!"
  else
    echo "Starting $SERVICE..."
    cd $MCPATH
    as_user "cd $MCPATH && screen -dmS minecraft $INVOCATION"
    sleep 7
    if pgrep -u $USERNAME -f $SERVICE > /dev/null
    then
      echo "$SERVICE is now running."
    else
      echo "Error! Could not start $SERVICE!"
    fi
  fi
}

mc_saveoff() {
  if pgrep -u $USERNAME -f $SERVICE > /dev/null
  then
    echo "$SERVICE is running... suspending saves"
    as_user "screen -p 0 -S minecraft -X eval 'stuff \"say SERVER BACKUP STARTING. Server going readonly...\"\015'"
    as_user "screen -p 0 -S minecraft -X eval 'stuff \"save-off\"\015'"
    as_user "screen -p 0 -S minecraft -X eval 'stuff \"save-all\"\015'"
    sync
    sleep 10
  else
    echo "$SERVICE is not running. Not suspending saves."
  fi
}

mc_saveon() {
  if pgrep -u $USERNAME -f $SERVICE > /dev/null
  then
    echo "$SERVICE is running... re-enabling saves"
    as_user "screen -p 0 -S minecraft -X eval 'stuff \"save-on\"\015'"
    as_user "screen -p 0 -S minecraft -X eval 'stuff \"say SERVER BACKUP ENDED. Server going read-write...\"\015'"
  else
    echo "$SERVICE is not running. Not resuming saves."
  fi
}

mc_stop() {
  if pgrep -u $USERNAME -f $SERVICE > /dev/null
  then
    echo "Stopping $SERVICE"
    as_user "screen -p 0 -S minecraft -X eval 'stuff \"say SERVER SHUTTING DOWN IN 10 SECONDS. Saving map...\"\015'"
    as_user "screen -p 0 -S minecraft -X eval 'stuff \"save-all\"\015'"
    sleep 10
    as_user "screen -p 0 -S minecraft -X eval 'stuff \"stop\"\015'"
    sleep 7
  else
    echo "$SERVICE was not running."
  fi
  if pgrep -u $USERNAME -f $SERVICE > /dev/null
  then
    echo "Error! $SERVICE could not be stopped."
  else
    echo "$SERVICE is stopped."
  fi
}

mc_update() {
  if pgrep -u $USERNAME -f $SERVICE > /dev/null
  then
    echo "$SERVICE is running! Will not start update."
  else
    MC_SERVER_URL=http://s3.amazonaws.com/MinecraftDownload/launcher/minecraft_server.jar?v=`date | sed "s/[^a-zA-Z0-9]/_/g"`
    as_user "cd $MCPATH && wget -q -O $MCPATH/minecraft_server.jar.update $MC_SERVER_URL"
    if [ -f $MCPATH/minecraft_server.jar.update ]
    then
      if `diff $MCPATH/$SERVICE $MCPATH/minecraft_server.jar.update >/dev/null`
      then
        echo "You are already running the latest version of $SERVICE."
      else
        as_user "mv $MCPATH/minecraft_server.jar.update $MCPATH/$SERVICE"
        echo "Minecraft successfully updated."
      fi
    else
      echo "Minecraft update could not be downloaded."
    fi
  fi
}

mc_backup() {
   mc_saveoff

   NOW=`date "+%Y-%m-%d_%Hh%M"`
   BACKUP_FILE="$BACKUPPATH/${WORLD}_${NOW}.tar"
   echo "Backing up minecraft world..."
   #as_user "cd $MCPATH && cp -r $WORLD $BACKUPPATH/${WORLD}_`date "+%Y.%m.%d_%H.%M"`"
   as_user "tar -C \"$MCPATH\" -cf \"$BACKUP_FILE\" $WORLD"

   echo "Backing up $SERVICE"
   as_user "tar -C \"$MCPATH\" -rf \"$BACKUP_FILE\" $SERVICE"
   #as_user "cp \"$MCPATH/$SERVICE\" \"$BACKUPPATH/minecraft_server_${NOW}.jar\""

   mc_saveon

   echo "Compressing backup..."
   as_user "gzip -f \"$BACKUP_FILE\""
   echo "Done."
}

mc_command() {
  command="$1";
  if pgrep -u $USERNAME -f $SERVICE > /dev/null
  then
    pre_log_len=`wc -l "$MCPATH/server.log" | awk '{print $1}'`
    echo "$SERVICE is running... executing command"
    as_user "screen -p 0 -S minecraft -X eval 'stuff \"$command\"\015'"
    sleep .1 # assumes that the command will run and print to the log file in less than .1 seconds
    # print output
    tail -n $[`wc -l "$MCPATH/server.log" | awk '{print $1}'`-$pre_log_len] "$MCPATH/server.log"
  fi
}

#Start-Stop here
case "$1" in
  start)
    mc_start
    ;;
  stop)
    mc_stop
    ;;
  restart)
    mc_stop
    mc_start
    ;;
  update)
    mc_stop
    mc_backup
    mc_update
    mc_start
    ;;
  backup)
    mc_backup
    ;;
  status)
    if pgrep -u $USERNAME -f $SERVICE > /dev/null
    then
      echo "$SERVICE is running."
    else
      echo "$SERVICE is not running."
    fi
    ;;
  command)
    if [ $# -gt 1 ]; then
      shift
      mc_command "$*"
    else
      echo "Must specify server command (try 'help'?)"
    fi
    ;;

  *)
  echo "Usage: $0 {start|stop|update|backup|status|restart|command \"server command\"}"
  exit 1
  ;;
esac

exit 0

[[Category:Server]]

And then this is the crontab entry to run the backup every 30 minutes:

0,30 * * * * mount /media/archive && /etc/init.d/minecraft backup; umount /media/archive

UPDATE 20120703 1110 hours:  The server is open for business at IP 67.53.8.172.  I will register a DNS entry shortly.  Currently we have only Bjorn and myself whitelisted.  Post a comment to this page to add your name and tell me who you are.  ATM, only IRL friends are welcome here.

Read the rest of this entry »

38 Comments

Sysadmin Day Celebration

On Friday, July 27, I will be celebrating System Administrator Appreciation Day (and potentially getting a job, depending).  My default place to celebrate is Old German Beer Hall.  But there are some others.  As I am fond of polls, here’s one:

3 Comments

Embracing the Dark Side

For years, I’ve resisted the move to the Microsoft way, it being driven entirely by warped corporate logic rather than technical excellence and innovation.  But it seems now that in the enterprise, Linux and Perl are now completely irrelevant.  One recruiter I met with had never even heard of them.  So I’ve decided to learn C#, ASP.NET and Microsoft Sharepoint, as well as how to develop apps for Android.  I still need a job and if learning .NET and Sharepoint is the only way to stay in IT, then I guess I have to.

I’ve seen tons of hype that the Cloud will generate 15 thousand IT jobs but does anyone actually know how to learn the skills employers want in whatever it is cloud people do?

Leave a comment

Learning in spare time

As things move to the cloud, I find it’s becoming more difficult to learn essential IT skills on your own.  I used to be able to learn some basic system admin skills, software development skills, etc. on a home PC or maybe a home LAN setup with Linux, cheap-to-free tools, evaluation versions, etc.  Nowadays, I’m finding it difficult to learn how to do stuff they’re asking for in job descriptions like “Large multiglobal enterprise support” and “Netscaler” and “IBM Websphere” and VMWare and Windows Server.  Seriously – I can’t afford to buy a Windows Server license just to learn Windows server!  Nor can I buy a large enterprise (complete with private cloud and SAN and other current IT stuff) to learn how to work in one.  How do I get those skills?

Leave a comment