Posts for the month of May 2012

RPM Compression

The other day at work I noticed that at the end of an RPM build, it seemed to hang. It turns out, it was compressing the files to create the installer. I'd rather not have it do that if I am building development versions since they only get scp'd to a lab environment.

Even if it does compress, I'd like to have feedback as to what it is doing. So I added these lines to my .spec file. They should be easy enough to tweak and add to a system-level macros file.

Background: We had "dev" appended to the version number already, so this was the easiest way to do it:

%if 0%(echo %{rpm_version} | grep -c dev)
%define _source_payload w0.gzdio %%{echo:Skipping source RPM compression...}
%define _binary_payload w0.gzdio %%{echo:Skipping binary RPM compression...}
%define _source_payload w9.gzdio %%{echo:Maximum source RPM compression...}
%define _binary_payload w9.gzdio %%{echo:Maximum binary RPM compression...}
%global _enable_debug_packages 0
%global _debug_package %{nil}

So now my RPMs are about four times as large as they were, but are built a lot faster.

Email your new IP address with TomatoUSB

So my router is now TomatoUSB and I wanted an alert when the IP changed. Sure, I could probably put something local on the router, but where's the fun in that?

So I put together a quick python script to drop me an email if the IP ever changes. Yes, TomatoUSB supports various Dynamic DNS services, but doesn't seem to natively support "email me."

So on the DDNS setup page, I chose the "Custom URL" service, and I put in "http:[email protected]" as the URL (the internal address of an Apache server running WSGI.

I have a custom config file /etc/httpd/conf.d/wsgi_IP as follows:

WSGIScriptAlias /IPCHECKS /var/www/wsgi/IP.wsgi

<Directory "/var/www/wsgi/">
  WSGIApplicationGroup %{GLOBAL}
  Order deny,allow
  Deny from all
  Allow from 192 127 ::1

HOPEFULLY that means none of you can change what I think my IP address is. ;)

Here's the actual python script (/var/www/wsgi/IP.wsgi):

from __future__ import print_function
from cgi import parse_qs, escape
import socket
import smtplib

# This is RevRagnarok's ugly IP checker.
# Tomato (firmware) will post to us with a "new_ip" parameter
# At this point, I want to see manually that the IPs change, not have it autoupdate
# Note: I had to enable HTTP sending email in SELinux:
# setsebool -P httpd_can_sendmail 1

def application(environ, start_response):
    parameters = parse_qs(environ.get('QUERY_STRING', ''))
    if 'new_ip' in parameters:
        newip = escape(parameters['new_ip'][0])
        newip = 'Unknown!'
    start_response('200 OK', [('Content-Type', 'text/html')])
    # Look up DNS values
    oldip = socket.gethostbyname('') # Yes, IPv4 only
    # Compare
    changed = ''
    if newip != oldip:
        changed = 'IP changed from {0} to {1}.'.format(oldip, newip)
    if changed:
        e_from = [email protected]'
        e_to = [[email protected]']
        e_msg = """Subject: IP Address change detected

        # I considered a try/catch block here, but then what would I do?
        smtpObj = smtplib.SMTP('localhost')
        smtpObj.sendmail(e_from, e_to, e_msg)
       changed = '(unchanged)'
       changed = 'IP is {0} (unchanged).'.format(newip)
    return [changed]

And don't forget, if you use SELinux, fix permissions on the script, and allow the webserver to send email:

[[email protected] wsgi]# ls -Z IP.wsgi 
-rw-r--r--. root root system_u:object_r:httpd_sys_script_exec_t:s0 IP.wsgi
[[email protected] wsgi]# setsebool -P httpd_can_sendmail 1

Optional requirements for RPM

(Wow, it's been over a year since my last blog post...)

At work, I have a program that optionally could use the Qt libraries, but I didn't want my RPM to actually require like it wanted to. And RPM doesn't seem to support an "OptRequires" or something similar... so here's my hack of a solution.

I put this script named find-requires into my project's "build" subdirectory so it is included in the "Source" tarball that rpmbuild will be using. I wrote it to be expandable.

#!/usr/bin/perl -w
use strict;
use IPC::Open2;

# This quick script will run the native find-requires (first parameter)
# and then strip out packages we don't want listed.

open2(\*IN, \*OUT, @ARGV);
print OUT while (<STDIN>);
my $list = join('', <IN>);

# Apply my filter(s):
$list =~ s/^*?$//mg;

print $list;

Then put in your .spec file this, which will call our script with the original script as the first parameter:

# Note: 'global' evaluates NOW, 'define' allows recursion later...
%global _use_internal_dependency_generator 0
%global __find_requires_orig %{__find_requires}
%define __find_requires %{_builddir}/%{?buildsubdir}/build/find-requires %{__find_requires_orig}