Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Initial commit of some small utility programs.

See the README for an overview.
  • Loading branch information...
commit 21e416e0c65ec082ec804e6378429d2a59686cf2 0 parents
@dripton authored
13 README
@@ -0,0 +1,13 @@
+Some random small programs that might be useful.
+
+backup.py -- This is my backup system, using rsync and hardlinks.
+
+finddupes.py -- Find files with duplicate MD5 checksums.
+
+nettest.py and parse_nettest.py -- Track the reliability of your network.
+
+number_oggs.py -- Add numbers to my music files so they sort correctly on
+my portable music player.
+
+portscan.py -- Multi-threaded port scanner to find where on my home network my
+print server is hiding today.
67 backup.py
@@ -0,0 +1,67 @@
+#!/usr/bin/python
+
+"""Backup most of a filesystem to a backup disk, using rsync."""
+
+import subprocess
+import time
+import os
+
+SOURCE = "/"
+DESTINATION = "/mnt/backup"
+EXCLUDES = [
+ "/proc",
+ "/sys",
+ "/lost+found",
+ "/mnt",
+ "/media",
+ "/tmp",
+ "/var/tmp",
+ "/var/run",
+ "/var/lock",
+]
+RSYNC = "/usr/bin/rsync"
+MOUNT = "/bin/mount"
+
+def mount_backup_disk():
+ cmd = [MOUNT]
+ proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
+ stdout, unused = proc.communicate()
+ if DESTINATION in stdout:
+ print "%s already mounted" % DESTINATION
+ return
+ cmd = [MOUNT, DESTINATION]
+ returncode = subprocess.call(cmd)
+ print "%s returned %d" % (cmd, returncode)
+
+def find_latest_destdir():
+ latest = 0
+ for fn in os.listdir(DESTINATION):
+ if fn.isdigit() and len(fn) == 14:
+ timestamp = int(fn)
+ latest = max(timestamp, latest)
+ if latest:
+ return str(latest)
+ return None
+
+def do_rsync():
+ cmd = [RSYNC]
+ cmd.append("-ab")
+ for exclude in EXCLUDES:
+ cmd.append("--exclude=%s" % exclude)
+ latest = find_latest_destdir()
+ if latest:
+ cmd.append("--link-dest=%s" % (os.path.join(DESTINATION, latest)))
+ cmd.append(SOURCE)
+ timestamp = time.strftime("%Y%m%d%H%M%S")
+ cmd.append(os.path.join(DESTINATION, timestamp))
+ print cmd
+ returncode = subprocess.call(cmd)
+ print "%s returned %d" % (cmd, returncode)
+
+def main():
+ mount_backup_disk()
+ do_rsync()
+
+
+if __name__ == "__main__":
+ main()
40 finddupes.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+
+import os
+import sys
+import hashlib
+
+def find_dupes(dirs):
+ size_to_paths = {}
+ for dir_ in dirs:
+ for fn in os.listdir(dir_):
+ path = os.path.join(dir_, fn)
+ if os.path.isfile(path):
+ size = os.path.getsize(path)
+ size_to_paths.setdefault(size, []).append(path)
+ md5_to_paths = {}
+ for size, paths in size_to_paths.iteritems():
+ if len(paths) > 1:
+ for path in paths:
+ with open(path) as fil:
+ contents = fil.read()
+ hasher = hashlib.md5()
+ hasher.update(contents)
+ md5 = hasher.hexdigest()
+ md5_to_paths.setdefault(md5, []).append(path)
+ for md5, paths in md5_to_paths.iteritems():
+ if len(paths) > 1:
+ for path in paths:
+ print path
+ print
+
+
+def main():
+ if len(sys.argv) == 1:
+ dirs = ["."]
+ else:
+ dirs = sys.argv[1:]
+ find_dupes(dirs)
+
+if __name__ == "__main__":
+ main()
60 nettest.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+
+"""Log whether the Internet connection is up.
+
+Call this script from cron every few minutes. Append the output
+to a file. It will contain a Unix timestamp then a 1 for up or
+0 for down.
+"""
+
+# Configuration
+public_hosts = set([
+ "http://yahoo.com",
+ "http://google.com",
+ "http://myspace.com",
+ "http://msn.com",
+ "http://ebay.com",
+ "http://amazon.com",
+ "http://craigslist.org",
+ "http://cnn.com",
+ "http://wikipedia.org",
+])
+
+num_retries = 2
+
+
+import time
+import random
+import urllib
+import socket
+
+def pick_random_host(tried):
+ host = random.choice(list(public_hosts - tried))
+ tried.add(host)
+ return host
+
+def connect_to_host(host):
+ try:
+ fil = urllib.urlopen(host)
+ unused = fil.read()
+ return unused
+ except IOError:
+ return False
+
+def is_internet_up():
+ tried = set()
+ while len(tried) < num_retries:
+ host = pick_random_host(tried)
+ connected = connect_to_host(host)
+ if connected:
+ return True
+ return False
+
+def main():
+ socket.setdefaulttimeout(20)
+ now = int(time.time())
+ up = int(is_internet_up())
+ print "%d %d" % (now, up)
+
+if __name__ == "__main__":
+ main()
54 number_oggs.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python
+
+"""Number my .ogg files
+
+A directory has m3u files with names like $artist-$album.m3u
+Songs fit into a directory structure like:
+ $artist/$album/$song.ogg
+The m3u file lists songs, one per line, in order:
+ $artist/$album/$song.ogg
+We want to prepend "$tracknumber-" to each song title, in both
+the ogg filename and within the m3u file. Track numbers should
+be in %02d format.
+
+Skip songs that already have track numbers.
+"""
+
+import sys
+import os
+
+def main():
+ for fn in sys.argv[1:]:
+ if fn.endswith(".m3u"):
+ process_m3u(fn)
+
+def process_m3u(fn):
+ fil = open(fn)
+ line_number = 0
+ out_lines = []
+ for line in fil:
+ line_number += 1
+ song_path = line.strip()
+ if not os.path.exists(song_path):
+ # Just remove data.ogg noise by hand
+ print "file not found", song_path
+ return
+ dirname = os.path.dirname(song_path)
+ basename = os.path.basename(song_path)
+ track = "%02d-" % line_number
+ if basename.startswith(track):
+ print "already has track number", song_path
+ return
+ new_path = os.path.join(dirname, track + basename)
+ os.rename(song_path, new_path)
+ out_lines.append(new_path)
+ fil.close()
+
+ fil = open(fn, "w")
+ for line in out_lines:
+ print >> fil, line
+ fil.close()
+
+
+if __name__ == "__main__":
+ main()
46 parse_nettest.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+
+"""Parse the output of nettest.py into a human-readable list of
+outage periods.
+
+The input is a sorted list of lines like:
+
+1157962502 0
+1157962802 1
+
+where the first number is a Unix timestamp, and the second is a 0
+for Internet connection down or 1 for Internet connection up.
+"""
+
+import sys
+import time
+
+def prettify(timestamp):
+ return time.ctime(int(timestamp))
+
+
+def main():
+ if len(sys.argv) != 2:
+ print "usage: %s nettest-log-filename" % sys.argv[0]
+ return 1
+ filename = sys.argv[1]
+ fil = open(filename)
+ prev_timestamp = None
+ prev_up = None
+ for line in fil:
+ tokens = line.strip().split()
+ timestamp, up = tokens
+ if prev_timestamp is None:
+ prev_timestamp = timestamp
+ elif up != prev_up:
+ if up == "1" and prev_up =="0":
+ print prettify(prev_timestamp), "-", prettify(timestamp)
+ else:
+ prev_timestamp = timestamp
+ prev_up = up
+ if not up:
+ print prettify(prev_timestamp), "-", prettify(timestamp)
+
+
+if __name__ == "__main__":
+ main()
53 portscan.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+
+"""Hunting for the TrendNet print server"""
+
+import socket
+import threading
+import Queue
+
+socket.setdefaulttimeout(5)
+
+port = 631
+num_threads = 250
+
+class ConnectThread(threading.Thread):
+ def __init__(self, in_queue, out_queue):
+ threading.Thread.__init__(self)
+ self.in_queue = in_queue
+ self.out_queue = out_queue
+ self.setDaemon(True)
+
+ def run(self):
+ while True:
+ ip = self.in_queue.get()
+ try:
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ sock.connect((ip, port))
+ except socket.error:
+ self.out_queue.put((ip, False))
+ else:
+ self.out_queue.put((ip, True))
+ self.in_queue.task_done()
+
+def main():
+ job_queue = Queue.Queue()
+ result_queue = Queue.Queue()
+ count = 0
+ for net in range(1, 255+1):
+ for addr in range(1, 255 + 1):
+ ip = "10.2.%d.%d" % (net, addr)
+ count += 1
+ job_queue.put(ip)
+ for unused in xrange(num_threads):
+ ConnectThread(job_queue, result_queue).start()
+ job_queue.join()
+
+ for unused in xrange(count):
+ ip, status = result_queue.get()
+ if status:
+ print ip
+
+
+if __name__ == "__main__":
+ main()

0 comments on commit 21e416e

Please sign in to comment.
Something went wrong with that request. Please try again.