I wanted to know whether I could use some tricks to make more efficient use of the 4GB Compact Flash storage i have in my Alix (running Gentoo Linux). I would like to keep a local portage tree on it — it currently mounts the tree over NFS due to space concerns.
Why no harddisk? Because that goes against the idea of having a small, reliable, always-on, energy-efficient home server.
Techies like pictures of hardware with the cover off so here’s my Alix:
Such a setup can lead to unfortunate situations, such as needing a package to restore connectivity to the network on which the fileserver resides that contains the package that I need to restore connectivity to the network on which… see where I’m going? Nowhere! ;-)
The portage tree fulfills the role of a package database for us Gentoo ricers. I need it locally.
I wanted to quickly find out what filesystem block size would suit different parts of my filesystem (such as /etc/, /usr/src/linux/, /usr/portage/, /var/db/pkg/) best, and how much I could save. Testing all block sizes with all parts of my FS was not very appealing, so I decided to simply calculate the file slack and wrote this simple Python script:
#!/usr/bin/env python3"""
slacktastic.py - calculate filesystem file slack for different block sizes.
Invoke me thusly:
find /path/to/tree -xdev -type f -printf "%s\\n" | slacktastic.py 4096
for a calculation using the contents below /path/to/tree with a block size of 4096 bytes.
"""importsys, functools, math
blksz = Nonetry:
blksz = int(sys.argv[1])except(IndexError,ValueError):
print(__doc__, file=sys.stderr)print('I need a blocksize as the first argument.\n', file=sys.stderr)sys.exit(1)
sizes = [int(strsize)for strsize insys.stdin.read().strip().split('\n')]
sumslack = functools.reduce(lambda sumslack, sz: sumslack + (blksz - (sz % blksz)), sizes, 0)
sumblks = functools.reduce(lambda sumblks, sz: sumblks + (math.ceil(sz / blksz)), sizes, 0)
sumsizes = sum(sizes)print('{:n} total slack'.format(sumslack))print('{:n} bytes in files'.format(sumsizes))print('{0:n} total blocks of {1} bytes'.format(sumblks,blksz))print('{:.2%} inefficiency'.format( sumslack / (sumblks*blksz)))
This doesn’t take into account things such as tail packing (à la ReiserFS), compression (Btrfs), or directory slack. Just file slack.
On my laptop filesystem, with a 4096 block size, this leads to the following observation:
find /var/db/pkg -xdev -type f -printf "%s\n" | slacktastic.py 4096
171942364 total slack
92655140 bytes in files
64506 total blocks of 4096 bytes
65.08% inefficiency
My /var/db/pkg, Gentoo’s ‘database’ of installed packages (containing their build environment and all kinds of stuff you wouldn’t need on a binary distro) contains 65% air! That’s 170 megs of waste which I don’t want that on my Alix’s 4GB CF card. With a 1024 byte block size — Ext4’s minimum — the situation is better, but it’s still over 40 megs of hot air.
I ended up choosing btrfs with compression. It has a fixed 4096 byte leaf/node size but it does tail packing (good for small files) and compression (for my /var/log). My script is useless for estimations on such a filesystem so I ran some actual tests and it turns out I can fit my /usr/src/linux, /var/db/pkg, /var/log and /usr/portage on a 1GB btrfs filesystem. They didn’t fit on an bs=1024b Ext4 FS.
But there may have been more to it than improper validation. One of the many ways Facebook comes up with suggestions running along the lines of “so-and-so is now on facebook, do you know her? let’s connect!” is to entice you to give your password to third-party services (they call this “add friends from your address book”). So suppose you had mary@jane.com in your Gmail address book at that time, and you let Facebook read this address book, then Facebook stores the mary@jane.com address (possibly indefinately) as one of your “friend candidates”.
Some time later, Mary Jane registers a Facebook account, using her mary@jane.com email address – the one that’s also on record as one of your friend candidates. Ping! Facebook sends you a message, enticing you to connect1.
Of course, this all falls down when Mary registers using a sub-addressed address, e.g., mary+facebook@jane.com. She might want to do this to channel the flood of facebook-originating email into a separate folder. mary+facebook@jane.com is probably not on file with you or anyone else, since if you want to send her an email, you’d send it to mary@jane.com — so that’s what was in your Gmail address book.
Sub-addresses: Bad for business, unless…
That brings me to the following conspiracy theory: Initially, Facebook disallowed sub-addressed email addresses (under the guise of a “broken” validator?) because those interfere with their goal of engaging you with as many people as possible (via friend suggestions), so as to have your eyeballs on their site and in front of their advertisers until they bleed (the eyeballs, not the advertisers).
At a certain moment in the past 28 months, they fixed the improper ‘invalid email address’ designation of sub-addressed accounts. Good for facebookers, bad for business — unless they parse the email address and drop the part between the + and the @. Thing is, sub-addressing is not a standard. On my mailserver, I can specify a character other than + to use as an extension designator. It’s up to the mailserver to do something useful or silly with the sub-addressing. There are no formal semantics. If there is a + in the user-part of an email address, that does not necessarily mean that it is sub-addressed.
My guess is that Facebook made their address matching fuzzy, to account for many possibilities. They’ll plunder your address book and will still figure out that you and Mary Jane are acquainted, no worries.
Tinfoil hat
Well, I do worry.
On the web, your email address is a key to your identity. Your identity is something which many organizations (advertisers, some governments, …) very much like to link across natural domain boundaries. I don’t think that many organizations have updated their address matching algorithms with fuzzyness… yet. So at the moment, it’s still a good idea to sign up to sites and services using unique, subaddressed email accounts. But to be futureproof, you’ll need to defeat fuzzy matchers that take the many forms of sub-addressing into account. It’s probably best to just register a domain and have all email arriving at that domain be delivered to one account. That way, you can easily use any email address at that domain when signing up. If you don’t want to run your own mail server, the one that Google provides you with if you take Google Apps on your domain allows just that. But I’m not so sure that recommendation is solid advice, privacy-wise…
1)Possibly, and hopefully, they do some cross-checking first.
For a little while I’ve been running a DIY dynamic DNS service. My peers think it’s convenient and pretty sweet, so in this post I’ll set things straight — a full disclosure on the mess that it really is ;-)
What is a dynamic DNS service?
Since the dial-up days of yore I have occasionaly been using “dynamic DNS” services. What is a “dynamic DNS” service, you ask? Well, it’s a marketing term, not a technical term, but most providers of such services allow for having some CNAME or A record point to an IP, and this pairing is updatable over HTTP. Usually they use a freemium business model where you can get a couple of subdomains on their second level domains.
Why use one?
An example of a use case: You run a development server on your laptop. You want someone to connect to it. Instead of saying to this person “now just go to… errr… hold on” (and now you pop your shell and run ip a s dev wlan0)1 “yes I’m back, you need to go to 110.34.56.250″ you can just say “go to kleinebeer.ath.cx”. Much easier. And that’s with IPv4. Typing an IPv6 address that someone just yelled at you from across the room is an even less joyful experience.
To enable this use case you configured your machine in such a way that every time your interface aquires a new IP, a program contacts the “dynamic DNS service” to update the ‘kleinebeer’ DNS record to reflect this IP. There are many clients for such services out there. I have even seen domestic ADSL modem/routers on which the factory firmware contains such a client.
Doing it differently
But some time ago I got fed up with all the “account expiration warning” emails I had been getting from the service that I used. And since I’m quite familiar with the components you need for building such a service yourself, I set out to do so. The thing I ended up with is for personal use, specific to my needs, KISS, and sinful.
Sins!
It allows for instant creation/updating of DNS records through a very simple HTTP GET. That is sinful for two reasons:
No authentication and authorization.
Anyone can create any record. And anyone can update any record he or she knows the name of. You understand how this could be a bad thing. Don’t have such names as MX records unless you don’t mind that mail intended for you ends up on someone else’s server.
At the same time it is a good thing, as I will show in the use case example below.
The HTTP GET alters state.
And that’s just plain Bad Taste. If you’re designing a web service you’ll usually try to make it RESTful. GET should be a safe method. But for this application, at the frontend, it is actually desirable — because grandma can GET, as you will see in the use case below.
Use cases
Case A:
Imagine you’re on the phone with your grandma, and after discussing apple pie recipes something else comes up and you need to know her IP (let’s say you need to SSH in and help her with her crontab). She hasn’t registered with any dynamic DNS service, she has a hard time determining her IP, she has a hard time reading it out loud without making mistakes, and you are fed up with typing IPs anyway. But she has a web browser. Wouldn’t it be nice if you could just tell her to open her browser and head over to http://grandma.reg-a-record.tld/reg.php ? Nothing to install, nothing to look up, and something reasonably simple for grandma to do. The script on http://grandma.reg-a-record.tld/reg.php creates a DNS A record named ‘grandma’ on dyndomain.tld, and this record points to your grandma’s IP. Now you can just do ’ssh grandma.dyndomain.tld’.
Case B:
Imagine you and your friends are on a coding binge, all running their Django/Rails/Node.js/Thing-du-jour instances on laptops, in the same room, and you all want to connect to each other’s development servers.
You could all call out your IPs across the room and let everyone type in everyone else’s IPs. Now you all have N tabs open in your browsers. Who was 123.231.101.45 again?
Or, everyone could just point their browser (or curl, wget…) to http://theirfirstname.reg-a-record.tld/reg.php2 and be done with it. If you want to view Fred’s progress you just go to fred.dyndomain.tld.
So, sin #1 & #2 allow for use cases that were not possible with the provider I was using.
You don’t have to register the records up front with some service provider. You can make up records as you go, and you want to be able to let anyone create any record. Hence sin #1. But it’s a good thing. You don’t have to reuse records, which is better for your privacy. With the commercial service I could only use a couple of names, so anyone whom I once had told to go to kleinebeer.ath.cx could kinda virtually follow me around and determine whether I was at work, home, uni or girlfriend by resolving this record. When creating new records is incredibly easy, there’s no reason to keep using the same name every time.
On to the code
It’s very, very simple! You need very little code. Things can be made much simpler than I have done. For byzantine reasons I use two webservers, one has a python CGI which creates the actual records, and the other one runs the public-facing PHP script (through mod_php) which you actually connect to.
DNS server
You need a domain for which you run the authoritative name server. I’m using the SheerDNS DNS server package on mine, for no good reason. Here’s a patch I made so that sheerdnshash creates directories with some group permission bits set, something I need in my setup.
You can use other DNS servers, of course. I discovered that the Unbound DNS server has a socket protocol which you can possibly use to add records on the fly. But I use sheerdns now, and here’s a Python module I made to write A-records in sheerdns’s directory structure. Public domain, use it as you see fit. You need to modify the constants to reflect your config, and you can test it by running the module from a shell.
#!/bin/env pythonimportsocket,os,string,subprocess,sys
SHEERDNS_DIR="/var/sheerdns"
SHEERDNS_HASH="/usr/sbin/sheerdnshash"
DYNDOMAIN="dyndomain.tld"
ALLOWCHARS=string.ascii_letters + ''.join(["%d"% i for i inrange(10)]) + '-'def mk_A(name,ip):
#are host and ip allright?
host = ''.join([ c for c in name if c in ALLOWCHARS ]).lower()ifnot host:
returnNonetry:
socket.inet_aton(ip)exceptsocket.error:
returnNone
fqdn = "%s.%s"%(host, DYNDOMAIN)#set the umask
oldumask = os.umask(0002)#get the hashhash = subprocess.Popen([SHEERDNS_HASH, fqdn], stdout=subprocess.PIPE).communicate()[0].strip()#construct the dirpath
path = os.path.join(SHEERDNS_DIR,hash,fqdn)#chmod it for everyone to reados.chmod(path,0755)#construct the A-record-filepath
apath = os.path.join(path,'A')#open the record filewithopen(apath,'w')as record:
record.write(ip)os.umask(oldumask)return name
if __name__ == '__main__':
iflen(sys.argv) == 3:
print(mk_A(sys.argv[1],sys.argv[2]))
Web ’service’ to create the records: a CGI
This is a Python CGI which uses the above module. I stick it behind HTTP Basic authentication which is handled by the web server. You call it like this: http://server_that_has/the_CGI?name=therecordname&ip=theip .
There’s no reason that this CGI should be guilty of Sin #2, except laziness on my behalf. If I’d be following every convention even for silly little solo projects I’d never get anything done, all right?
It doesn’t propagate any errors from the sheerdns library, but it prints the name as it is registered — stripped of disallowed characters, or nothing if something failed along the way (invalid IP, for instance).
#!/usr/bin/pythonimport sheerdns
importcgiprint"Content-type: text/plain\n\n";
params = cgi.parse()
name, ip = params.get('name'), params.get('ip')if ip and name:
dnsname = sheerdns.mk_A(name[0],ip[0])print dnsname
The accessible part: reg.php
This is in PHP. It lives in the default virtual host of my Apache config, and for good reasons. I have a CNAME record that points *.reg-a-record.tld to this web server. I then use whatever is in * to construct the name for the dyndomain.tld-record. The wildcard record is essential.
You need to modify this script to reflect your config.
If you visit http://kitten.reg-a-record.tld/reg.php, the IP address that the web server sees you coming from gets registered as kitten.dyndomain.tld. If everything went well, the script responds with this mapping.
You could set DirectoryIndex reg.php here, or rename reg.pgp to index.php, if you don’t want users to type ‘reg.php’. I did make it explicit, because web sites on this server come and go and I don’t want people to stumble onto reg.php every time they hit the default vhost because their web site doesn’t exist any more.
1)Let’s assume you’re not NATed. 2)Try to only have friends with distinct names that can be expressed in ASCII.
While planning my upcoming “Except Hungary”1 cycling trip I did some research on land mines, since I might find myself passing through areas mined during the Yugoslav wars of the 90’s.
Croatia is one of the world’s worst affected countries when it comes to land mines, right up there with Angola and Cambodia. In the Croatian War of Independence, a grand total of about 3M anti-personnel mines have been laid in border areas — both sides were stretched on personnel, and Croatia happens to have very long borders (it has quite an unusual shape). About 100K mines have yet to be cleaned up — a rather costly business (at $300-$3K a pop (no pun intended), according to the Red Cross). Perhaps bees will come and help out.
Of course I’m not the first to wonder about the perils of traveling through such regions. Shallow googling (or duck-duck-go-ing as I tend to do nowadays) does not yield any comprehensive information on the location of the mined areas. It mostly boils down to “don’t go off the beaten track” and “tourist areas are safe”, “ask the locals”, “look for signs”, “nah. most of them are up north in cow country now why would you want to visit our cows, go visit our beaches instead”.
My land usage patterns are often quite different from those of other tourists. I camp out in a small tent in the fields. My usual method of finding a suitable spot to pitch said tent is to scoot up some dirt tracks and stroll into those fields willy-nilly. At dusk.
From a health perspective, this mode of habitation-seeking is incompatible with mine fields.
Luckily, the CROMAC (Croatian Mine Action Centre) offers a web-based GIS application showing, in detail, all areas suspected to be mined. An overview of how the GISing of military maps, aerial photography and other sources of information comes about is provided in this presentation.
It appears many mine fields (~60%) are in forests (or: some forests are on mine fields), possibly because these have had the lowest priority in de-mining operations and/or because abandoned fields tend to become forested.
As for Serbia, I won’t be passing through the locations mentioned on the “Landmine and Cluster Munitions Monitor” report. There’s talk of mine fields near the Kosovo border but the Kroatian border appears to be fully demined on the Serbian side. Unexploded cluster bomblets from the NATO bombardments are not found north of Beograd.
So now I’m coloring mined regions on the map of Croatia which I will take with me on my bicycle journey. It’s a solemn activity, and a weird thing to do — marking up mine fields is not a standard part of the holiday planning process. These mines were laid twenty years ago. I was still in primary school then. I remember watching weekly reports on “school-TV weekjournaal” and discussing them in class. There was a refugee girl from Bosnia2 in our class, I think her name was Çenka.
And it never occured to me that contaminating an area with land mines can have nonlocal effects. From the country report on Croatia by the “Landmine and Cluster Munitions Monitor”: “Another priority is suspected mine contamination along canals and river banks, which has prevented maintenance and resulted in flooding of ploughed land, particularly along the border with Hungary. In addition to canals, parts of the banks of the Kupa river in Sisak-Moslavina county, the Sava river in Brod-Posavina and Vukovar-Srijem counties, and the Drava river in Osijek-Baranja county are inaccessible due to mine contamination. Protection from flood is also impossible.”
Mining riverbanks is a terrible idea for another reason, too: in autumn and spring torrents, mines can wash away and end up god knows where.
On the bright side, there hasn’t been a casualty caused by a land mine in Croatia since 2006 (except for a 2009 incident with demining personnel — brave people). And the Drava/Danube rivers running wild east of Osijek are bound to offer an undisturbed wetland habitat for avifauna. I see ecotourism opportunities.
1) Not that I dislike Hungary. I spent a wonderful time there back in 2001. But I do dislike cycling on endless plains, so I am trying to avoid the area known as the Great Hungarian Plain (the “Puszta”).
2) In the Bosnian war another 3M mines were laid, often in a haphazard way which makes clearing them an even harder task. The excellent pitch-dark comedy/drama/tragedy “No Man’s Land” revolves around a Bosnian trench, three soldiers, a land mine, and a UNPROFOR/media travesty.
While decrufting my homedir I found some scripts that might be of public* interest — either because of their amusement value, or their utility ;-)
Some are so tiny that you’d actually be better off just defining them as functions in your ~/.{ba,z}shrc .
*) For unixoid values of ‘public’.
groe
Open a file (argument 2) in joe (works with vim, too) with the cursor on the first line matching the regex in argument 1.
#!/bin/bash -euTHEL=$(grep-m1-n${1}${2}|cut-d':'-f1)[-n"$THEL"]&& joe +$THEL $2
paserv
Set pulseaudio server (in X11, for display in $DISPLAY env var) to argument 1. Useful if you use several pulseaudio network audio servers. Without arguments, resets to default.
#!/bin/bashif[-n"${1}"]; then pax11publish -e-S${1}else pax11publish -e -r; fi
gmrun
Wrapper launcher for the excellent “gmrun” program launcher. (queue “yo dawg” meme).
Raises and/or pulls any existing gmrun windows to your current desktop.
Get an X11 authorization cookie for a display on some other host, over SSH.
#!/bin/bashif[-z${1}]; thenecho"Usage: $(basename ${0}) sshstanza"echo""exit2fiSSH=${1}XHO=${1##*@}DIS=${2-":0"}ssh${SSH}"xauth list ${XHO}${DIS} | sort -u"|whileread line; do xauth add ${line}; done
gaap
Ghetto power management. We don’t need no stinkin’ gnome-power-manager, we’ll just grep our keyboard/trackpad interrupt counter thankyouverymuch (I got that idea from reading the xscreensaver man page).
Comes in two parts. is_user_alive:
#!/bin/bash -eu#Succeeds if keystrokes or touchpad input has taken place since last time this was run, or if there is no record of the last run.RECORD=${1:-/dev/shm/i8042_intcnt}RETVAL="1"
upd_intcnt(){grep i8042 /proc/interrupts >${RECORD}}
is_alive(){grep i8042 /proc/interrupts |diff - ${RECORD}>/dev/null 2>&1||RETVAL=0}[!-f${RECORD}]&& upd_intcnt &&exit0
is_alive
upd_intcnt
exit$RETVAL
Run this one (gaap.sh) from cron:
#!/bin/bash -eu
misschien_slapen(){test-f/tmp/koffie || on_ac_power || echt_slapen
}
echt_slapen(){/usr/local/sbin/is_user_alive /dev/shm/gaap_alive ||trueecho-e"Hibernating in 30 secs, unless you prove you're alive by pressing\na key or touching the touchpad. Physically. On ${HOSTNAME}."|wallfor sec in`seq0399`; doecho$sec; sleep1; done|DISPLAY=":0"XAUTHORITY="/home/boer/.Xauthority"sudo-u boer zenity --progress--auto-close--text"hibernate?"||exit0/usr/local/sbin/is_user_alive /dev/shm/gaap_alive ||/usr/sbin/pm-hibernate
}/usr/local/sbin/is_user_alive /dev/shm/gaap_alive || misschien_slapen
You might want to install zenity, and you’ll have to adjust the username. As you can see my laptop is a single-user system. The sudo is therefore a bit silly, but hey, it’s good practice to not present privilege escalation attack surfaces to yourself ;-)
I still need to find a good way of iterating over all X11 displays and finding the user who started the associated X server. Does anyone know of a not-too-hackish approach?
Aphorism slideshow
A friend of mine got married this summer and I got the newlyweds one of those digital photo frames. I preloaded it with a bunch (5.5K) of images generated from my unix fortune database. So it’s kind of a modern incarnation of those tiles that older Dutch generations used to cement onto their walls (Wikipedia entry [Dutch]). Terrible as they are, they’re making a (campy) comeback. Personally I can’t wait for the day that camp culture itself becomes camp (queue another “yo dawg” meme).
Anyway, I made myself this sed script, “str2cu.sed”:
/^%$/d
s/"\([^"]*\)"/“\1”/g
and then did this. Which, the better part of a year later, proves quite hard to reverse-engineer:
for CATG in art definitions education fightclub food hitchhiker humorists kids literature love medicine men-women news paradoxum pets platitudes politics science smac strangelove wisdom work; \
domkdir/home/boer/tmp/fortunes/$CATG; cd/home/boer/tmp/fortunes/$CATG; \
csplit -q-z/usr/share/fortune/$CATG'/%/''{*}' ; for f in/home/boer/tmp/fortunes/$CATG/*; \
docat$f|sed-f/home/boer/tmp/fortunes/str2cu.sed |fmt-w2500|tr-s'\t'| expand -t2>/tmp/fortune; \
mv/tmp/fortune $f; done; find/home/boer/tmp/fortunes/$CATG/-type f -size +200c -execrm'{}' \; ; \
for f in/home/boer/tmp/fortunes/$CATG/*; do convert -background pink -fill white -size 480x234 \
-stroke black -gravity Center -font Essays1743-Bold caption:@$f$f.jpg; done; done
GNU textutils are fun… but holy cow. What an obtuse kludge.
A simple python script could have done all the work up until the image generation (which is done with imagemagick, it has a nice auto text scaling feature, did you know?).
SQLite is great for ad-hoc SQL DB-ing, but it’s not so great if you need to serve multiple processes (on writing, it locks the complete database).
It just so happens that, for a certain project, I need the ad-hocishness of SQLite *and* multiprocess write concurrency.
It appears that PostgreSQL can easily be made to run in “hassle-free” mode. Meaning: no need to ask your mum or your sysadmin anything, no need to write any config files.
Minimalism
Well, almost. I put in some extra options to disable the TCP socket, and I set some permissions on the unix socket.
For these examples, I assume bash or zsh and a unixish system. And PostgreSQL 9.0.
create a database:
initdb ~/mypostgres
You now have a directory ‘mypostgres’ in your homedir. It contains some config files with defaults. We don’t care.
start a server:
postgres -D ~/mypostgres/ -k ~/mypostgres/ --listen_addresses='' \ --unix_socket_permissions=0660 --unix_socket_group=$(id -g)
Let’s go over these options:
-D ~/mypostgres/ — Use ~/mypostgres as datadir (it’s where you created the database, so.)
-k ~/mypostgres/ — Use ~/mypostgres as the directory to store the unix socket for clients to connect to. Look closely and you’ll discover it (it starts with a dot for no good reason). Put it somewhere else (/tmp springs to mind) if you want other users to connect to your db, more on that later.
These are not strictly necessary:
--listen_addresses='' — Don’t listen on any TCP sockets. We don’t really authenticate users. So if you expose a TCP socket (default, on the localhost interface) any user can do anything to your databases just by running something like psql -h 127.0.0.1 -d postgres -U yourusername
--unix_socket_permissions=0660 — By default, permissions are o=rwx. If you put the socket in a public place such as /tmp, then with our authentication-free mode of operation, you probably do not want any and all users to be able to access your DB.
--unix_socket_group=$(id -g) — This is completely superfluous but it’s here so you don’t shoot yourself in the foot when blindly copy-pasting teh codez. $(id -g), of course, is your primary group ID and is what the group ownership of the socket will have been set to without this specification anyway (hence the superfluousness). So when would you use this? You’d use it when you want to let other users access your DB. You’d set the gid to some appropriate group that you and the other users belong to (and you’d put the socket in a public place, that much should be clear now).
some goodies:
--silent-mode=true — Daemon mode. To quit the server, get the PID from ~/mydb/postmaster.pid and send it a SIGTERM.
-F — Wicked fast writes mode. Also, wickedly trashed DB mode if the server is interrupted abnormally.
Create and connect
Now the server is up and running, create a database: createdb -h ~/mypostgres mydb
and connect to it: psql -h ~/mypostgres -d mydb
By default psql will try to log you in to the DB using the same username as your current unix username. Convenient, because that user has full privileges on the DB.
Should you need to specify the user as whom to connect, you can do so with -U.
Wrapper?
Just like with sqlite, you determine access to the DB by setting unix permissions. We do it on the socket, with SQLite you do it on the DB file itself.
So, how about a wrapper Python module to make all this just as easy as
So what’s a soft power switch anyway? Let’s start with the converse: a regular light switch, say, of the tumbler type. You switch it in the ‘on’ position and voila, light. There’s a power cut and off it goes. But the switch maintains ’state’, so when the mains come back on, so does your light!
This doesn’t happen with soft switches. Pushing a soft switch momentarily closes a contact, thereby generating a signal. Typically this signal is interpreted by some circuit, turning on your laptop. Or if your laptop is already on it might put it into standby. The effect of pushing this switch depends on context. The pushbutton has no state, it just generate an event when it’s being pushed. No persistent state here. And context might get lost — after a power failure, for instance.
Context bites.
In itself this is not a bad thing, but the devil is in the details. The implementation of the circuit part can make a geek’s life miserable. I had an external harddisk enclosure sporting one of those soft power switches. Connect power, push the button, it’s on. Power cut? Off it goes (of course). Power restored — it’s still off. But I wanted it to be on whenever there is power. Duct-taping the button in the ‘pushed’ position (hey, ’state’!) didn’t do much good as, in my limited understanding, this particular switch appeared to work by ‘pulling down’ a signal from the high state to the low state. The circuit will never be armed! With the button pushed down when power comes back on, the high state will never be reached as any potential will just leak away through the switch, dammit.
I spent some time trying to solder around this problem, trying to delay the bridging of the contact with all kinds of contraptions made of stuff I had lying around (positive feedback circuit from LEDs and an LDR, fun) to no other avail than eventually frying the controller circuit. I’m such a n00b with electronics, I can’t even build a proper delay circuit.
Laptop relay
But that didn’t stop me from soldering up a solution to the following problem. My old netbook is performing home server duties now, which is nice as it’s energy-efficient, quiet, and has builtin UPS. This is the plan: If the mains go down it can keep running. After a while it sets an RTC wakeup alarm and suspends itself. The RTC alarm will be set ~12 hrs into the future, it will power up and switch on the UPS which powers the ADSL modem, border router, and switch. That way it can collect some mail. And then it shuts down the UPS, sets another RTC wakeup alarm…. wash, rinse, repeat, until battery power runs out.
Problems
So what if battery power has run out, and mains power gets restored?
Then I’d have to physically push the button to power the thing back on. I don’t want that. But there’s no ‘restore power state after power loss” BIOS option on this laptop. Lucky for me, with this particular piece of equipment I can just permanently short the same pins that the power switch shorts — no timing trouble as with the harddisk enclosure here.
So what if mains power comes back on after the server has just decided to go to sleep for another XX hours?
Well that would be a silly situation. I need the laptop to resume from standby in that case.
This posed problems as the pin shorting trick mentioned before doesn’t help in this case. Potential just keeps on flowing through the ‘pressed’ switch, regardless of the state of the mains power. So restoring mains power doesn’t generate an event.
Solution
…was to use a relay. The coil is wired to the internal 20V leads coming from the power connector (right picture). klz helped soldering this rather tricky one. The relais switch leads are soldered onto the switch wires (left picture, you can see the little switch connector). In the middle (middle) you can see the relais. It’s huge and makes the bottom plate of the laptop bulge a bit.
But it works! It generates the equivalent of a button push whenever mains power comes on.
A while ago I received a question from a reader. He was having some trouble with a pretty interesting setup. As I was rather intrigued I spent some time to figure it out — it’s solved, but I’m not 100% sure on the theory. So if you are, please comment.
the question
from Yves <theYinYeti@yeti.selfip.net>
to wicher@gavagai.eu
date Wed, Sep 15, 2010 at 16:06
subject Socat
It happens I have a problem with socat on my Sheevaplug server, and it seems you have good knowledge of this software.
Following http://zarb.org/~gc/html/udp-in-ssh-tunneling.html, I use socat to tunnel DNS through SSH, so as to have transparent DNS resolution, to be used with a transparent proxy (NAT rules + tinyproxy, backed by cntlmd, backed by corporate proxy).
My problem is that the number of socat PIDs on both the client and the server keeps growing. I’ve had floods of “accept: too many open files” messages, and I suspect socat is the culprit (at this point, a ps -ef shows almost a thousand of socat PIDs!); especially since the transparent DNS stops working after this flood of messages.
More specifically, on the client, I run:
dnsmasq with “server=127.0.0.1#1053” as a back-end
Besides, on localhost (local client), ssh is configured this way:
Host remoteserver
Port 443
ServerAliveInterval 60
ProxyCommand /usr/bin/proxytunnel -v -p corporateproxy:8080 -P login:passwd -d %h:%p
Do you have an idea on how I could make socat behave better?
I thank you beforehand for any advice you could provide.
Sincerely,
Yves.
the reply
from Wicher Minnaard <wicher@gavagai.eu>
to Yves <theYinYeti@yeti.selfip.net>
date Thu, Sep 16, 2010 at 02:19
subject Re: Socat
Dear mister Yves,
On Wed, Sep 15, 2010 at 16:06, Yves <yves@yeti.selfip.net> wrote:
Dear mister Minnaard,
I hope you don’t mind me asking you for help. By chance, I saw your blog post:
http://smorgasbord.gavagai.nl/2010/01/socat-access-your-x-servers-domain-socket-over-tcp/
It happens I have a problem with socat on my Sheevaplug server, and it seems
you have good knowledge of this software.
Thank you for your compliment. Actually, I do not know socat all too well, but I know a thing or two about networking.
Following http://zarb.org/~gc/html/udp-in-ssh-tunneling.html, I use socat to tunnel DNS through SSH, so as to have transparent DNS resolution, to be used with a transparent proxy (NAT rules + tinyproxy, backed by cntlmd, backed by
corporate proxy).
Sounds like just another day at the office ;-)
Interesting setup.
My problem is that the number of socat PIDs on both the client and the server keeps growing. I’ve had floods of “accept: too many open files” messages, and I suspect socat is the culprit (at this point, a ps -ef shows almost a thousand of socat PIDs!); especially since the transparent DNS stops working after this flood of messages.
dnsmasq with “server=127.0.0.1#1053” as a back-end
Sidenote: Google provides a solid DNS service nowadays. I don’t know what they do with the data, though the same could be said about OpenDNS.
See http://code.google.com/speed/public-dns/
So it’s DNS over UDP over TCP over SSH over proxied HTTPS, or something. I’m losing track of all the layers here.
Do you have an idea on how I could make socat behave better?
I thank you beforehand for any advice you could provide.
Well you got me curious now.
I managed to reproduce your problem in a simplified setup:
- on host w00tage, setup the nameserver façade: socat udp4-listen:1053,reuseaddr tcp:localhost:1054
- from host w00tage, tunnel the TCP connection over SSH to the host hosting the to-be-proxied nameserver: ssh -L 1054:localhost:1054 priv
- now, on this host priv, connect the TCP socket to the UDP socket where the nameserver is listening socat tcp4-listen:1054,fork,reuseaddr UDP:localhost:53
- on w00tage, do queries on localhost:1054: dig @localhost -p1053 google.fr
Dig is part of the bind-tools package and greatly helps in diagnosing DNS problems.
The first dig will probably return. Subsequent digs may take seconds to return. And they leave stray socat processes behind on both w00tage and priv. Kill the strays on w00tage, and the ones on priv dissolve. So the local ones (on w00tage) tie up the remote ones. The latter are not the problem, just a symptom. You can keep on querying, doing more digs, until your file descriptors run out.
A stab at what is going on here: UDP is stateless, and socat is ignorant of protocol data (as it should be). A DNS query takes one UDP packet. But socat does not know we’re doing DNS. And since UDP is stateless, there’s no ‘bye’ in the conversation. So socat doesn’t know when to stop waiting for more. Dig does, though – it recognizes a DNS answer when it sees one. So dig returns (but why the delays? socat buffers and timeouts maybe?) but socat doesn’t. It’s still waiting for more.
Now since we’re forking socat for every new independent socketpair opened (which is what happens when you do a query), we get a lot of those hanging socats.
I had a look at the URL you sent me, http://zarb.org/~gc/html/udp-in-ssh-tunneling.html, to see how they are getting it to work and it appears there is a ‘UDP-RECVFROM’ address type in socat. From its manpage:
————
UDP-RECVFROM:
Creates a UDP socket on
[UDP service] using UDP/IP version 4
or 6 depending on option pf. It receives one packet from an
unspecified peer and may send one or more answer packets to that peer.
This mode is particularly useful with fork option where each arriving
packet – from arbitrary peers – is handled by its own sub process.
This allows a behaviour similar to typical UDP based servers like
ntpd or named. This address works well with socat UDP-SENDTO address
peers.
————
Hey, explicit mentioning of nameservers there. Receive one packet, don’t wait for more, send it off, collect answer, send that back.
On host w00tage, I run the façade thusly:
And that appears to work indeed. But wait, how does socat (on priv) know when to stop trying to collect answer packets?
I think it’s socat timeouts, but I’m not 100% sure. What leads me to think that it’s timeouts is that when I stress-test this setup from w00tage:
while true; do dig @localhost -p1053 sheeva; done
(for ’sheeva’ the nameserver never has to do recursion)
I have about 30 forked-off query-listeners when I do a pgrep socat | wc -l on w00tage. But I have about 400 on priv. That number goes up and down and the pids change, so they do not *accumulate* but rather seem to hang about until they decide their job is done. But to be sure I’d have to study the source. Or ask the socat mailing list.
Anyway, problem solved!
I was happy to help you and I got some exercise out of it. Any reason why you didn’t post this question as a comment on my blog? Maybe it would be a bit off-topic, I can see that.
Would you mind if I published this?
Regards and good luck, Wicher Minnaard.
it works
from Yves <theYinYeti@yeti.selfip.net>
to wicher@gavagai.eu
date Thu, Sep 16, 2010 at 10:01
subject Re: Socat
Dear mister Minnaard,
All in all, I was just careless in adapting the “alternative solution with socat” to my setup.
I thank you for your analysis and tests; I learnt a few things following them. And I certainly wouldn’t mind at all if you were to publish this.
However, if you do so, please change the e-mail to “theYinYeti@yeti.selfip.net” (the Sheevaplug :-) ), and my name to simply “Yves”; thank you. As for the web site (I see there’s a field for it), it is “http://yeti.selfip.net/gablin.php” (a bit lame, but I may find time someday to update it…)
As you said, I had the feeling this was a bit off-topic. But now, I see how this can shed some light on advanced socat usage.
–
Regards,
The other week I visited Tirana, Albania. In many ways it is not unlike other parts of Europe, which surprised me because its “opening up” to the rest of the world is of such such recent history (under Hoxha it was the North Korea of Europe).
One thing that certainly has changed since Hoxha’s time is city traffic. In those days there were less than 2000 cars in the whole of Albania, and look at it now:
Video on this page is embedded through the HTML5 Video element, with two video streams.
I did the VP8 WebM with ffmpeg:
ffmpeg -i raw.avi -f webm -vcodec libvpx -acodec libvorbis -aq 3 -b 800 -y TiranaTraffic.webm
The specified bitrate seems to be ignored by the encoder. Libvpx support in ffmpeg is rather new so I guess this will be resolved in the near future.
The fallback Ogg Theora I did with ffmpeg2theora:
ffmpeg2theora -o TiranaTraffic.ogv --two-pass --optimize -V 1200 raw.avi
While sifting through last month’s collection of spamboxed comments to this blog, I stumbled upon these gems:
soyboalilla, 83.21.212.75, 2010/08/23 at 7:51pm
Good day!
I’ve recently found an excellent search engine – Warning: array_merge() [function.array-merge]: Argument #2 is not an array in /var/www/html/links.php on line 16
P.S. Yahoo – everything will be found! Google: nothing was really lost…
See you!
Soyboalilla, my honest opinion: The name of your warningarraymergefunctionargument-something search engine has a less than cheerful ring to it, and I find it rather hard to remember.
soyboalilla, 83.9.113.130, 2010/08/24 at 4:01pm
Hi everyone
Check out an excellent search engine – MYSQL ERROR #126 : Incorrect key file for table ‘./spamer/urls.MYI’; try to repair itSELECT u.url as url ,k.key as `key` FROM `urls` as u left join keywords as k on (u.keyword_id = k.id) where u.id in (49296827615,588861,221691,263472,983972,865840,966666,200061)
P.S. Yahoo – everything will be found! Google: nothing was really lost…
Bye to everyone!
Thanks for the suggestion, soyboalilla. Maybe you should go tot that search engine of yours and find yourself a nice little SQL tutorial. You’ll be a pro ’spamer’ someday!