<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-9974736</id><updated>2011-08-02T17:01:20.628-07:00</updated><title type='text'>Brainfish Eat Fishbrain</title><subtitle type='html'>Technical information some people might find useful (or not).</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://brainfish-eat-fishbrain.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>66</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-9974736.post-5195792860851754004</id><published>2010-10-12T09:41:00.000-07:00</published><updated>2010-10-12T09:42:34.537-07:00</updated><title type='text'>How does WP (3) resolve (pretty) urls</title><content type='html'>When I was checking a pretty custom WP site, I couldn't easily figure out how the URLs flow through the system, so I decided to write down what / how I found out how it works. &lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;index.php -&gt; wp-blog-header.php -&gt; wp-load.php -&gt; wp-includes/functions.php -&gt; wp() -&gt; (wp-includes/classes.php/WP)wp-&gt;main() -&gt; wp-&gt;parse_request() &lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;... is the basic flow used to decode the urls. &lt;br /&gt;&lt;br /&gt;The first point you need to look at is: &lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;// Fetch the rewrite rules.&lt;br /&gt;$rewrite = $wp_rewrite-&gt;wp_rewrite_rules();&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;In my case this ($rewrite) contained a ton of rules which I couldn't really match with any code or rules in the database. Where are these rules coming from? The following comment to the function would indicate that it's cached:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;* WP_Rewrite::rewrite_rules()} is that this method stores the rewrite rules&lt;br /&gt;* in the 'rewrite_rules' option and retrieves it. This prevents having to&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;I wanted to make sure. To find this we have to dive into wp_rewrite_rules() which can be found in wp-includes/rewrite.php;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;function wp_rewrite_rules() {&lt;br /&gt;$this-&gt;rules = get_option('rewrite_rules');&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;The above $this-&gt;rules now already contained the 'ghost rules' so apparently they are stored in the database somehwere. To find out where, you just debug get_option() in functions.php. This brought me into: &lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;$alloptions = wp_load_alloptions();&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;And options are retrieved, obviously, from: &lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;if ( !$alloptions_db = $wpdb-&gt;get_results( "SELECT option_name, option_value FROM $wpdb-&gt;options WHERE autoload = 'yes'" ) )&lt;br /&gt;$alloptions_db = $wpdb-&gt;get_results( "SELECT option_name, option_value FROM $wpdb-&gt;options" );&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;So basically we found out that this is a kind of cache indeed. To flush that cache, you go to the wp-admin-&gt;Settings-&gt;Permalinks and click Save Changes. After that it's flushed. &lt;br /&gt;&lt;br /&gt;After flushing there were still a few of the mysterious rules in the rewrite list. Those were due to;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;register_taxonomy( 'review', 'post', array( 'label' =&gt; __('Review') ) );&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;When a custom taxonomy was added, you will see rules like this: &lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;[review/([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?$] =&gt; index.php?review=$matches[1]&amp;feed=$matches[2]&lt;br /&gt;[review/([^/]+)/(feed|rdf|rss|rss2|atom)/?$] =&gt; index.php?review=$matches[1]&amp;feed=$matches[2]&lt;br /&gt;[review/([^/]+)/page/?([0-9]{1,})/?$] =&gt; index.php?review=$matches[1]&amp;paged=$matches[2]&lt;br /&gt;[review/([^/]+)/?$] =&gt; index.php?review=$matches[1]&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;Now that 'mystery' was solved, on with the rest of the flow: &lt;br /&gt;&lt;br /&gt;In the parse_request() method you can find; &lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;foreach ( (array) $rewrite as $match =&gt; $query) {&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;This is the loop which has all rewrite rules which WP uses to translate from pretty urls to arguments the WP application can use to get the post(s) and other data needed and mesh that with the templates.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;if ( preg_match("#^$match#", $request_match, $matches) ||&lt;br /&gt;preg_match("#^$match#", urldecode($request_match), $matches) ) {&lt;br /&gt;// Got a match.&lt;br /&gt;$this-&gt;matched_rule = $match;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;Now WP found a match, so we can check what the result is: &lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;die("$match =&gt; $query");&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;An example of a matching rule is: &lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;review/([^/]+)/([^/]+)(/[0-9]+)?/?$ =&gt; index.php?$matches[1]&amp;name=$matches[2]&amp;page=$matches[3]&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;This rule is translated based on the URL and then it can be matched, this is done with this code:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;$query = addslashes(WP_MatchesMapRegex::apply($query, $matches));&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;and the result is, for instance; &lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;review/([^/]+)/([^/]+)(/[0-9]+)?/?$ =&gt; ms-windows-7&amp;name=windows-7-is-better-but-still-sucks&amp;page=&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;With the following method this is translated to a php array: &lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;parse_str($query, $perma_query_vars);  &lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;This results into something like this:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;Array ( [ms-windows-7] =&gt; [name] =&gt; windows-7-is-better-but-still-sucks [page] =&gt; )&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;With this information, it should be clear (and at least be easy to follow) how WP resolves it's URLs. With a debugger this is all easy enough to find, but it's still easy to see it all on a page.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-5195792860851754004?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/5195792860851754004'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/5195792860851754004'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2010/10/how-does-wp-3-resolve-pretty-urls.html' title='How does WP (3) resolve (pretty) urls'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-4578659929268240162</id><published>2010-05-22T06:39:00.000-07:00</published><updated>2010-05-22T06:39:29.653-07:00</updated><title type='text'>Migrating a Wordpress installation from your localhost to a production server (using cpanel)</title><content type='html'>Say you have locally WP installed under WAMP or MAMP or whatever under; &lt;br /&gt;&lt;br /&gt;http//localhost:8888/somesite&lt;br /&gt;&lt;br /&gt;and you want to run it, with all content and plugins and what have not under: &lt;br /&gt;&lt;br /&gt;http://www.somesite.com&lt;br /&gt;&lt;br /&gt;The steps to do this: &lt;br /&gt;&lt;br /&gt;- create somesite.com in your WHM system (http://yourhost.com/whm) or make sure your site exists&lt;br /&gt;- go to your local phpmyadmin, usually; http://localhost:8888/ and then clicking on phpmyadmin&lt;br /&gt;- click on the database you are using &lt;br /&gt;- click on export&lt;br /&gt;- make sure SQL is selecting on the left&lt;br /&gt;- click on go&lt;br /&gt;- open another tab in your browser and open http://www.somesite.com/cpanel&lt;br /&gt;- login &lt;br /&gt;- create a database and a user for that database and remember what you you used there&lt;br /&gt;- now open phpmyadmin in your cpanel&lt;br /&gt;- click on the database you just created&lt;br /&gt;- click on SQL &lt;br /&gt;- copy/paste the sql from your localhost tab into this new db and click go&lt;br /&gt;- now connect (with ftp) to your somesite.com server and copy over everything in your root directory from your localhost (for instance; htdocs/somesite/*)&lt;br /&gt;- edit, remotely, your public_html/wp-config.php; change the values DB_NAME, DB_USER, DB_PASS to the values you used to create your db in cpanel&lt;br /&gt;- now, basically, your site should work; simply try http://www.somesite.com&lt;br /&gt;- if you get a database error, please check your remote wp-config.php to see what went wrong&lt;br /&gt;- you probably now get some error; not found http://somesite.com:8888 or something like that; this is because the php options are wrong&lt;br /&gt;- to fix this, just open SSH to your remote server and run; &lt;br /&gt;&lt;br /&gt;cd /home/somesite &lt;br /&gt;mysqldump YOURDBNAME wp_options &gt; tmp.sql&lt;br /&gt;sed -i 's/localhost:8888\/somesite/www.somesite.com/ig' tmp.sql&lt;br /&gt;mysql YOURDBNAME &lt; tmp.sql&lt;br /&gt;&lt;br /&gt;Now your site will work.&lt;br /&gt;&lt;br /&gt;Have fun.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-4578659929268240162?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/4578659929268240162'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/4578659929268240162'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2010/05/migrating-wordpress-installation-from.html' title='Migrating a Wordpress installation from your localhost to a production server (using cpanel)'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-2455438941076776948</id><published>2009-10-26T03:07:00.000-07:00</published><updated>2009-10-26T03:07:06.795-07:00</updated><title type='text'>Cpanel: Monitoring :2082 logins</title><content type='html'>Simple script to send you all new logins of the day. Seeing something strange would trigger further research.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;#!/usr/bin/perl&lt;br /&gt;&lt;br /&gt;chdir('/root');&lt;br /&gt;&lt;br /&gt;$d = `date +%m/%d/%Y`;&lt;br /&gt;chomp($d);&lt;br /&gt;&lt;br /&gt;@logins = `cat /usr/local/cpanel/logs/access_log|grep $d|awk '{print \$1 " " \$3}'|sort|uniq`;&lt;br /&gt;&lt;br /&gt;$x = "";&lt;br /&gt;&lt;br /&gt;foreach(@logins) {&lt;br /&gt; chomp; &lt;br /&gt; /(.*?)\ (.*)/;&lt;br /&gt; next if $2 eq "-";&lt;br /&gt; $z = `whois $1|grep addres|tail -n 1`;&lt;br /&gt; chomp($z);&lt;br /&gt; $x.="$z $1 $2\n";&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;if (not -f "./latestscan") {&lt;br /&gt; `touch ./latestscan`;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;$y = `cat ./latestscan`;&lt;br /&gt;&lt;br /&gt;exit if $y eq $x;&lt;br /&gt;&lt;br /&gt;open(F, "&gt;latestscan");&lt;br /&gt;print F $x; &lt;br /&gt;close F;&lt;br /&gt;&lt;br /&gt; $sendmail = "/usr/sbin/sendmail -t";&lt;br /&gt; open(SENDMAIL, "|$sendmail") or die "Cannot open $sendmail: $!"; &lt;br /&gt; print SENDMAIL "Reply-to: root\@myserver.org\n"; &lt;br /&gt; print SENDMAIL "Subject: Login report hostf1\n"; &lt;br /&gt; print SENDMAIL "To: alerts\@yourserver.com\n"; &lt;br /&gt; print SENDMAIL "Content-type: text/plain\n\n"; &lt;br /&gt; print SENDMAIL $x; &lt;br /&gt; close(SENDMAIL); &lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-2455438941076776948?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/2455438941076776948'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/2455438941076776948'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2009/10/cpanel-monitoring-2082-logins.html' title='Cpanel: Monitoring :2082 logins'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-6660484369905088090</id><published>2009-10-25T00:58:00.000-07:00</published><updated>2009-10-25T01:05:33.616-07:00</updated><title type='text'>Watching series; I don't want to touch my computer</title><content type='html'>When I watch series I don't want to touch my computer and I watch all episodes in one fell swoop; if I do something like mplayer *.mpg it crashes, so that doesn't work. This does, run like;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;./play "*.mpg"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;or &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;./play "*.avi"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The code;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#!/usr/bin/perl&lt;br /&gt;&lt;br /&gt;$a = "";&lt;br /&gt;foreach(@ARGV) {&lt;br /&gt; $a.=" " if $a; &lt;br /&gt; $a.=$_;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;while(1){foreach(glob("$a")){`mplayer -fs \"$_\"`}}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-6660484369905088090?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/6660484369905088090'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/6660484369905088090'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2009/10/watching-series-i-dont-want-to-touch-my.html' title='Watching series; I don&apos;t want to touch my computer'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-4422931015331441041</id><published>2009-10-24T05:08:00.000-07:00</published><updated>2009-10-24T05:25:36.037-07:00</updated><title type='text'>Cpanel security: scanning for usage or upload of c99 shell script (or other scripts)</title><content type='html'>Sometimes users upload stuff to your server or use scripts you don't want used. To detect them fast, I wrote this script.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#!/usr/bin/perl&lt;br /&gt;    &lt;br /&gt;use Digest::Perl::MD5 'md5_hex';&lt;br /&gt;&lt;br /&gt;chdir('/root/');&lt;br /&gt;`touch ./scanned` if not -f "./scanned";&lt;br /&gt;&lt;br /&gt;%h = ();&lt;br /&gt;open(F, "scanned");&lt;br /&gt;while(&lt;F&gt;) {&lt;br /&gt; chomp;&lt;br /&gt; $h{$_} = 1;&lt;br /&gt;}&lt;br /&gt;close F;&lt;br /&gt;&lt;br /&gt;@x = `cd /etc/httpd/domlogs/; grep c99me *`;&lt;br /&gt;open(F, "&gt;&gt;scanned");&lt;br /&gt;$s = "";&lt;br /&gt;foreach(@x) {&lt;br /&gt; chomp;&lt;br /&gt; $m = md5_hex($_);&lt;br /&gt; next if $h{$m};&lt;br /&gt; print F "$m\n";&lt;br /&gt; $s.=$_."\n";&lt;br /&gt;}&lt;br /&gt;close F;&lt;br /&gt;&lt;br /&gt;if ($s) {&lt;br /&gt; $sendmail = "/usr/sbin/sendmail -t";&lt;br /&gt; open(SENDMAIL, "|$sendmail") or die "Cannot open $sendmail: $!"; &lt;br /&gt; print SENDMAIL "Reply-to: root\@myserver.org\n"; &lt;br /&gt; print SENDMAIL "Subject: Found some illegal stuff on server\n"; &lt;br /&gt; print SENDMAIL "To: alerts\@somewhere.com\n"; &lt;br /&gt; print SENDMAIL "Content-type: text/plain\n\n"; &lt;br /&gt; print SENDMAIL $s; &lt;br /&gt; close(SENDMAIL); &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-4422931015331441041?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/4422931015331441041'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/4422931015331441041'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2009/10/cpanel-security-scanning-for-usage-or.html' title='Cpanel security: scanning for usage or upload of c99 shell script (or other scripts)'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-5600240887093385330</id><published>2009-10-24T04:21:00.000-07:00</published><updated>2009-10-24T04:45:03.433-07:00</updated><title type='text'>Cpanel security: cron update all Wordpress installations on your server</title><content type='html'>Two simple scripts. Use with caution and at your own risk. Might eat your machine and piss off all your users. &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;!/usr/bin/perl&lt;br /&gt;&lt;br /&gt;`rm -fR wordpress`;&lt;br /&gt;`wget http://wordpress.org/latest.zip`;&lt;br /&gt;`unzip latest.zip`;&lt;br /&gt;&lt;br /&gt;@all = `ls -la /home/|awk '{print \$3}'|grep -v root`;&lt;br /&gt;&lt;br /&gt;foreach(@all) {&lt;br /&gt; chomp;&lt;br /&gt; next if /^$/;&lt;br /&gt; `./updatewp $_`;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#!/usr/bin/perl&lt;br /&gt;&lt;br /&gt;$host = `hostname`; &lt;br /&gt;chomp($host);&lt;br /&gt;&lt;br /&gt;$u = $ARGV[0]; &lt;br /&gt;&lt;br /&gt;exit if !$u; # user as arg&lt;br /&gt;&lt;br /&gt;exit if not -f "/home/$u/public_html/wp-config.php"; # not wp install&lt;br /&gt;&lt;br /&gt;# you shouldn't actually have the readme.html, but if it's there it's a bit faster&lt;br /&gt;$v1 = `cat /home/$u/public_html/readme.html|grep Version &gt; dev/null`;&lt;br /&gt;$v1 =~ /Version\ (\d+\.\d+\.\d+)/;&lt;br /&gt;$v1 = $1; &lt;br /&gt;&lt;br /&gt;$v2 = `cat wordpress/readme.html|grep Version`;&lt;br /&gt;$v2 =~ /Version\ (\d+\.\d+\.\d+)/;&lt;br /&gt;$v2 = $1;&lt;br /&gt;&lt;br /&gt;exit if $v1 eq $v2; # already updated&lt;br /&gt;&lt;br /&gt;`cp -a wordpress /home/$u/wp_int`;&lt;br /&gt;&lt;br /&gt;`cp -rpf /home/$u/public_html/wp-config.php /home/$u/wp_int`;&lt;br /&gt;`cp -rpf /home/$u/public_html/wp-content/* /home/$u/wp_int/wp-content/`;&lt;br /&gt;`cp -rpf /home/$u/public_html/.htaccess /home/$u/wp_int/`;&lt;br /&gt;&lt;br /&gt;`chown $u.$u /home/$u/wp_int`;&lt;br /&gt;&lt;br /&gt;`cp -a /home/$u/public_html /home/$u/wpback\`date +%d%m%y\``;&lt;br /&gt;&lt;br /&gt;`cp -rpf /home/$u/wp_int/* /home/$u/public_html/`;&lt;br /&gt;&lt;br /&gt;`rm -fR /home/$u/wp_int`;&lt;br /&gt;&lt;br /&gt;$x = `lynx -dump http://$host/~$u/wp-admin/upgrade.php`;&lt;br /&gt;&lt;br /&gt;if ($x =~ /Database Upgrade Required/isgm) {&lt;br /&gt; `lynx -dump http://$host/~$u/wp-admin/upgrade.php?step=1\&amp;backto=`;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;print "Updated $u\n";&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-5600240887093385330?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/5600240887093385330'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/5600240887093385330'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2009/10/cpanel-security-cron-update-all.html' title='Cpanel security: cron update all Wordpress installations on your server'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-482539225429425218</id><published>2009-08-03T07:37:00.000-07:00</published><updated>2009-08-03T07:46:37.762-07:00</updated><title type='text'>Mac OS X Firefox 3.5 intervals to 100% CPU about every 30 seconds</title><content type='html'>Yesterday suddenly my Firefox started to show the busy mouse pointer about every 30 seconds. Very annoying as it was completely unusable during about 5  seconds, and then 30 seconds later again etc. &lt;br /&gt;&lt;br /&gt;I removed my Profile in ~/Library and checked if it was FF or something in my profile. Ofcourse it was something in my profile. &lt;br /&gt;&lt;br /&gt;Checking my files I saw one file that looked 'odd' ; places.sqlite was rather huge (I do browser a lot), however sqlite can handle quite big databases. Anyway; I ran a&lt;br /&gt;&lt;br /&gt;rm -f places* &lt;br /&gt;&lt;br /&gt;and restarted FF. No more 100%. Fixed. &lt;br /&gt;&lt;br /&gt;What is going on I don't know; it looks like FF is running some kind of really bad query on that sqlite every +/- 30 s which is messing up the whole thing.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-482539225429425218?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/482539225429425218'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/482539225429425218'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2009/08/mac-os-x-firefox-35-intervals-to-100.html' title='Mac OS X Firefox 3.5 intervals to 100% CPU about every 30 seconds'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-904022534263290341</id><published>2009-06-30T01:18:00.000-07:00</published><updated>2009-06-30T01:25:19.623-07:00</updated><title type='text'>Checking/repairing all MySQL tables</title><content type='html'>Caution: on busy servers this will make a lot of load. Use only when you suspect/know tables are broken.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#!/usr/bin/perl&lt;br /&gt;&lt;br /&gt;$mysql = "/var/lib/mysql";&lt;br /&gt;&lt;br /&gt;@res = `cd $mysql; find .|grep MYD`;&lt;br /&gt;&lt;br /&gt;foreach(@res) {&lt;br /&gt; chomp;&lt;br /&gt; /\.\/(.*?)\/(.*?).MYD/;&lt;br /&gt; $tab = $1.".".$2;&lt;br /&gt; print `mysql --execute='repair table $tab'`; &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-904022534263290341?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/904022534263290341'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/904022534263290341'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2009/06/checkingrepairing-all-mysql-tables.html' title='Checking/repairing all MySQL tables'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-1524662282828530502</id><published>2009-02-06T03:44:00.001-08:00</published><updated>2009-02-06T04:45:56.852-08:00</updated><title type='text'>A simple, non bloated script for Amazon S3 backups (Linux, easy portable) - II - recurse to subdirs</title><content type='html'>To follow this, please read &lt;a href="http://brainfish-eat-fishbrain.blogspot.com/2009/01/simple-non-bloated-script-for-amazon-s3.html"&gt;this post&lt;/a&gt; first. &lt;br /&gt;&lt;br /&gt;We needed to backup our images from http://www.picturepush.com to S3 for our premium members so we were searching for a simple script to do that one time. As in my previous post; there is no such thing. Bloated, uninstallable shit is the only thing there is. &lt;br /&gt;&lt;br /&gt;So I changed the code a bit and added; &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;foreach($_SERVER["argv"] as $d) {&lt;br /&gt; recurse_copy($d, $d);&lt;br /&gt;}&lt;br /&gt;exit;&lt;br /&gt;&lt;br /&gt;function recurse_copy($d, $org) {&lt;br /&gt; foreach(glob("$d/*") as $d1) {&lt;br /&gt;  if ($d1=='..' || $d1=='.') continue;&lt;br /&gt;  if (is_dir($d1)) {&lt;br /&gt;   recurse_copy($d1, $org); &lt;br /&gt;  } else {&lt;br /&gt;   // put on s3&lt;br /&gt;   global $s3;&lt;br /&gt;   global $bucket;&lt;br /&gt;   $s3-&gt;putObjectFile($d1, $bucket, $d1);&lt;br /&gt;   echo "Storing: ".$d1."\n";&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;below the last;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;array_shift($_SERVER["argv"]);&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-1524662282828530502?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/1524662282828530502'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/1524662282828530502'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2009/02/simple-non-bloated-script-for-amazon-s3.html' title='A simple, non bloated script for Amazon S3 backups (Linux, easy portable) - II - recurse to subdirs'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-4984024590741954701</id><published>2009-01-03T09:01:00.000-08:00</published><updated>2009-01-03T11:01:40.355-08:00</updated><title type='text'>A simple, non bloated script for Amazon S3 backups (Linux, easily portable)</title><content type='html'>While searching for scripts to backup files from Linux -&gt; S3 (servers) I was surprised how difficult it was to find any nice, trim ones. There are &lt;span style="font-weight:bold;"&gt;huge&lt;/span&gt; java jars filled with crap to do it ofcourse;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;dbserv01:~# ls -lah js3tream.jar &lt;br /&gt;-rw-r--r-- 1 root root 3.2M 2007-12-19 15:07 js3tream.jar&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Come on. 3.2M... What does that include? Windows Vista? &lt;br /&gt;&lt;br /&gt;Sure js3tream is actually nice software. Portable and it works. It's incredibly, mindbogglingly slow (but ofcourse, Java is not slow these days as many people tell me...) on my quad Xeon servers. But yeah, it has the features you would want. Except encryption of the files I upload; you arrange that in a different way please. Come to think of it; other features are missing as well.&lt;br /&gt;&lt;br /&gt;There is S3Sync in Ruby which is actually nice and working well, but still too much hassle to get going as simple script. But no complaints about the speed or size of that.&lt;br /&gt;&lt;br /&gt;Then there is some rsync thing in Python (I forgot the name and the HELLLLLLLLLLLLLLLLLL I went to to install it will not make me remember it any time soon).&lt;br /&gt;&lt;br /&gt;So, as almost all things in life, if you want it done right, you just have to do it yourself. I don't find it pretty at all, but it weighs in, including comments, at 36 kbs, which is, by far the smallest possible script I could find for the purpose I needed. &lt;br /&gt;&lt;br /&gt;I'm not counting rar or gpg as they are not included in the other ones either, but when counting them it wouldn't go over 1 mb. &lt;br /&gt;&lt;br /&gt;Download http://undesigned.org.za/2007/10/22/amazon-s3-php-class&lt;br /&gt;&lt;br /&gt;And install: &lt;br /&gt;&lt;br /&gt;- rar (apt-get install rar)&lt;br /&gt;- gpg (apt-get install gnupg)&lt;br /&gt;- php (apt-get install php5-cli php5-curl)&lt;br /&gt;&lt;br /&gt;Then edit the Amazon S3.php; put on top of it;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#!/usr/bin/php&lt;br /&gt;&lt;?php&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;if (sizeof($_SERVER["argv"])&lt;4) {&lt;br /&gt; echo "Usage: ./s3backup bucket ident dir dir dir\n";&lt;br /&gt; exit;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;$bucket = $_SERVER["argv"][1];&lt;br /&gt;$ident = $_SERVER["argv"][2];&lt;br /&gt;&lt;br /&gt;define('PHPARTIALS_FILE_AWS_S3_ACCESSKEY', '');&lt;br /&gt;define('PHPARTIALS_FILE_AWS_S3_SECRETKEY', '');&lt;br /&gt;define('PHPARTIALS_FILE_RAR_ENCRYPT', '');&lt;br /&gt;define('PHPARTIALS_FILE_GPG_ENCRYPT', '');&lt;br /&gt;&lt;br /&gt;$s3 = new S3(PHPARTIALS_FILE_AWS_S3_ACCESSKEY, PHPARTIALS_FILE_AWS_S3_SECRETKEY);&lt;br /&gt;&lt;br /&gt;#print_r($s3-&gt;getBucket($bucket));exit;&lt;br /&gt;&lt;br /&gt;$l = $s3-&gt;listBuckets(true);&lt;br /&gt;&lt;br /&gt;if (!in_array($bucket, $l)) {&lt;br /&gt; $s3-&gt;putBucket($bucket, S3::ACL_PRIVATE);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;$fn = $ident."-".strftime('%d%m%y%H%M').".rar";&lt;br /&gt;&lt;br /&gt;array_shift($_SERVER["argv"]);&lt;br /&gt;array_shift($_SERVER["argv"]);&lt;br /&gt;array_shift($_SERVER["argv"]);&lt;br /&gt;&lt;br /&gt;$f = implode(' ', $_SERVER["argv"]);&lt;br /&gt;&lt;br /&gt;$cmd = "rar a -hp".PHPARTIALS_FILE_RAR_ENCRYPT." $fn $f";&lt;br /&gt;&lt;br /&gt;echo `$cmd`;&lt;br /&gt;&lt;br /&gt;$fn1=$fn.".enc";&lt;br /&gt;&lt;br /&gt;$cmd = "gpg --batch --yes --trust-model always --encrypt --recipient '".PHPARTIALS_FILE_GPG_ENCRYPT."' -o $fn1 $fn";&lt;br /&gt;&lt;br /&gt;echo `$cmd`;&lt;br /&gt;&lt;br /&gt;$s3-&gt;putObjectFile($fn, $bucket, baseName($fn1));&lt;br /&gt;&lt;br /&gt;print "Backup created!\nSize: ".filesize($fn1)." bytes\n";&lt;br /&gt;&lt;br /&gt;unlink($fn);&lt;br /&gt;unlink($fn1);&lt;br /&gt;&lt;br /&gt;exit;&lt;br /&gt;?&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Rename the S3.php  to something like s3backup and chmod 700 s3backup to make it executable.&lt;br /&gt;&lt;br /&gt;You put your 2 keys for Amazon S3 in the Amazon defines, a password for rarring in the RAR password define and the name of the user your public key is for on that system to GPG encrypt the rar. &lt;br /&gt;&lt;br /&gt;To add a public key for GPG, just put your GPG Public key in a file, say /root/mypub.key and run;&lt;br /&gt;&lt;br /&gt;gpg -a --import /root/mypub.key&lt;br /&gt;&lt;br /&gt;And all will be fine.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-4984024590741954701?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/4984024590741954701'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/4984024590741954701'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2009/01/simple-non-bloated-script-for-amazon-s3.html' title='A simple, non bloated script for Amazon S3 backups (Linux, easily portable)'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-301869886522588365</id><published>2008-11-24T19:55:00.000-08:00</published><updated>2008-11-25T05:01:09.319-08:00</updated><title type='text'>Filthy Rotten Scriptkiddies - Blackmailing Siteowners</title><content type='html'>A friend of mine owns a site which has very little traffic and sells a niche product. Because he gets so little traffic, alarm bells immediately sound when suddenly there is a spike. &lt;br /&gt;&lt;br /&gt;If there would be a spike, he would be rich probably, but the chances of that happening are very slim. &lt;br /&gt;&lt;br /&gt;Anyway, this night, the guy called me up at 3:30 saying he received an email from some hotmail address saying something like ;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;I understand how much revinue you bring in each month, I can bring that down to 0 if I wish. Think I'm kidding? Think this is a joke?&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;And then his demands. &lt;br /&gt;&lt;br /&gt;So, me thinking this was indeed a joke, asking why he )(@#%()#@% woke me. But it wasn't a joke. The site was down. Very much so for 1.5 hour already. Costing my friend money. &lt;br /&gt;&lt;br /&gt;A bit groggy from sleeping I could not imagine this being anything else than some lame DOS attack; one or a few computers bonking away on :80. &lt;br /&gt;&lt;br /&gt;Unfortunately that was not the case at all. &lt;br /&gt;&lt;br /&gt;This was a quite (for this kind of lame threat / blackmail) heavy DDOS. After a few minutes I already collected (and blocked) over 200 unique ips (from different classes mostly). &lt;br /&gt;&lt;br /&gt;In this blog I have shown more than ones some ideas for catching and blocking DDOS attacks from within Linux and this one was rather a simple one and could be simply blocked using; &lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.flexlists.com/view.php?list_id=6192#d::4"&gt;List of Linux tricks&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Few notes here; Apache (or whatever you might use) queues all those income connections and leaves them connected even though they are blocked. Because of this, &lt;br /&gt;during the attack, I run from the cron; */10 * * * * service httpd restart. Making Apache immediately kill of those bad connections, but finish off the real ones with a real response. At least you'll have service for most people using this method.&lt;br /&gt;&lt;br /&gt;Ofcourse it required a bunch of tweaking as the attacker changed his strategy quite often  to make it more difficult. &lt;br /&gt;&lt;br /&gt;I don't get people who do this and I certainly don't understand how they can mount such a huge attack with so many different IPs.&lt;br /&gt;&lt;br /&gt;Edit: attack has been going on for 9 hours now... site doing fine.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-301869886522588365?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/301869886522588365'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/301869886522588365'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2008/11/filthy-rotten-scriptkiddies.html' title='Filthy Rotten Scriptkiddies - Blackmailing Siteowners'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-2352789961431239965</id><published>2008-11-13T15:11:00.000-08:00</published><updated>2008-11-13T16:19:55.438-08:00</updated><title type='text'>MacOSX / Bootcamp / Installing Windows XP without SPs / there is not enough disk space on $ntservicepackuninstall$ to install service pack bla</title><content type='html'>Sometimes you have to do things you don't want. Today I needed to install something under Windows to convert some fileformat (media file format) for which I cannot find Linux or Mac converters. Not even Mplayer can play it. Only some weird proprietary Windows app. &lt;br /&gt;&lt;br /&gt;So basically; I needed Windows. And I hate Windows. And not without passion; I really hate it. But ok, enough about that. &lt;br /&gt;&lt;br /&gt;I have a Mac Mini standing on my desk gathering dust (oh did I mention I hate Mac OS X too?), so I thought ; I can install on that. &lt;br /&gt;&lt;br /&gt;Not that easy. Requires an XP disk with SP2. And ofcourse I didn't have that. As I really don't want to pay for stuff I already have, I took an XP version from 2001 (so without any SPs) and tried to find a way to install that on the Mac Mini. Legal as I don't even have the computer anymore on which is belonged, but I have the 'authentic Windows crap sticker' still.&lt;br /&gt;&lt;br /&gt;The installation from within Bootcamp went 'smooth', although Windows doesn't want to shutdown or restart, you have to force it down by holding the shutdown button. &lt;br /&gt;&lt;br /&gt;And almost none of the software/drivers Apple provides work without SP2. Even worse (well... not much worse); Mac OS X doesn't boot anymore. &lt;br /&gt;&lt;br /&gt;Anyway; I got the SP2 download and burnt it on a CD under Linux and tried to install it under the non-SP version on the Mac Mini. Unfortunately, it started yelping about some missing 4 mb's of space....... 4 mbs. Ofcourse I have more than 20 gb free so that could not be right. &lt;br /&gt;&lt;br /&gt;Quite annoyingly, the Mac community is not of the technical details; when searching for these kind of problems, people keep repeating in forums that I insulted my Mac by installing Windows OR that I did not read and MUST HAVE SP2 Windows install CD OR that I should just reinstall everything. All very helpful. Not. &lt;br /&gt;&lt;br /&gt;So I was faced with two problems;&lt;br /&gt;&lt;br /&gt;- no more Mac OS X&lt;br /&gt;- Windows couldn't install the SP so I couldn't install any drivers etc&lt;br /&gt;&lt;br /&gt;The former was not that important for me as I don't like Mac OS X that much and certainly never use it if I can avoid it. &lt;br /&gt;&lt;br /&gt;But for the latter I started this whole adventure, so I couldn't give that up.&lt;br /&gt;&lt;br /&gt;I read all messages about this problem and the solution turned out to be very (very) simple;&lt;br /&gt;&lt;br /&gt;Windows-R (Start-&gt;Run)&lt;br /&gt;regedit&lt;br /&gt;&lt;br /&gt;Add a String &lt;br /&gt;&lt;br /&gt;key = BootDir &lt;br /&gt;value = C:\&lt;br /&gt;&lt;br /&gt;To &lt;br /&gt;&lt;br /&gt;[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Setup]&lt;br /&gt;&lt;br /&gt;And rerun the SP2 installer.&lt;br /&gt;&lt;br /&gt;Why didn't they just SAY so?&lt;br /&gt;&lt;br /&gt;Anyway; if/when I have Mac OS X back I'll report it here and people can use nice old  CD's of XP they find in car boot sales, instead of paying money to that company we all love.&lt;br /&gt;&lt;br /&gt;Edit: Well, that was ofcourse kind of simple; &lt;br /&gt;&lt;br /&gt;- remove the read only flag from c:\boot.ini&lt;br /&gt;- edit boot.ini&lt;br /&gt;- put at the end c:\CHAIN0="Mac OS X"&lt;br /&gt;- save&lt;br /&gt;- put this file in you c:\&lt;br /&gt;- reboot&lt;br /&gt;&lt;br /&gt;Not Boot Camp, but working fine.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-2352789961431239965?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/2352789961431239965'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/2352789961431239965'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2008/11/macosx-bootcamp-installing-windows-xp.html' title='MacOSX / Bootcamp / Installing Windows XP without SPs / there is not enough disk space on $ntservicepackuninstall$ to install service pack bla'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-455743119063774848</id><published>2008-10-04T11:40:00.000-07:00</published><updated>2008-10-04T11:44:08.961-07:00</updated><title type='text'>Creating databases in cpanel remotely</title><content type='html'>Lately I was wondering how one would go about creating databases in cpanel without having to log on. Do it from PHP or something and create a somewhat 'nicer' interface to that 'nice' cpanel stuff.&lt;br /&gt;&lt;br /&gt;It proved to be trivial to do anything with the system; that is in face kind of nice and has been a relief for me as I thought it would be (much) more difficult.&lt;br /&gt;&lt;br /&gt;Here is a code snippet how to do this easily. It return &lt;a href="http://www.phpartials.com"&gt;PHPartialsResult&lt;/a&gt;, but you can replace that with 'true' or something.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  function remote_account_create_db($host, $user, $pass, $dbname) {&lt;br /&gt;   $conn = "http://$user:$pass@$host:2082/frontend/x3/sql/addb.html?db=$dbname";&lt;br /&gt;   file_get_contents($conn); &lt;br /&gt;   return PHPartialsResult::ok();&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  function remote_account_create_dbuser($host, $user, $pass, $_user, $_pass) {&lt;br /&gt;   $conn = "http://$user:$pass@$host:2082/frontend/x3/sql/adduser.html?user=$_user&amp;pass=$pass&amp;pass2=$pass";&lt;br /&gt;   file_get_contents($conn); &lt;br /&gt;   return PHPartialsResult::ok(); &lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  function remote_account_create_dbuserconnection($host, $user, $pass, $_user, $_db) {&lt;br /&gt;   $conn = "http://$user:$pass@$host:2082/frontend/x3/sql/addusertodb.html?ALL=ALL&amp;user=$_user&amp;db=$_db";&lt;br /&gt;   file_get_contents($conn); &lt;br /&gt;   return PHPartialsResult::ok(); &lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-455743119063774848?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/455743119063774848'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/455743119063774848'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2008/10/creating-databases-in-cpanel-remotely.html' title='Creating databases in cpanel remotely'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-215441226113983491</id><published>2008-04-25T15:05:00.000-07:00</published><updated>2008-04-28T07:26:04.215-07:00</updated><title type='text'>Using tcpproxy for http forwarding? Add X-Forwarded-For!</title><content type='html'>TCPProxy is one of the most beautiful tools I know of; it was nicely programmed, but above all; it has no bugs. None. We are routing millions of pageviews a day of hundreds of thousands of unique users through it and it has never let me down. It is fast, uses almost no CPU and is very very robust (I miss FTP support, but further it is totally perfect). &lt;br /&gt;&lt;br /&gt;This unlike Apache (proxy pass) or Squid or the many other, less known, proxies I tried. Apache is especially crappy; proxy pass is riddled with bugs; under load it simply is unusable. And most of them are feature-heavy; too feature heavy; they are a pain to set up, but trivial things like not binding to 0.0.0.0 etc or simple config files they have not. &lt;br /&gt;&lt;br /&gt;We have the necessity to route web traffic via different machines in different places and ofcourse I wanted to use tcpproxy for the task, but it has no x-forwarded-for and so we were pissing our users (with forums, blogs etc) off. So I decided to hack tcpproxy for this. And it works. Serving the millions of pages through it. With x-forwarded-for. &lt;br /&gt;&lt;br /&gt;This was tested on 1.1.9; &lt;br /&gt;&lt;br /&gt;In tcpproxy.c, search for these lines;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;int proxy_request(config_t *x, int cfd)&lt;br /&gt;{&lt;br /&gt;int     sfd, rc, bytes;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;and change to: &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;int     sfd, rc, bytes, first=1, i;&lt;br /&gt;char    *hp, *hp1;&lt;br /&gt;char    tmp[4096];&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;then search for;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  else if (write(sfd, buffer, bytes) != bytes) {&lt;br /&gt;                                syslog(LOG_NOTICE, "client write() error");&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;and change that to; &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;else {&lt;br /&gt;if (first &amp;&amp; (&lt;br /&gt; (buffer[0] == 'G' &amp;&amp; buffer[1] == 'E' &amp;&amp; buffer[2] == 'T') ||&lt;br /&gt; (buffer[0] == 'P' &amp;&amp; buffer[1] == 'O' &amp;&amp; buffer[2] == 'S' &amp;&amp; buffer[3] == 'T') ||&lt;br /&gt; (buffer[0] == 'P' &amp;&amp; buffer[1] == 'U' &amp;&amp; buffer[2] == 'T')&lt;br /&gt; )) {&lt;br /&gt;&lt;br /&gt; hp = &amp;buffer;&lt;br /&gt; *(hp+bytes)='\0';&lt;br /&gt; hp = strstr(buffer, "\r\n\r\n");&lt;br /&gt; if (hp) {&lt;br /&gt;  hp1 = &amp;buffer;&lt;br /&gt;  i = abs(hp1-hp);&lt;br /&gt;  *hp = '\0';&lt;br /&gt;  memcpy(tmp, buffer, bytes+1);&lt;br /&gt;  strupr(buffer);&lt;br /&gt;  if (!strstr(buffer, "X-FORWARDED-FOR")) {&lt;br /&gt;   sprintf(buffer, "%s\r\nX-Forwarded-For: %s\r", tmp, x-&gt;client_ip);&lt;br /&gt;   hp = &amp;tmp;&lt;br /&gt;   hp += i + 1;&lt;br /&gt;   i = bytes - i - 1;&lt;br /&gt;   bytes = i + strlen(buffer);&lt;br /&gt;   hp1 = &amp;buffer;&lt;br /&gt;   hp1 += strlen(buffer);&lt;br /&gt;   memcpy(hp1, hp, i);&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;first = 0;&lt;br /&gt;&lt;br /&gt;if (write(sfd, buffer, bytes) != bytes) {&lt;br /&gt;                                syslog(LOG_NOTICE, "client write() error");&lt;br /&gt; &lt;br /&gt;           break;&lt;br /&gt;                                }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Compile it and it'll add X-Forwarded-For.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-215441226113983491?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/215441226113983491'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/215441226113983491'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2008/04/using-tcpproxy-for-http-forwarding-add.html' title='Using tcpproxy for http forwarding? Add X-Forwarded-For!'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-2305055615314742618</id><published>2008-04-09T04:41:00.000-07:00</published><updated>2008-04-09T04:55:32.731-07:00</updated><title type='text'>Debootstrap must be the most brilliant thing ever conceived</title><content type='html'>Are you lazy?&lt;br /&gt;Are you tired of installing the same shit across Linux servers?&lt;br /&gt;Are you sick of compiling the latest &amp; greatest bag of mplayer/ffmpeg/lame on all your systems? &lt;br /&gt;Are you becoming suicidal when someone asks you to send you a 'working out of the box version'? &lt;br /&gt;&lt;br /&gt;You don't need to be :) Install once, run anywhere (on Linux ofcourse, but what else would you run anyway huh); &lt;br /&gt;&lt;br /&gt;Install debootstrap;&lt;br /&gt;&lt;br /&gt;apt-get install debootstrap&lt;br /&gt;&lt;br /&gt;I personally find it nicest to have everything in a file (so you can easily copy one file and leave it at that);&lt;br /&gt;&lt;br /&gt;First make a loopdevice (3 gb file); &lt;br /&gt;&lt;br /&gt;dd if=/dev/zero of=/myETCH bs=1M count=3000&lt;br /&gt;&lt;br /&gt;Set up kernel loopdevice if you didn't;&lt;br /&gt;&lt;br /&gt;insmod loop.o&lt;br /&gt;&lt;br /&gt;Set up the loop device;&lt;br /&gt;&lt;br /&gt;losetup /dev/loop0 /myETCH&lt;br /&gt;&lt;br /&gt;Format the loopdevice with ext3;&lt;br /&gt;&lt;br /&gt;mkfs.ext3 /dev/loop0&lt;br /&gt;mount /dev/loop0 /myETCH&lt;br /&gt;&lt;br /&gt;then remove everything again; &lt;br /&gt;&lt;br /&gt;umount /dev/loop0&lt;br /&gt;losetup -d /dev/loop0&lt;br /&gt;&lt;br /&gt;Your loopdevice is now ready for use! &lt;br /&gt;&lt;br /&gt;mount it with;&lt;br /&gt;&lt;br /&gt;mount -t ext3 /myEtch /etchinstall -o loop=/dev/loop0&lt;br /&gt;&lt;br /&gt;If you do not want a loopback device, simply run; &lt;br /&gt;&lt;br /&gt;mkdir /etchinstall&lt;br /&gt;&lt;br /&gt;After this you can proceed with installing Debian etch; &lt;br /&gt;&lt;br /&gt;debootstrap etch /etchinstall&lt;br /&gt;&lt;br /&gt;Wait for it to be done.&lt;br /&gt;&lt;br /&gt;Then mount proc; &lt;br /&gt;&lt;br /&gt;mount -t proc proc /etchinstall/proc&lt;br /&gt;&lt;br /&gt;then you can chroot it; &lt;br /&gt;&lt;br /&gt;chroot /etchinstall&lt;br /&gt;&lt;br /&gt;And there you are; your own nice, contained version of Debian Etch.&lt;br /&gt;&lt;br /&gt;Install whatever you want into it. Provide your friends with the loop file /myEtch when you want to have 100% the environment as you!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-2305055615314742618?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/2305055615314742618'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/2305055615314742618'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2008/04/debootstrap-must-be-most-brilliant.html' title='Debootstrap must be the most brilliant thing ever conceived'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-5635721923766796428</id><published>2008-03-31T15:50:00.000-07:00</published><updated>2008-03-31T15:58:29.115-07:00</updated><title type='text'>Heavy encrypting files on your linux box</title><content type='html'>After some nasty run-in with reality I decided to day to take better care of my passwords. By encrypting them with GnuPG, I thought I would stand a much better chance when my laptop gets stolen. I am lazy so I already have my HD encrypted, but, for the super paranoid, as I am becoming more and more, I now also have my passes seperate encrypted in a vault file with 4096 gpg encryption. &lt;br /&gt;&lt;br /&gt;How? Very simple; first generate a pub/priv key pair; &lt;br /&gt;&lt;br /&gt;gpg --gen-key&lt;br /&gt;&lt;br /&gt;then add two files to your path;&lt;br /&gt;&lt;br /&gt;enc;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#!/usr/bin/perl&lt;br /&gt;&lt;br /&gt;$file = $ARGV[0];&lt;br /&gt;$file1 = $ARGV[1]; &lt;br /&gt;&lt;br /&gt;if (!$file or !$file1) {&lt;br /&gt; print "Usage: ./enc input output\n";&lt;br /&gt; exit;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;print `gpg --encrypt --recipient 'Your Name' -o $file1 $file`;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;dec; &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#!/usr/bin/perl&lt;br /&gt;&lt;br /&gt;$file = $ARGV[0]; &lt;br /&gt;&lt;br /&gt;if (!$file) {&lt;br /&gt; print "Usage: dec input\n"; &lt;br /&gt; exit;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;print `gpg --decrypt $file`;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Then make sure you have zero writing tool to delete the original, to be encrypted, file and you're all done :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-5635721923766796428?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/5635721923766796428'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/5635721923766796428'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2008/03/heavy-encrypting-files-on-your-linux.html' title='Heavy encrypting files on your linux box'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-5877175446326850371</id><published>2008-03-09T21:09:00.000-07:00</published><updated>2008-03-09T21:15:45.573-07:00</updated><title type='text'>Mysql (or other) dump in PHP</title><content type='html'>I a lot of sourcode I see the calling of mysqldump to dump tables. Doing so needs all kind of OS dependent path settings and so on, so I thought I share a simple function for dumping a table from MySQL in PHP: &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  function _mysqlDump($table, $toFile) {&lt;br /&gt;   $f = fopen($toFile, "w");&lt;br /&gt;   $qry = "select * from $table";&lt;br /&gt;   $q = mysql_query($qry);&lt;br /&gt;   if (!$q) {&lt;br /&gt;    echo "Could not dump $table\n";&lt;br /&gt;    return;&lt;br /&gt;   }&lt;br /&gt;   while($r = mysql_fetch_assoc($q)) {&lt;br /&gt;    $i1 = ""; $i2 = "";&lt;br /&gt;    foreach($r as $k=&gt;$v) {&lt;br /&gt;     if ($i1) {$i1.=","; $i2.=",";}&lt;br /&gt;     $i1.=$k;&lt;br /&gt;     $v = mysql_real_escape_string($v);&lt;br /&gt;     $i2.="'$v'";&lt;br /&gt;    }&lt;br /&gt;    fputs($f, "insert into $table ($i1) values ($i2);\n");&lt;br /&gt;   }&lt;br /&gt;   fclose($f);&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;  &lt;br /&gt;&lt;br /&gt;The advantage of this is that it creates total inserts which is handy when you want to recreate the database with the content intact.&lt;br /&gt;&lt;br /&gt;Inserting the content back into the database is trivial ofcourse: &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;   $f = fopen($toFile, "r");&lt;br /&gt;   while($s=fgets($f, 128000)) {&lt;br /&gt;    if (trim($s)) mysql_query($s);&lt;br /&gt;   }&lt;br /&gt;   fclose($f);&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-5877175446326850371?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/5877175446326850371'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/5877175446326850371'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2008/03/mysql-or-other-dump-in-php.html' title='Mysql (or other) dump in PHP'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-1588077216349802149</id><published>2008-03-08T21:28:00.000-08:00</published><updated>2008-03-08T21:44:40.854-08:00</updated><title type='text'>Commandline Rapidshare.com downloader</title><content type='html'>Sometimes you would want to download files from rapidshare via the commandline because the webinterface sucks. Did I say sometimes? You *never* want to use the webinterface :)&lt;br /&gt;&lt;br /&gt;You have to have a premium account to use it.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#!/usr/bin/perl&lt;br /&gt;&lt;br /&gt;$user = $ARGV[0];&lt;br /&gt;$pass = $ARGV[1];&lt;br /&gt;$file = $ARGV[2];&lt;br /&gt;&lt;br /&gt;`mkdir ~/.cookies; wget --save-cookies ~/.cookies/rapidshare --post-data "login=$user&amp;password=$pass" -O - https://ssl.rapidshare.com/cgi-bin/premiumzone.cgi &gt; /dev/null`;&lt;br /&gt;&lt;br /&gt;open(F, $file);&lt;br /&gt;while(&lt;F&gt;) {&lt;br /&gt; chomp;&lt;br /&gt; next if /^$/;&lt;br /&gt; print `wget -c --load-cookies ~/.cookies/rapidshare $_`;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-1588077216349802149?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/1588077216349802149'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/1588077216349802149'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2008/03/commandline-rapidsharecom-downloader.html' title='Commandline Rapidshare.com downloader'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-8834315380992809602</id><published>2008-03-08T00:50:00.000-08:00</published><updated>2008-03-08T00:59:17.887-08:00</updated><title type='text'>Automatic destruction of phishing sites</title><content type='html'>The Americans are getting worse with their phishing 'resolutions'; a lot of provider down your server and others implement draconian measures like giving you less than 1 hour to remove the site before they shutdown your equipment. Because we are a small company, we cannot sit behind email 24/7. So we had to be smart instead of hiring more people. &lt;br /&gt;&lt;br /&gt;How does it work? Make an 'abuse' gmail account, have your mailsystem forward all abuse mails to it. Then run the below program in CRON */5. It'll basically remove all scamming sites from existence after a complaint.&lt;br /&gt;&lt;br /&gt;Ofcourse you need to tweak it for your purpose/host. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#!/usr/bin/php&lt;br /&gt;&lt;?php&lt;br /&gt;&lt;br /&gt;$mbox = imap_open ("{pop.gmail.com:995/pop3/ssl/novalidate-cert}INBOX", &lt;br /&gt;        "xxyyzzaabbccdd@gmail.com", "yourpass");&lt;br /&gt;&lt;br /&gt;$msgs=imap_headers($mbox);&lt;br /&gt;foreach ($msgs as $index=&gt;$header) {&lt;br /&gt; $content = imap_body($mbox, $index+1);  &lt;br /&gt; $header = imap_fetchheader($mbox, $index+1);&lt;br /&gt; $msg = $content;&lt;br /&gt; $content = $header.$content;&lt;br /&gt;&lt;br /&gt; $res  = array();&lt;br /&gt;&lt;br /&gt; preg_match("/Subject: (.*)/", $content, $res);&lt;br /&gt; $res = $res[1];&lt;br /&gt; if (strpos($res, "Abuse")!==false) {&lt;br /&gt;  $res1=array();&lt;br /&gt;  preg_match_all("/(.*.yourdomain.com)/", $content, $res1);&lt;br /&gt;&lt;br /&gt;  foreach($res1 as $r) {&lt;br /&gt;   foreach($r as $r1) {&lt;br /&gt;    $i = strpos($r1, ".yourdomain.com")-1; &lt;br /&gt;    $user= "";&lt;br /&gt;    for(;$i&gt;0;$i--) {&lt;br /&gt;     if (in_array($r1[$i], array(' ', '/', '\n', '\r'))) break;&lt;br /&gt;     $user=$r1[$i].$user;&lt;br /&gt;    }  &lt;br /&gt;    kill_user($user);&lt;br /&gt;&lt;br /&gt;    mail("abuse@yourhoster.com", "Re: $res", &lt;br /&gt;        "Dear,\nThis account has been removed.\n\nThank you,\nA Friend\n\n\n$msg", &lt;br /&gt;        "From: afriend@yourdomain.com\n");&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;imap_expunge($mbox);&lt;br /&gt;imap_close($mbox);&lt;br /&gt;?&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-8834315380992809602?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/8834315380992809602'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/8834315380992809602'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2008/03/automatic-destruction-of-phishing-sites.html' title='Automatic destruction of phishing sites'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-6545654473849601643</id><published>2008-03-03T13:49:00.000-08:00</published><updated>2008-03-03T13:55:34.165-08:00</updated><title type='text'>postfix, cannot connect to mysql server localhost</title><content type='html'>When trying to run Postfix with virtual maps in MySQL, you can get the following error: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;connect to mysql server localhost: Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' postfix&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This error is because postfix is running in chroot /var/spool/postfix. So it cannot find the unix socket for MySQL.&lt;br /&gt;&lt;br /&gt;If you have the option to run mysql on 127.0.0.1 or on another IP, simply go to;&lt;br /&gt;&lt;br /&gt;/etc/postfix&lt;br /&gt;&lt;br /&gt;run;&lt;br /&gt;&lt;br /&gt;grep localhost *&lt;br /&gt;&lt;br /&gt;and replace all localhost to 127.0.0.1 or the IP in all files starting with mysql-virtual.&lt;br /&gt;&lt;br /&gt;If you insist on running via unix sockets, you can simply fix it by running; &lt;br /&gt;&lt;br /&gt;mkdir /var/spool/postfix/var&lt;br /&gt;mount --bind /var /var/spool/postfix/var&lt;br /&gt;&lt;br /&gt;Ater this, all will work fine.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-6545654473849601643?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/6545654473849601643'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/6545654473849601643'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2008/03/postfix-cannot-connect-to-mysql-server.html' title='postfix, cannot connect to mysql server localhost'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-2364332566011946032</id><published>2008-02-29T11:24:00.000-08:00</published><updated>2008-02-29T11:32:35.743-08:00</updated><title type='text'>Stupid DDOS attacks - a simple script and common sense</title><content type='html'>Today we had some fun; a DDOS attack from  some kind of botnet. We can hundreds (thousands) of IPs sending something to Apache like;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;$MyNick Aando|$Lock EXTENDEDPROT&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The new Linux kernel iptables can DROP/REJECT based on strings, but I was not going to recompile and install an experimental kernel for this 'little problem', risking more downtime than need-be. &lt;br /&gt;&lt;br /&gt;So I used sniffing to detect problems:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;tcpdump -n -vvv -i eth0 -A|grep -B 1 \$MyNick|grep \.80: &gt; /tmp/ip.log&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;(grepping for port .80: because it is attacking my webserver)&lt;br /&gt;&lt;br /&gt;Then a killer perl script to block the offending IPs:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#!/usr/bin/perl&lt;br /&gt;&lt;br /&gt;%ips=();&lt;br /&gt;open(F, "tail -f /tmp/ip.log|");&lt;br /&gt;while(&lt;F&gt;){&lt;br /&gt; chomp;&lt;br /&gt; /.*\)\ (\d+?\.\d+?\.\d+?\.\d+?)\..*?\&gt;/;&lt;br /&gt; $ip = $1;&lt;br /&gt; next if $ip=~/127.0.0/;&lt;br /&gt; if (!$ips{$ip}) {&lt;br /&gt;  $ips{$ip} = 1;&lt;br /&gt;  `iptables -A INPUT -p tcp  --source $ip --dport 80 -j REJECT`;&lt;br /&gt;  print "$ip blocked\n";&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;close F;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This'll do it; server freed up and we could serve again nicely :) No need for recompiling at all!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-2364332566011946032?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/2364332566011946032'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/2364332566011946032'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2008/02/stupid-ddos-attacks-simple-script-and.html' title='Stupid DDOS attacks - a simple script and common sense'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-2551067388688195207</id><published>2008-02-28T02:07:00.000-08:00</published><updated>2008-02-28T02:08:28.455-08:00</updated><title type='text'>Apache logs: simple log analyzer in Perl - II</title><content type='html'>I added top 30 and bandwidth / minute; &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#!/usr/bin/perl&lt;br /&gt;&lt;br /&gt;# get handler to the logfile&lt;br /&gt;open(LOG_FILE, "tail -f /var/log/httpd/access_log.users|");&lt;br /&gt;&lt;br /&gt;# start the main loop&lt;br /&gt;%users = ();&lt;br /&gt;$cp=0;&lt;br /&gt;$ct=time();&lt;br /&gt;while(&lt;LOG_FILE&gt;) {&lt;br /&gt; chomp;&lt;br /&gt; &lt;br /&gt; $cp = time() + 5*60 if $cp==0;&lt;br /&gt; if (-f "/tmp/killtraffic") {&lt;br /&gt;  %users=();&lt;br /&gt;  `rm -f /tmp/killtraffic`;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; my $t1 = time(); # timestamp for checkpointing&lt;br /&gt;&lt;br /&gt; my ($dom, $ip, $date, $req, $code, $ref, $client, $in, $out) &lt;br /&gt;                = /(.*?)\ (.*?)\ .*?\[(.*?)\]\ \"(.*?)\"\ (.*?)\ .*?\"(.*?)\"\ \"(.*?)\"\ (.*?)\ (.*)/;&lt;br /&gt;&lt;br /&gt; my ($method, $uri, $proto) = ($req =~ /(.*?)\ (.*?)\ (.*)/);&lt;br /&gt;&lt;br /&gt; my $get = 0;&lt;br /&gt; if ($uri =~ /(.*?)\?(.*)$/) {&lt;br /&gt;  $uri = $1;&lt;br /&gt;  $get = $2;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; my $url = $dom;&lt;br /&gt;&lt;br /&gt; if (!$users{$url}) {&lt;br /&gt;  $users{$url} = $in + $out;&lt;br /&gt; } else {&lt;br /&gt;  $users{$url} = $users{$url} + $in + $out;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; $cpc = time();&lt;br /&gt; if ( $cpc &gt; $cp ) {&lt;br /&gt;  $cp=0; &lt;br /&gt;  my $s="";&lt;br /&gt;  $m = (time()-$ct) / 60;&lt;br /&gt;  $count = 0;&lt;br /&gt;  foreach(keys %users) {&lt;br /&gt;   $s.=($users{$_}/1024)." kb - ".($users{$_}/1024/$m)." kb/min - ".$_."\n";&lt;br /&gt;   $count++; &lt;br /&gt;   last if $count&gt;30;&lt;br /&gt;  }&lt;br /&gt;  `echo "Count started $m minutes ago\n" &gt; /tmp/traffic.log`;&lt;br /&gt;  `echo "$s"|sort -n -r &gt;&gt; /tmp/traffic.log`;&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;# never get here:&lt;br /&gt;close LOG_FILE;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-2551067388688195207?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/2551067388688195207'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/2551067388688195207'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2008/02/apache-logs-simple-log-analyzer-in-perl_28.html' title='Apache logs: simple log analyzer in Perl - II'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-3213164773937451252</id><published>2008-02-28T01:38:00.000-08:00</published><updated>2008-02-28T01:45:19.123-08:00</updated><title type='text'>Apache logs: simple log analyzer in Perl</title><content type='html'>Get Apache to log your bandwidth by putting in httpd.conf/apache2.conf;&lt;br /&gt;&lt;br /&gt;LogFormat "%V %h %l %u %t \"%r\" %&gt;s %b \"%{Referer}i\" \"%{User-agent}i\" %I %O" combined_io&lt;br /&gt;CustomLog /var/log/httpd/access_log.users combined_io&lt;br /&gt;&lt;br /&gt;And run the following perl script;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#!/usr/bin/perl&lt;br /&gt;&lt;br /&gt;# get handler to the logfile&lt;br /&gt;open(LOG_FILE, "tail -f /var/log/httpd/access_log.users|");&lt;br /&gt;&lt;br /&gt;# start the main loop&lt;br /&gt;%users = ();&lt;br /&gt;$cp=0;&lt;br /&gt;while(&lt;LOG_FILE&gt;) {&lt;br /&gt; chomp;&lt;br /&gt; &lt;br /&gt; $cp = time() + 5*60 if $cp==0; # set to refresh the traffic.log file every 5 min&lt;br /&gt; &lt;br /&gt; my $t1 = time(); # timestamp for checkpointing&lt;br /&gt;&lt;br /&gt; my ($dom, $ip, $date, $req, $code, $ref, $client, $in, $out) &lt;br /&gt;                = /(.*?)\ (.*?)\ .*?\[(.*?)\]\ \"(.*?)\"\ (.*?)\ .*?\"(.*?)\"\ \"(.*?)\"\ (.*?)\ (.*)/;&lt;br /&gt;&lt;br /&gt; my ($method, $uri, $proto) = ($req =~ /(.*?)\ (.*?)\ (.*)/);&lt;br /&gt;&lt;br /&gt; my $get = 0;&lt;br /&gt; if ($uri =~ /(.*?)\?(.*)$/) {&lt;br /&gt;  $uri = $1;&lt;br /&gt;  $get = $2;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; my $url = $dom;&lt;br /&gt;&lt;br /&gt; if (!$users{$url}) {&lt;br /&gt;  $users{$url} = $in + $out;&lt;br /&gt; } else {&lt;br /&gt;  $users{$url} = $users{$url} + $in + $out;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; $cpc = time();&lt;br /&gt; if ( $cpc &gt; $cp ) {&lt;br /&gt;  $cp=0; &lt;br /&gt;  my $s = "";&lt;br /&gt;  foreach(keys %users) {&lt;br /&gt;   $s.=($users{$_}/1024)." kb - ".$_."\n";&lt;br /&gt;  }&lt;br /&gt;  `echo "$s"|sort -n -r &gt; /tmp/traffic.log`;&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;# never get here:&lt;br /&gt;close LOG_FILE;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;By viewing /tmp/traffic.log, you'll see what/who is using most traffic.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-3213164773937451252?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/3213164773937451252'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/3213164773937451252'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2008/02/apache-logs-simple-log-analyzer-in-perl.html' title='Apache logs: simple log analyzer in Perl'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-1486353920915690368</id><published>2008-02-24T23:09:00.000-08:00</published><updated>2008-02-24T23:35:48.838-08:00</updated><title type='text'>A better killall and such</title><content type='html'>Didn't you sometimes wish you had a 'superkill'; a kill that kills all processes with a certain text in it. Killall is supposed to do that, but actually never does, as you have to type the complete command which is a pain. So I usually type:&lt;br /&gt;&lt;br /&gt;ps auxw|grep -i apache|awk '{print $2}'|xargs kill -9&lt;br /&gt;&lt;br /&gt;in this case killing Apache (1 and 2). &lt;br /&gt;&lt;br /&gt;To make life easier, as a regular part of my Debian and Ubuntu installs, I now have the command 'sk' (superkill) in /usr/sbin/sk;&lt;br /&gt;&lt;br /&gt;#!/bin/sh&lt;br /&gt;&lt;br /&gt;ps uaxw|grep -i $1|grep -v $0|grep -v grep|awk '{print $2}'|xargs kill -9&lt;br /&gt;&lt;br /&gt;allowing me to run;&lt;br /&gt;&lt;br /&gt;sk apache&lt;br /&gt;&lt;br /&gt;and gone it is.&lt;br /&gt;&lt;br /&gt;Now that I am writing this anyway; here is another missing command :)&lt;br /&gt;&lt;br /&gt;find /some/directory -maxdepth 1 -type f -mtime +2 -exec rm {} \;&lt;br /&gt;&lt;br /&gt;Into a file /usr/sbin/ro; &lt;br /&gt;&lt;br /&gt;#!/bin/sh&lt;br /&gt;&lt;br /&gt;find $1 -maxdepth 1 -type f -mtime +$2 -exec rm {} \;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-1486353920915690368?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/1486353920915690368'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/1486353920915690368'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2008/02/better-killall.html' title='A better killall and such'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-341656389492530100</id><published>2008-01-07T07:30:00.000-08:00</published><updated>2008-01-07T07:45:46.848-08:00</updated><title type='text'>Talking to SMTP / Mail via telnet to diagnoze mail problems on a server</title><content type='html'>Mailserver diagnoses can be tricky: I personally find the easiest way to do it still using telnet in combination with the server logs to find out what exactly is wrong. &lt;br /&gt;&lt;br /&gt;It is very easy to do: &lt;br /&gt;&lt;br /&gt;telnet thehost.com 25&lt;br /&gt;&lt;br /&gt;helo: myhost.com&lt;br /&gt;mail from: me@myhost.com&lt;br /&gt;rcpt to: someone@thehost.com&lt;br /&gt;data&lt;br /&gt;&lt;br /&gt;... type some data ...&lt;br /&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;quit&lt;br /&gt;&lt;br /&gt;That is all; it will help to exactly determine where it goes wrong.&lt;br /&gt;&lt;br /&gt;The case we had today; &lt;br /&gt;&lt;br /&gt;- postfix didn't send mail ; it gave connection refused&lt;br /&gt;- thoughts; firewall, network, dns etc.&lt;br /&gt;- we tried the above and it worked fine, meaning postfix was the one refusing, not the network/firewall etc&lt;br /&gt;- we fixed the postfix config and all was fine&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-341656389492530100?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/341656389492530100'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/341656389492530100'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2008/01/talking-to-smtp-mail-via-telnet-to.html' title='Talking to SMTP / Mail via telnet to diagnoze mail problems on a server'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-4529875920681623462</id><published>2008-01-06T08:30:00.000-08:00</published><updated>2008-01-06T08:36:04.350-08:00</updated><title type='text'>PHP Posting to ASP.NET (ASPX) pages / sites</title><content type='html'>If you want to post anything (for instance a login/password), you need to take the viewstate in order to be able to post anything to any aspx page, so request the page for the first time, in the same session: &lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;  $ch = curl_init();&lt;br /&gt;&lt;br /&gt;  curl_setopt($ch, CURLOPT_URL, $login_url);&lt;br /&gt;  curl_setopt($ch, CURLOPT_HEADER, 1);&lt;br /&gt;  curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);&lt;br /&gt;  curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);&lt;br /&gt;  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);&lt;br /&gt;  curl_setopt($ch, CURLOPT_COOKIEJAR, 'cookie.txt');&lt;br /&gt;  curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookie.txt');&lt;br /&gt;  curl_setopt($ch, CURLOPT_POST, 0);&lt;br /&gt;  curl_setopt($ch, CURLOPT_POSTFIELDS, array());&lt;br /&gt;  $data = curl_exec($ch);&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Then you collect the viewstate;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;  $vars = array("login"=&gt;$user,&lt;br /&gt;                "password"=&gt;$pass);&lt;br /&gt;&lt;br /&gt;  $i = strpos($data, "__VIEWSTATE");&lt;br /&gt;  $i = strpos($data, "value=", $i);&lt;br /&gt;  $i += 7;&lt;br /&gt;  $j = strpos($data, "\"", $i+1);&lt;br /&gt;  $viewstate = substr($data, $i, $j-$i);&lt;br /&gt;  $vars['__VIEWSTATE'] = $viewstate;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;After that you can safely login to the site; &lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;  curl_setopt($ch, CURLOPT_URL, $login_url);&lt;br /&gt;  curl_setopt($ch, CURLOPT_HEADER, 1);&lt;br /&gt;  curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);&lt;br /&gt;  curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);&lt;br /&gt;  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);&lt;br /&gt;  curl_setopt($ch, CURLOPT_COOKIEJAR, 'cookie.txt');&lt;br /&gt;  curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookie.txt');&lt;br /&gt;  curl_setopt($ch, CURLOPT_POST, 1);&lt;br /&gt;  curl_setopt($ch, CURLOPT_POSTFIELDS, $vars);&lt;br /&gt;  $data = curl_exec($ch)&lt;br /&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-4529875920681623462?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/4529875920681623462'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/4529875920681623462'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2008/01/php-posting-to-aspnet-aspx-pages-sites.html' title='PHP Posting to ASP.NET (ASPX) pages / sites'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-6831725003542785957</id><published>2007-12-24T11:11:00.000-08:00</published><updated>2007-12-24T11:15:44.271-08:00</updated><title type='text'>Analyzing MySQL usage; finding and fixing bottlenecks</title><content type='html'>MyTop and Mtop are nice tools to analyze MySQL load and queries, however long running systems require another system, so I present a simple script to analyze longer running multi user databases for abusers and bottlenecks. The code is very easy to alter to retrieve other stats. &lt;br /&gt;Otherwise you can always mail me to fix it for what you might need.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;#!/usr/bin/perl&lt;br /&gt;&lt;br /&gt;while(1) {&lt;br /&gt; # load all previous data, if any&lt;br /&gt; %users = (); &lt;br /&gt; if (-f "./sql.log") {&lt;br /&gt;  open(F, "./sql.log"); &lt;br /&gt;  while(&lt;F&gt;) {&lt;br /&gt;   chomp; &lt;br /&gt;   # user no_queries tot_length&lt;br /&gt;   /(.*?)\ (.*?)\ (.*)/;&lt;br /&gt;   $users{$1} = "$2 $3";&lt;br /&gt;  }&lt;br /&gt;  close F;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; @p = `mysql -u yyy --password=xxx --execute='show full processlist'`;&lt;br /&gt; for($i=3;$i&amp;lt;scalar(@p)-1;$i++) {&lt;br /&gt;  $r = $p[$i]; &lt;br /&gt;  chomp($r); &lt;br /&gt;  @cols = split(/\t/, $r);&lt;br /&gt;&lt;br /&gt;  next if $cols[4] eq "Sleep";&lt;br /&gt;&lt;br /&gt;  $q = ""; &lt;br /&gt;  for($j=7;$j&amp;lt;scalar(@cols);$j++) {&lt;br /&gt;   $q .= $cols[$j]." ";&lt;br /&gt;  }&lt;br /&gt;  next if $q=~/show full processlist/;&lt;br /&gt;  next if $q eq "NULL";&lt;br /&gt;&lt;br /&gt;  $u = $cols[1];  &lt;br /&gt;  $l = $cols[5];&lt;br /&gt;&lt;br /&gt;  $res = "";&lt;br /&gt;  if (!$users{$u}) {&lt;br /&gt;   $res = "1 $l";&lt;br /&gt;  } else {&lt;br /&gt;   $res = $users{$u}; &lt;br /&gt;   $res =~ /(.*?)\ (.*)/; &lt;br /&gt;   $l += $2;&lt;br /&gt;   $t = $1 + 1;&lt;br /&gt;   $res = "$t $l";&lt;br /&gt;  }&lt;br /&gt;  $users{$u} = $res;&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; open(F, "&gt;./sql.log");&lt;br /&gt; foreach(keys(%users)) {&lt;br /&gt;  $res = $users{$_};&lt;br /&gt;  print F "$_ $res\n";&lt;br /&gt; }&lt;br /&gt; close F;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-6831725003542785957?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/6831725003542785957'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/6831725003542785957'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2007/12/analyzing-mysql-usage-finding-and.html' title='Analyzing MySQL usage; finding and fixing bottlenecks'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-2929552091179580048</id><published>2007-12-21T05:08:00.000-08:00</published><updated>2007-12-21T05:14:15.212-08:00</updated><title type='text'>Automatically kill all processes that do not belong on your system</title><content type='html'>A client of mine asked me for a program which would destroy 'illegal' processes. After a brief search I found the existing apps too limited or not configurable, so I threw one together that learns itself which processes are and are not allowed. &lt;br /&gt;&lt;br /&gt;Simply run it like;&lt;br /&gt;&lt;br /&gt;./process.pl learn&lt;br /&gt;&lt;br /&gt;first; just do all stuff on your computer/server that is normal, so the system can learn. &lt;br /&gt;&lt;br /&gt;After that press ctrl-c and rerun as:&lt;br /&gt;&lt;br /&gt;./process.pl check&lt;br /&gt;&lt;br /&gt;That's it!&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#!/usr/bin/perl&lt;br /&gt;&lt;br /&gt;$cmd = $ARGV[0]; &lt;br /&gt;&lt;br /&gt;if (!$cmd) {&lt;br /&gt; $cmd = "check"; &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;%allowproc = (); &lt;br /&gt;if ($cmd eq "check") {&lt;br /&gt; open(F, "procs.log"); &lt;br /&gt; while(&lt;F&gt;) {&lt;br /&gt;  chomp;&lt;br /&gt;  $allowproc{$_} = 1; &lt;br /&gt; }&lt;br /&gt; close F; &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;if ($cmd eq "learn") {&lt;br /&gt; open(F, "&gt;procs.log"); &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;while (1) {&lt;br /&gt; @procs = `ps auxwww`;&lt;br /&gt; foreach(@procs) {&lt;br /&gt;  chomp; &lt;br /&gt;  /.*?\s+(.*?)\s+.*?\s+.*?\s+.*?\s+.*?\s+.*?\s+.*?\s+.*?\s+.*?\s+(.*)/;&lt;br /&gt;  next if /^$/;&lt;br /&gt;  next if /defunct/;&lt;br /&gt;  next if /process.pl/;&lt;br /&gt;  if (!$allowproc{$2}) {&lt;br /&gt;   if ($cmd eq "learn") {&lt;br /&gt;    $allowproc{$2} = 1;&lt;br /&gt;    print F $2."\n";&lt;br /&gt;   } else {&lt;br /&gt;    if (!$allowproc{$2}) {&lt;br /&gt;     `kill -9 $1`;&lt;br /&gt;    }&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt; sleep 1;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-2929552091179580048?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/2929552091179580048'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/2929552091179580048'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2007/12/automatically-kill-all-processes-that.html' title='Automatically kill all processes that do not belong on your system'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-6958479673187659007</id><published>2007-12-19T04:44:00.000-08:00</published><updated>2007-12-19T04:46:20.173-08:00</updated><title type='text'>How to make sendmail send from another IP FROM address</title><content type='html'>put, in /etc/mail/sendmail.cf;&lt;br /&gt;&lt;br /&gt;O ClientPortOptions=Family=inet, Addr=YOURIP&lt;br /&gt;&lt;br /&gt;where YOURIP is the address you want to use to send from.&lt;br /&gt;&lt;br /&gt;Handy if one of your IPs is blacklisted or if it doesn't have PTR record (but others on the server have).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-6958479673187659007?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/6958479673187659007'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/6958479673187659007'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2007/12/how-to-make-sendmail-send-from-another.html' title='How to make sendmail send from another IP FROM address'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-764447280226527142</id><published>2007-12-18T08:26:00.000-08:00</published><updated>2007-12-18T08:50:14.783-08:00</updated><title type='text'>Removing the Linux ext filelimit for scripts that do not circumvent that limit (like Mihalism multi host image hosting script)</title><content type='html'>With a few changes this will work on any script / system ofcourse, but it was done for Mihalism.&lt;br /&gt;&lt;br /&gt;First you need to put all files in directories, go to the 'files' directory and run;&lt;br /&gt;&lt;br /&gt;ls -la|awk '{print $8}'|perl -e 'while(&lt;&gt;){chomp; @a=split(//, $_);$d="";for($i=0;$i&lt;5;$i++){$d.=@a[$i]."/"; print `mkdir $d`}; print `mv $_ $d`;}'&lt;br /&gt;&lt;br /&gt;Then the code needs a bit of fixing; &lt;br /&gt; &lt;br /&gt;open the file &lt;br /&gt;&lt;br /&gt; source/global_functions.php &lt;br /&gt;&lt;br /&gt;and add a function; &lt;br /&gt;&lt;br /&gt;function calc_directory($file){&lt;br /&gt; $dir = ""; &lt;br /&gt; for($i=0;$i&lt;5;$i++) $dir .= $file[$i]."/";&lt;br /&gt; return $dir;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;then you need to fix all files that are calling the $path and $file to reflect the changed; &lt;br /&gt;&lt;br /&gt;in the main directory of the script, run;&lt;br /&gt;&lt;br /&gt;grep -R \$path.\$file *|awk '{print $1}'|uniq|perl -e 'while(&lt;&gt;){chomp; /^(.*):$/; $f=$1;$s=`cat $f`; $s=~s/\$path.\$filename/\$path.calc_directory\(\$filename\)/isgm; $s=~s/\$path.\$file/\$path.calc_directory\(\$file\)/isgm; open(F, "&gt;$f"); print F $s; close F;}'&lt;br /&gt;&lt;br /&gt;and then test; I had no time to test yet, but the idea should be clear enough.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-764447280226527142?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/764447280226527142'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/764447280226527142'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2007/12/removing-linux-ext-filelimit-for.html' title='Removing the Linux ext filelimit for scripts that do not circumvent that limit (like Mihalism multi host image hosting script)'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-1187969831465382663</id><published>2007-11-15T01:29:00.001-08:00</published><updated>2007-11-15T01:32:16.885-08:00</updated><title type='text'>Simple stuff to use and remember; one liner grep and replace and when the time on your server is not ok</title><content type='html'>Grep and replace over all files in the current dit and the dirs below that;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;perl -e '@f=`find . -type f`;foreach(@f){chomp;$s=`cat $_`;$s=~s/php/jsp/isgm;open(F,"&gt;$_");print F $s; close F;}';&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;When the time on the server is not ok, even after running ntpdate, probably your timezone is wrong. Run: &lt;br /&gt;&lt;br /&gt;tzconfig&lt;br /&gt;&lt;br /&gt;and set your timezone even when it &lt;strong&gt;looks&lt;/strong&gt; ok already.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-1187969831465382663?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/1187969831465382663'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/1187969831465382663'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2007/11/simple-stuff-to-use-and-remember-one.html' title='Simple stuff to use and remember; one liner grep and replace and when the time on your server is not ok'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-7658770481385688423</id><published>2007-11-14T07:06:00.000-08:00</published><updated>2007-11-14T07:10:28.488-08:00</updated><title type='text'>Preventing bugs in PHP : stripslashes</title><content type='html'>To prevent code injection, most PHP code has magic_quotes_gpc = On. For more than one reason this bad and introduces a lot of (difficult to debug) problems in large code bases. So it is better to switch that off from the get go. &lt;br /&gt;&lt;br /&gt;If you do not have permission to switch that off (like on a lot of free hosting services), you can call the following code before doing anything else.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;if(get_magic_quotes_gpc()) {&lt;br /&gt; foreach($_REQUEST as $k=&gt;$v) {&lt;br /&gt;  $_REQUEST[$k] = stripslashes($v);&lt;br /&gt; }&lt;br /&gt; foreach($_POST as $k=&gt;$v) {&lt;br /&gt;  $_POST[$k] = stripslashes($v);&lt;br /&gt; }&lt;br /&gt; foreach($_GET as $k=&gt;$v) {&lt;br /&gt;  $_GET[$k] = stripslashes($v);&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ofcourse do &lt;strong&gt;not&lt;/strong&gt; forget to escape stuff that goes into your database!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-7658770481385688423?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/7658770481385688423'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/7658770481385688423'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2007/11/preventing-bugs-in-php-stripslashes.html' title='Preventing bugs in PHP : stripslashes'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-4335799180391637772</id><published>2007-11-08T01:21:00.000-08:00</published><updated>2007-11-08T02:50:34.571-08:00</updated><title type='text'>Checking what is eating your memory.... Part III</title><content type='html'>Finally I found out what it was AND it was / is (using &lt;a href="http://brainfish-eat-fishbrain.blogspot.com/2007/11/checking-what-is-eating-your-memory_06.html"&gt;this&lt;/a&gt; script) a major flaw in the (gz) output handler; a user on the server uses in his code;&lt;br /&gt;&lt;br /&gt;ob_start("ob_gzhandler", 9);&lt;br /&gt;&lt;br /&gt;something();&lt;br /&gt;&lt;br /&gt;ob_flush();&lt;br /&gt;&lt;br /&gt;If something() generates a certain amounts of data, the ob_gzhandler will get stuck in a loop, eating all memory. &lt;br /&gt;&lt;br /&gt;In the user his particular case, because his database was not working, some pages always have this 'magic size' (probably some factor of 9 in this case). &lt;br /&gt;&lt;br /&gt;I tried this on the latest stable of PHP 5 and the bug is still there; you can crash &lt;span style="font-weight:bold;"&gt;any&lt;/span&gt; php hosting machine on the net with this :(&lt;br /&gt;&lt;br /&gt;As to prevent this kind of thing from happening, I put the following code on the machines; &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#!/usr/bin/perl&lt;br /&gt;&lt;br /&gt;$maxmem=10;&lt;br /&gt;&lt;br /&gt;while(1) {&lt;br /&gt;  @r=`ps auxwhww|awk '{print \$4,\$2,\$11,\$12,\$13,\$15}'|grep httpd-users|grep -v grep`;&lt;br /&gt;  foreach(@r) {&lt;br /&gt;   chomp;&lt;br /&gt;   /(.*?)\ (.*?)\ (.*)/;&lt;br /&gt;   if ($1&gt;$maxmem) {&lt;br /&gt;    print "$_ killed\n";&lt;br /&gt;    `kill -9 $2`;&lt;br /&gt;   }&lt;br /&gt;  sleep 1;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Update: Only PHP5.x is affected, not lower (tested); didn't try higher. I have code to reproduce it every run.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-4335799180391637772?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/4335799180391637772'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/4335799180391637772'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2007/11/checking-what-is-eating-your-memory_08.html' title='Checking what is eating your memory.... Part III'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-1910608801585922434</id><published>2007-11-07T08:10:00.000-08:00</published><updated>2007-11-07T08:40:04.689-08:00</updated><title type='text'>Enterprise workflow................</title><content type='html'>Today the server of an important client went down. Was not reachable. Not that interesting as, with the enormous amounts of servers we are managing these days, that happens more often. &lt;br /&gt;&lt;br /&gt;What was nice about it is the process surrounding this issue. The server was the mail relay server. So the client could no longer send mail from his website to the outside world, as this mail goes via the relay server. &lt;br /&gt;&lt;br /&gt;Unfortunately the admin was, for a brief moment not reachable to use remote powerboot to fix it, so I uttered the, in hindsight, dangerous words; &lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;this is a mail relay, why don't we just set another relay for the moment?&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Apparently the 10 minutes (even less...) required to change the relay in Postfix, were translated into the company (that hired me) workflow to: &lt;br /&gt;&lt;br /&gt;1. ask John to create an issue in Jira&lt;br /&gt;2. assign the issue to the person in charge of the admin work load distribution, Frank&lt;br /&gt;3. Frank will check the roster of the admins and assign one; Paul &lt;br /&gt;4. Paul will estimate the time needed to change the relay (a whopping 8 hours!) and assigns the issue back to Frank&lt;br /&gt;5. Frank fixes the estimate by Paul by setting the estimate to estimate*PI and assigns back to John&lt;br /&gt;6. John assigns the issue to sales &lt;br /&gt;7. Sales talks to the client and asks for estimate*PI*120%*$100 ~ $3000&lt;br /&gt;8. After approval the issue is assigned back to John&lt;br /&gt;9. John assigns to Frank &lt;br /&gt;10. Frank assigns to someone other than Paul (as that is how it goes)&lt;br /&gt;&lt;br /&gt;During step 2 the admin came back and rebooted the server. &lt;br /&gt;&lt;br /&gt;Unfortunately the above is not strange; any person working at a bigger company knows that this is actually not too bad compared to even bigger companies. In fact; Frank or Paul in steps 2,3,4 should have sent the issue back to John for lack of a clear RFP. And the estimate is actually quite low, considering someone has to write an RFP, FO and TO for this problem. And no, I am not kidding, as I see it happen every day.&lt;br /&gt;&lt;br /&gt;Enterprises are weird entities that spend massive amounts of $ on nothing at all. Wondering if it is possible to run one without all that crud... It is a disease and I am waiting for 10 years already for IT to kick in and make at least the almost enterprises or middle sized companies a lot leaner than this. Hasn't happen though. People still buy ERP systems for millions that are unusable, they still hire 'enterprise Java' guys for $200/hour and consultants for $2500/day to tell them how to work Websphere and so on. A sick, sick world. &lt;br /&gt;&lt;br /&gt;(the names have been changed to protect the innocent)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-1910608801585922434?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/1910608801585922434'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/1910608801585922434'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2007/11/enterprise-workflow.html' title='Enterprise workflow................'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-5906001234204790776</id><published>2007-11-06T01:14:00.000-08:00</published><updated>2007-11-06T01:19:40.310-08:00</updated><title type='text'>Checking what is eating your memory.... Part II</title><content type='html'>The experiment of yesterday was showing me only apache2 doing this; I was hoping the strace would show me the path to the offending code (as I am almost 100% sure it is PHP doing it). Instead it showed me an entire file full of mmap2 which are taking away memory. No paths as the strace only kicks in when the system is already dying, so too late. &lt;br /&gt;&lt;br /&gt;So I had to make some code to check this further:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#!/usr/bin/perl&lt;br /&gt;&lt;br /&gt;$maxmem=10;&lt;br /&gt;&lt;br /&gt;`mkdir memstrace`;&lt;br /&gt;`rm memstrace/*`;&lt;br /&gt;&lt;br /&gt;%detected=();&lt;br /&gt;&lt;br /&gt;open(F, "&gt;mem.log");&lt;br /&gt;while(1) {&lt;br /&gt;  @r=`ps auxwhww|awk '{print \$4,\$2,\$11,\$12,\$13,\$15}'|grep httpd-users|grep -v grep`;&lt;br /&gt;  foreach(@r) {&lt;br /&gt;   chomp;&lt;br /&gt;   /(.*?)\ (.*?)\ (.*)/;&lt;br /&gt;   if ($1&gt;$maxmem and !$detected{$2}) {&lt;br /&gt;    print F "$_\n";&lt;br /&gt;    $detected{$2} = 1;&lt;br /&gt;   }&lt;br /&gt;   next if -f "memstrace/$2";&lt;br /&gt;   if (!fork()) {&lt;br /&gt;    `strace -f -o memstrace/$2 -p $2`;&lt;br /&gt;    exit;&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt;  sleep 1;&lt;br /&gt;}&lt;br /&gt;close F;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Which should store all Apache syscalls including the offending and then log which one is offending when it becomes that.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-5906001234204790776?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/5906001234204790776'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/5906001234204790776'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2007/11/checking-what-is-eating-your-memory_06.html' title='Checking what is eating your memory.... Part II'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-7798271226669020810</id><published>2007-11-05T09:03:00.000-08:00</published><updated>2007-11-06T01:06:00.709-08:00</updated><title type='text'>Checking what is eating your memory....</title><content type='html'>We have several servers running &gt; 50.000 sites. On those servers there is always 2 gb of memory free. Except sometimes when memory suddenly disappears in seconds and the system starts swapping, load jumps to &gt; 400 in seconds after that. This happens once every few hours for a few days now.&lt;br /&gt;&lt;br /&gt;When watching top, we see that memory of Apache2 grows to &gt; 50%. So what site is doing that out of 50.000+? I made a script for checking that; &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#!/usr/bin/perl&lt;br /&gt;&lt;br /&gt;$maxmem=10;&lt;br /&gt;&lt;br /&gt;`mkdir memstrace`;&lt;br /&gt;open(F, "&gt;mem.log");&lt;br /&gt;while(1) {&lt;br /&gt;  @r=`ps auxwhww|awk '{print \$4,\$2,\$11,\$12,\$13,\$15}'|sort -n|tail -n 5`;&lt;br /&gt;  foreach(@r) {&lt;br /&gt;   chomp;&lt;br /&gt;   /(.*?)\ (.*?)\ (.*)/;&lt;br /&gt;   if ($1 &gt; $maxmem) {&lt;br /&gt;    next if -f "memstrace/$2";&lt;br /&gt;    print F "$_\n";&lt;br /&gt;    if(!fork()) {&lt;br /&gt;     `strace -f -o memstrace/$2 -p $2`&lt;br /&gt;     exit;&lt;br /&gt;    };&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt;  sleep 1;&lt;br /&gt;}&lt;br /&gt;close F;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-7798271226669020810?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/7798271226669020810'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/7798271226669020810'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2007/11/checking-what-is-eating-your-memory.html' title='Checking what is eating your memory....'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-2695228973205959018</id><published>2007-10-29T06:47:00.000-07:00</published><updated>2007-10-29T06:56:07.171-07:00</updated><title type='text'>Perl FP : getting abusers from my mail logger one-liner</title><content type='html'>To catch abusers of my free hosting service, I altered the PHP C source to write mail sending scripts (we only allow mail() to send mail; no fsockopen etc) to a log file. This file looks like this: &lt;br /&gt;&lt;br /&gt;/www/user/htdocs/sendmail.php&lt;br /&gt;/www/user/htdocs/sendmail.php&lt;br /&gt;/www/user/htdocs/sendmail.php&lt;br /&gt;/www/user/htdocs/sendmail.php&lt;br /&gt;/www/user/htdocs/sendmail.php&lt;br /&gt;/www/user/htdocs/sendmail.php&lt;br /&gt;/www/user/htdocs/phpBB3/something.php&lt;br /&gt;etc&lt;br /&gt;&lt;br /&gt;Now I wanted to find people that are sending more than X mails and get a warning about them. For this I wrote the following code; &lt;br /&gt;&lt;br /&gt;map { /(.*?)\ (.*)$/; if($1&gt;$cm) {print "Abusing: $2\n";} } `cat $mf|sort|uniq -c|awk '{print \$1 " " \$2}'|sort -g`;&lt;br /&gt;&lt;br /&gt;where $mf  is the log file and $cm the X which is the maximum number of mails a user is allowed to send. &lt;br /&gt;&lt;br /&gt;I run this in a cron and I actually block users with more than 400 mails. Works like a charm.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-2695228973205959018?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/2695228973205959018'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/2695228973205959018'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2007/10/perl-fp-getting-abusers-from-my-mail.html' title='Perl FP : getting abusers from my mail logger one-liner'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-538571728008781426</id><published>2007-09-28T02:56:00.000-07:00</published><updated>2007-09-28T03:01:08.544-07:00</updated><title type='text'>Linux disk stuff - what brand drive do you have</title><content type='html'>I always forget commands I don't use daily; for instance, to get at least some idea about why, at one provider, more drives were breaking than at another provider, I needed the brand of the drivers. Ofcourse I cannot reach the servers physically, only via SSH. Searching Google didn't give me much on this, but after a long search in forums, I found it;&lt;br /&gt;&lt;br /&gt;apt-get install smartmontools&lt;br /&gt;&lt;br /&gt;box46:/disk1# smartctl --all /dev/sdc1&lt;br /&gt;smartctl version 5.36 [i686-pc-linux-gnu] Copyright (C) 2002-6 Bruce Allen&lt;br /&gt;Home page is http://smartmontools.sourceforge.net/&lt;br /&gt;&lt;br /&gt;Device: ATA      WDC WD2500YS-01S Version: 20.0&lt;br /&gt;Serial number:      WD-WCANY1884382&lt;br /&gt;Device type: disk&lt;br /&gt;Local Time is: Fri Sep 28 04:59:32 2007 CDT&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;And yes, Western Digital drives seem to break (much) more than Samsung and Hitachi for the same work + load.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-538571728008781426?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/538571728008781426'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/538571728008781426'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2007/09/linux-disk-stuff-what-brand-drive-do.html' title='Linux disk stuff - what brand drive do you have'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-3577317047308152104</id><published>2007-09-19T05:48:00.000-07:00</published><updated>2007-09-19T06:15:43.772-07:00</updated><title type='text'>register_globals Off is not the end of the world</title><content type='html'>We are getting continues remarks from our hosting users that 'they cannot work with register_globals Off'.&lt;br /&gt;&lt;br /&gt;Register_globals is a way to pass GET &amp; POST variables to a PHP script as normal PHP variables, for instance;&lt;br /&gt;&lt;br /&gt;test.php:&lt;br /&gt;&lt;?&lt;br /&gt; echo $test;&lt;br /&gt;?&gt;&lt;br /&gt;&lt;br /&gt;test.php?test=hello&lt;br /&gt;&lt;br /&gt;would result in &lt;br /&gt;&lt;br /&gt;hello&lt;br /&gt;&lt;br /&gt;when register_globals is On.&lt;br /&gt;&lt;br /&gt;A lot of (older) apps are built on this system as 'security' was not a problem before :) &lt;br /&gt;&lt;br /&gt;Thing is, this is not a security problem per-se, but it invites security issues; if you are not very careful you will introduce them. How? For instance (I actually found this in an open source app... I changed it here to match the same principle in a few lines); &lt;br /&gt;&lt;br /&gt;test1.php:&lt;br /&gt;&lt;?&lt;br /&gt; if (!$user) echo "please enter your username"; &lt;br /&gt; else include('test2.php');&lt;br /&gt;?&gt;&lt;br /&gt;&lt;br /&gt;test2.php:&lt;br /&gt;&lt;?&lt;br /&gt; if ($user) &lt;br /&gt;  mysql_query("select * from users where user = '$user'"); &lt;br /&gt;?&gt;&lt;br /&gt;&lt;br /&gt;A malicious user could now do the following;&lt;br /&gt;&lt;br /&gt;test2.php?user='; select * from users;'&lt;br /&gt;&lt;br /&gt;or something like that to get all users. &lt;br /&gt;&lt;br /&gt;So the preferred way is to make it a bit more difficult for developers so they have to actually think about what they are doing and what variables they are passing; the better way is;&lt;br /&gt;&lt;br /&gt;test.php:&lt;br /&gt;&lt;?&lt;br /&gt; echo $_GET['test'];&lt;br /&gt;?&gt;&lt;br /&gt;&lt;br /&gt;and &lt;br /&gt;&lt;br /&gt;test1.php:&lt;br /&gt;&lt;?&lt;br /&gt; $user = $_GET['user'];&lt;br /&gt; if (!$user) echo "please enter your username"; &lt;br /&gt; else include('test2.php');&lt;br /&gt;?&gt;&lt;br /&gt;&lt;br /&gt;test2.php:&lt;br /&gt;&lt;?&lt;br /&gt; if ($user) &lt;br /&gt;  mysql_query("select * from users where user = '$user'"); &lt;br /&gt;?&gt;&lt;br /&gt;&lt;br /&gt;executing test2.php as;&lt;br /&gt;&lt;br /&gt;test2.php?user='; select * from users;'&lt;br /&gt;&lt;br /&gt;would result in nothing as $user will be empty in test2.php.&lt;br /&gt;&lt;br /&gt;Anyway; programmers using 'the old way' suck. But to keep the users of your back, you can easily  help them by; a) educating them about the dangers b) telling them to rewrite the code. But most cannot or will not. And for them, you can give them this code and pray all will be fine;&lt;br /&gt;&lt;br /&gt;&lt;?&lt;br /&gt; foreach($_REQUEST as $k=&gt;$v) $$k=$v;&lt;br /&gt;?&gt;&lt;br /&gt;&lt;br /&gt;or;&lt;br /&gt;&lt;br /&gt;&lt;?&lt;br /&gt; foreach($_REQUEST as $k=&gt;$v) $$k=$v;&lt;br /&gt; foreach($_COOKIE as $k=&gt;$v) $$k=$v;&lt;br /&gt;?&gt;&lt;br /&gt;&lt;br /&gt;Putting this on top of all files (better is one generic header or include file, but even a lot of programs don't have that....). &lt;br /&gt;&lt;br /&gt;It will result in the same idea as register_globals On :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-3577317047308152104?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/3577317047308152104'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/3577317047308152104'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2007/09/registerglobals-off-is-not-end-of-world.html' title='register_globals Off is not the end of the world'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-3710896666953459636</id><published>2007-09-18T15:52:00.001-07:00</published><updated>2007-09-18T15:52:34.463-07:00</updated><title type='text'>New Site!</title><content type='html'>&lt;a href="http://www.movinglabs.com"&gt;Niceee....&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-3710896666953459636?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/3710896666953459636'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/3710896666953459636'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2007/09/new-site.html' title='New Site!'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-6987377240580233977</id><published>2007-09-18T15:43:00.000-07:00</published><updated>2007-11-05T09:15:53.784-08:00</updated><title type='text'>Combine MySQL databases ignoring keys</title><content type='html'>I would like to do something like this;&lt;br /&gt;&lt;br /&gt;on server1; mysqldump mysql &gt; db1.sql&lt;br /&gt;on server2; mysqldump mysql &gt; db2.sql&lt;br /&gt;&lt;br /&gt;on server3 (new server); &lt;br /&gt;&lt;br /&gt;mysql --force mysql &lt; db1.sql&lt;br /&gt;mysql --force mysql &lt; db2.sql&lt;br /&gt;&lt;br /&gt;which should give me db1.sql users root etc but it should combination of the users from db1 + db2, so for instance;&lt;br /&gt;&lt;br /&gt;db1.sql =&gt; users{root,a,b,c}&lt;br /&gt;db2.sql =&gt; users{root,a,d,e}&lt;br /&gt;&lt;br /&gt;on server3 I want to see;&lt;br /&gt;&lt;br /&gt;users{root,a,b,c,d,e}&lt;br /&gt;&lt;br /&gt;Ofcourse that doesn't work, as you get duplicate key messages on all double users. &lt;br /&gt;&lt;br /&gt;So ofcourse I wrote something to fix that; &lt;br /&gt;&lt;br /&gt;I first did;&lt;br /&gt;&lt;br /&gt;mysql mysql &lt; db1.sql&lt;br /&gt;mysql mysqlold &lt; db2.sql&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;PHP:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;?&lt;br /&gt; mysql_connect("localhost", "", ""); &lt;br /&gt; mysql_select_db("mysqlold");&lt;br /&gt; &lt;br /&gt; $q = mysql_query("select * from mysqlold.user");&lt;br /&gt; while ($r = mysql_fetch_row($q)) {&lt;br /&gt;  $q1 = mysql_query("select * from mysql.user where User='".$r[1]."'");&lt;br /&gt;  if (mysql_num_rows($q1)) {&lt;br /&gt;   continue;&lt;br /&gt;  }&lt;br /&gt;  $s="";&lt;br /&gt;  foreach($r as $r1) {&lt;br /&gt;   if ($s) $s.=",";&lt;br /&gt;   $s.="'".$r1."'";&lt;br /&gt;  }&lt;br /&gt;  $qry = "insert into mysql.user values ($s)";&lt;br /&gt;  mysql_query($qry);&lt;br /&gt; }&lt;br /&gt;?&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ofcourse, writing everything yourself was again much faster than searching the solution in the MySQL manual or on Google.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-6987377240580233977?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/6987377240580233977'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/6987377240580233977'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2007/09/combine-mysql-databases-ignoring-keys.html' title='Combine MySQL databases ignoring keys'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-114425022861140823</id><published>2006-04-05T08:12:00.000-07:00</published><updated>2006-04-05T08:17:08.626-07:00</updated><title type='text'>Online voting ... about anything !</title><content type='html'>There are a lot of URL voting applications on the web which have gained a very large audience, like www.digg.com and www.reddit.com. These systems are really nice, but the problem is that they are not meant to make you vote on anything else but URLs.&lt;br /&gt;&lt;br /&gt;Because of this, we created a generic voting application. Simply made to vote on anything. Favorite restaurant; put it in. Favorite movie; let' s have it. Favorite ... Whatever.&lt;br /&gt;&lt;br /&gt;A very nice and effective application this week for the &lt;a href="http://www.votelists.com"&gt;movinglabs&lt;/a&gt;; &lt;a href="http://www.votelists.com"&gt;votelists.com&lt;/a&gt; !&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-114425022861140823?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/114425022861140823'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/114425022861140823'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2006/04/online-voting-about-anything.html' title='Online voting ... about anything !'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-114371870627506341</id><published>2006-03-30T03:30:00.000-08:00</published><updated>2006-03-30T03:38:26.286-08:00</updated><title type='text'>And... Another *great* tool, the best so far... Sharepoint, eat your heart out (really, you should)</title><content type='html'>Our latest and greatest tool is including great and cool Web 2.0 AJAX technology and is a replacement for all that sad and boring Excel-with-list sending over the mail. How often do you get an Excel sheet in your mail with no calculations, but only an enumeration of some sort ?&lt;br /&gt;&lt;br /&gt;I get this daily; even yesterday one of my colleagues sent me an Excel with;&lt;br /&gt;&lt;br /&gt;index servername URL action comment&lt;br /&gt;&lt;br /&gt;He sent it to all people in the company (100) and asks if the responsible person for that site can please put some action in it and, if needed, some comment of what to do with this site/url.&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;A bit shocked I mailed back if we don't have Sharepoint for this and he replies; it is too much hassle to put it into SP and our SP will get a mess because of it.&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;So our new invention has it's merits. And we are using it already for everything.&lt;br /&gt;&lt;br /&gt;Without further blabla, I proudly present; &lt;a href="http://flexlists.com"&gt;flexlists.com&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Also some other things we did; &lt;a href="http://www.movinglabs.com"&gt;www.movinglabs.com&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;And I added very secure CLIENTSIDE encryption for &lt;a href="http://yourdraft.com"&gt;yourdraft.com&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-114371870627506341?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/114371870627506341'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/114371870627506341'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2006/03/and-another-great-tool-best-so-far.html' title='And... Another *great* tool, the best so far... Sharepoint, eat your heart out (really, you should)'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-114351561946131954</id><published>2006-03-27T18:50:00.000-08:00</published><updated>2006-03-27T19:13:39.480-08:00</updated><title type='text'>Making phpBB a bit more secure</title><content type='html'>I actually like phpBB. Why? Because it is mature and usually working perfectly for setting up a nice (looking) forum in a really short time. phpBB has a lot of 'security' problems. Usually these problems are not really problems that are in the forum software itself, but through it's massive use, the forum, if not propertly secured, is attacked by a lot of automated software on the internet.&lt;br /&gt;When I set up a forum for the first time, I usually allow anonymous posting. This is one of those 'security' things; anonymous posting makes it very easy for a robot to run over the internet, and post crap like viagra and casino links.&lt;br /&gt;&lt;br /&gt;To fix this, phpBB has an option to make only registered users post to a forum. This, however, is not working ok either, because the robots can register themselves and then post crap.&lt;br /&gt;&lt;br /&gt;Luckily the system has a way to 'secure' the registration process by adding a captcha to the forum registration form. This is, however, in the case of phpBB, &lt;a href="http://sam.zoy.org/pwntcha/"&gt;not safe&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;So what can you do? Just change the captcha algorithm by your own! And when it is &lt;a href="http://sam.zoy.org/pwntcha/"&gt;hacked&lt;/a&gt;,  just replace it again! At least the automated bots on the internet don't stand a chance this way.&lt;br /&gt;&lt;br /&gt;So here is a little howto for phpBB 2.x.&lt;br /&gt;&lt;br /&gt;Edit file includes/usercp_confirm.php ; go to the line before;&lt;br /&gt;&lt;br /&gt;if (@extension_loaded('zlib'))&lt;br /&gt;&lt;br /&gt;(line 67 in my version)&lt;br /&gt;&lt;br /&gt;and put&lt;br /&gt;&lt;br /&gt;exit;&lt;br /&gt;&lt;br /&gt;there.&lt;br /&gt;&lt;br /&gt;Before that, you will put your code.&lt;br /&gt;&lt;br /&gt;Now download the following captcha code, for instance:&lt;br /&gt;&lt;a href="http://www.ejeliot.com/pages/2"&gt;&lt;br /&gt;http://www.ejeliot.com/pages/2&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;and put it in your phpBB main directory.&lt;br /&gt;&lt;br /&gt;You are almost done now.&lt;br /&gt;&lt;br /&gt;Add the following above the 'exit' in includes/usercp_confirm.php;&lt;br /&gt;&lt;br /&gt; require('php-captcha.inc.php');&lt;br /&gt; $aFonts = array('/usr/share/fonts/truetype/ttf-bitstream-vera/Vera.ttf');&lt;br /&gt; $oPhpCaptcha = new PhpCaptcha($aFonts, 202, 43);&lt;br /&gt; $oPhpCaptcha-&gt;Create('', $code);&lt;br /&gt;&lt;br /&gt;Change this line;&lt;br /&gt;&lt;br /&gt; $aFonts = array('/usr/share/fonts/truetype/ttf-bitstream-vera/Vera.ttf');&lt;br /&gt;&lt;br /&gt;to a font (or more; it &lt;span style="font-weight: bold;"&gt;is&lt;/span&gt; an array ;) which actually exists on your system.&lt;br /&gt;&lt;br /&gt;Now this isn't working still, because&lt;br /&gt;&lt;br /&gt; $oPhpCaptcha-&gt;Create('', $code);&lt;br /&gt;&lt;br /&gt;does not exist; you need to edit the php-captcha code. Open the file php-captcha.inc.php and find the function 'GenerateCode'; change it as follows;&lt;br /&gt;&lt;br /&gt;function GenerateCode($generate=0) {&lt;br /&gt;// reset code&lt;br /&gt;         $this-&gt;sCode = '';&lt;br /&gt;&lt;br /&gt;         if (!$generate) {&lt;br /&gt;// leave original code here!         &lt;br /&gt;         } else $this-&gt;sCode = $generate;&lt;br /&gt;&lt;br /&gt;         // save code in session variable&lt;br /&gt;         if ($this-&gt;bCaseInsensitive) {&lt;br /&gt;            $_SESSION[CAPTCHA_SESSION_ID] = strtoupper($this-&gt;sCode);&lt;br /&gt;// etc; put original code here&lt;br /&gt;&lt;br /&gt;Now find the &lt;span style="font-style: italic;"&gt;first&lt;/span&gt; Create constructor (the second is of the sound captcha's!) and find the line;&lt;br /&gt;&lt;br /&gt;$this-&gt;GenerateCode();&lt;br /&gt;&lt;br /&gt;change this to:&lt;br /&gt;&lt;br /&gt;$this-&gt;GenerateCode($generate);&lt;br /&gt;&lt;br /&gt;Now the code will be working fine.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;If you need to debug, go to the registration page of your phpBB site;&lt;br /&gt;&lt;br /&gt;/profile.php?mode=register&amp;agreed=true&lt;br /&gt;&lt;br /&gt;open the HTML source and search for an img src attribute which contains;&lt;br /&gt;&lt;br /&gt;/profile.php?mode=confirm&amp;amp;id=&lt;br /&gt;&lt;br /&gt;open that in the browser and you'll see why something is not working.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-114351561946131954?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/114351561946131954'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/114351561946131954'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2006/03/making-phpbb-bit-more-secure.html' title='Making phpBB a bit more secure'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-114295738756966852</id><published>2006-03-21T08:03:00.000-08:00</published><updated>2006-03-21T08:09:47.590-08:00</updated><title type='text'>The next tiny tool!</title><content type='html'>As promised...&lt;br /&gt;&lt;br /&gt;Not even a week further, the next tool has been released; &lt;a href="http://www.yourdraft.com"&gt;yourdraft.com&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The tools fills a small gap in my webtool repository; a simple and no-nonsense site for putting drafts of documents and files without having to concern myself with irritating account information and so forth.&lt;br /&gt;&lt;br /&gt;The editing is quite smooth and simple; you just start typing and all information will be stored for later viewing. No passwords etc to remember. It is not really secure, but it was not meant to be; you can work together on a document or show someone something for a short period and then  remove it again.&lt;br /&gt;&lt;br /&gt;Number three of our tools will be a bit more elaborate; it will fill a gap which, to date, was not filled by anything worth-while.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-114295738756966852?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/114295738756966852'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/114295738756966852'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2006/03/next-tiny-tool.html' title='The next tiny tool!'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-114263575882497567</id><published>2006-03-17T14:44:00.000-08:00</published><updated>2006-03-17T14:51:43.356-08:00</updated><title type='text'>Creating MySQL databases securely</title><content type='html'>When building sites I often need to set-up a MySQL database which has all proper settings so I can start working right  away knowing that all is fine. Here is a little script which I use to do this;&lt;br /&gt;&lt;br /&gt;#!/bin/sh&lt;br /&gt;&lt;br /&gt;if [ ! -n "$1" ]; then&lt;br /&gt;echo "Invoke as ./createdb.sh DATABASE_NAME"&lt;br /&gt;exit -1&lt;br /&gt;fi&lt;br /&gt;&lt;br /&gt;DBNAME="$1"&lt;br /&gt;&lt;br /&gt;mysqladmin --user=root --password=SOMEPASS create $DBNAME&lt;br /&gt;&lt;br /&gt;PASS=`perl -e 'for($i=0;$i&lt;6;$i++){print rand()*26%26};'`&lt;br /&gt;mysql --user=root --password=SOMEPASS -e "grant all privileges on $DBNAME.* to $DBNAME@'localhost' identified by '$PASS';"&lt;br /&gt;mysql --user=root --password=SOMEPASS -e "flush privileges;"&lt;br /&gt;&lt;br /&gt;echo $PASS&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-114263575882497567?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/114263575882497567'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/114263575882497567'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2006/03/creating-mysql-databases-securely.html' title='Creating MySQL databases securely'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-114249366285254907</id><published>2006-03-15T23:11:00.000-08:00</published><updated>2006-03-17T12:53:50.350-08:00</updated><title type='text'>Software writing  in the fast lane</title><content type='html'>I am often searching the internet for handy programs  and tools. Unfortunately, the never have anything I need or I cannot find it (which means, they did not market it properly ofcourse ;).&lt;br /&gt;&lt;br /&gt;Usually I do some brainstorming with a friend about this kind of thing and then we think about  building this tool ourself if we don't like the existing ones or if we cannot find any. Our conversation usually go a bit like this;&lt;br /&gt;&lt;br /&gt;me; would it not be nice to have X&lt;br /&gt;he; yes that would be excellent, it would have features a,b,c&lt;br /&gt;me; and ofcourse d,e,f,g,h&lt;br /&gt;he; and it would certainly need i,j,k,l,m&lt;br /&gt;me; right! that's the least it should have&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;After about 30 minutes in this kind of talk, we both conclude that we need a rapid web application development environment and that X is just a subset of that environment.&lt;br /&gt;&lt;br /&gt;Needless to say; we don't have time, resources or even energy to start with the production of an RWADE...&lt;br /&gt;&lt;br /&gt;We decided, after years of those kind of pointless sessions, to do the following; we will think of something which can be built, from concept to live application on the web, in less than 24 hours.&lt;br /&gt;This forces it to be makeable and it cannot be an RWADE ;) We decided to release such a 'nice little tool' every week.&lt;br /&gt;&lt;br /&gt;The first we have is &lt;a href="http://www.forlater.net"&gt;forlater.net&lt;/a&gt;.  A very simple tool (take a look) which was built in about 4 hours from concept to the site you see online.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-114249366285254907?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/114249366285254907'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/114249366285254907'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2006/03/software-writing-in-fast-lane.html' title='Software writing  in the fast lane'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-113967069162027344</id><published>2006-02-11T07:06:00.000-08:00</published><updated>2006-02-11T07:11:31.640-08:00</updated><title type='text'>Hiding affiliate urls</title><content type='html'>Let's say you are a webmaster into a few affiliate programs. You will have URLs which will look like;&lt;br /&gt;&lt;br /&gt;http://www.somesite.com/?id=xyz&lt;br /&gt;&lt;br /&gt;or&lt;br /&gt;&lt;br /&gt;http://www.somesite.com/affiliate/xyz&lt;br /&gt;&lt;br /&gt;or something like that.&lt;br /&gt;&lt;br /&gt;The best way of getting visitors to not go directly to the site is making them believe (and the searchengines for that matter), that you are not an affiliate but that it is your site.&lt;br /&gt;&lt;br /&gt;You do this by registering a domain and then using mod_rewrite in Apache:&lt;br /&gt;&lt;br /&gt;Let's say we registered www.someothersite.com and you want to rewrite, without users be able to see, this url to http://www.somesite.com/?id=xyz, you should set, in Apache;&lt;br /&gt;&lt;br /&gt;&lt;virtualhost&gt;&lt;br /&gt;        ServerName www.someothersite.com&lt;br /&gt;        RewriteEngine On&lt;br /&gt;        RewriteRule (.*) http://www.somesite.com/$1?id=xyz [P]&lt;br /&gt;&lt;/virtualhost&gt;&lt;br /&gt;&lt;br /&gt;No-one will be able to see the id in the URL without using frames, iframes etc.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-113967069162027344?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/113967069162027344'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/113967069162027344'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2006/02/hiding-affiliate-urls.html' title='Hiding affiliate urls'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-113879505376969743</id><published>2006-02-01T03:48:00.000-08:00</published><updated>2006-02-01T03:59:57.676-08:00</updated><title type='text'>Apache + Webdav + LDAP + Debian</title><content type='html'>Getting those to work is not that difficult, but a LOT of site keep nagging about using:&lt;br /&gt;&lt;br /&gt;LDAP_Server&lt;br /&gt;&lt;br /&gt;You will get something like:&lt;br /&gt;&lt;br /&gt;Invalid command 'LDAP_Server'&lt;br /&gt;&lt;br /&gt;Prerequisites are:&lt;br /&gt;&lt;br /&gt;- Apache 2 under Debian&lt;br /&gt;- Installed and working (open)LDAP&lt;br /&gt;&lt;br /&gt;Something like; apt-get install apache2&lt;br /&gt;&lt;br /&gt;Symbolic link the dav_load in mods-available/ to mods-enabled/. Do the same with auth_ldap.load and dav_fs.conf and dav_fs.load.&lt;br /&gt;&lt;br /&gt;Then add the following to apache2.conf:&lt;br /&gt;&lt;br /&gt;Listen 666&lt;br /&gt;&amp;lt;VirtualHost *:666&gt;&lt;br /&gt;DAVLockDB /var/lib/dav/lockdb&lt;br /&gt;&lt;br /&gt;Alias /share /home/share&lt;br /&gt;&lt;br /&gt;&amp;lt;Location "/share"&gt;&lt;br /&gt; Options Indexes FollowSymLinks&lt;br /&gt; AllowOverride None&lt;br /&gt; order allow,deny&lt;br /&gt; allow from all&lt;br /&gt;&lt;br /&gt; DAV On&lt;br /&gt; AuthType Basic&lt;br /&gt;&lt;br /&gt; AuthLDAPBindDN cn=admin,dc=mydomain,dc=com&lt;br /&gt; AuthLDAPBindPassword SOMEPASS&lt;br /&gt; AuthLDAPURL ldap://127.0.0.1/ou=People,dc=mydomain,dc=com?uid?sub?(objectClass=*)&lt;br /&gt;&lt;br /&gt; AuthName "Repository  Access"&lt;br /&gt; Require valid-user&lt;br /&gt;&amp;lt;/Location&gt;&lt;br /&gt;&amp;lt;/VirtualHost&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/home/share&lt;br /&gt;&lt;br /&gt;will be shared now under;&lt;br /&gt;&lt;br /&gt;http://somedomain/share&lt;br /&gt;&lt;br /&gt;You can use SSL by putting:&lt;br /&gt;&lt;br /&gt;SSLEngine On&lt;br /&gt;&lt;br /&gt;in the &amp;lt;Location&gt; directive.&lt;br /&gt;&lt;br /&gt;I had a problem that I also use Samba and SCP for access on the same system, meaning that there could be a potential sharing access problem; everything must be written with group user and then made 770 directory/file mask.&lt;br /&gt;To fix this, put in /etc/init.d/apache2&lt;br /&gt;&lt;br /&gt;umask 0007&lt;br /&gt;&lt;br /&gt;somewhere at the start and restart Apache. It will work..&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-113879505376969743?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/113879505376969743'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/113879505376969743'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2006/02/apache-webdav-ldap-debian.html' title='Apache + Webdav + LDAP + Debian'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-113874076096101374</id><published>2006-01-31T12:43:00.000-08:00</published><updated>2006-01-31T12:52:40.976-08:00</updated><title type='text'>Installing LDAP on Debian</title><content type='html'>&lt;span style="font-family: arial;"&gt;Installing LDAP is not that simple. Some basic LDAP knowledge is needed, but for setting up quickly do;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: arial;"&gt;apt-get install slapd ldap-utils migrationtools&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: arial;"&gt;Answer all questions; make sure you enter for the first to screens (DN and org) the same name, for instance domain.com. You don't have to do this, but if you don't know anything about LDAP this is advisable, because you'll get errors like; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: arial;"&gt;ldap_bind: Invalid credentials&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: arial;"&gt;Now you can add your /etc/passwd users by migrating them with:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: arial;"&gt;cd /usr/share/migrationtools&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: arial;"&gt;./migrate_passwd.pl /etc/passwd /tmp/passwd.ldif&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: arial;"&gt;When importing these like:&lt;br /&gt;&lt;br /&gt;ldapadd -x -v -D cn=admin,dc=domain,dc=com  -w YOURPASSWORD &lt; /tmp/passwd.ldif&lt;br /&gt;&lt;br /&gt;You'll probably get some error like:&lt;br /&gt;&lt;br /&gt;parent does not exist&lt;br /&gt;&lt;br /&gt;Because your passwd.ldif contains:&lt;br /&gt;&lt;br /&gt;ou: Groups&lt;br /&gt;&lt;br /&gt;If you want to know why, you should look at an organizational schema of LDAP, but if you don't care, just make an ldif file like:&lt;br /&gt;&lt;br /&gt;dn: ou=People,dc=domain,dc=com&lt;br /&gt;ou: People&lt;br /&gt;objectClass: organizationalUnit&lt;br /&gt;&lt;br /&gt;And add it;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: arial;"&gt;ldapadd -x -v -D cn=admin,dc=domain,dc=com  -w YOURPASSWORD &lt; /tmp/ou.ldif&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Now add the passwd.diff&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: arial;"&gt;ldapadd -x -v -D cn=admin,dc=domain,dc=com  -w YOURPASSWORD &lt; /tmp/passwd.ldif&lt;br /&gt;&lt;br /&gt;and check if all went ok;&lt;br /&gt;&lt;br /&gt;/usr/bin/ldapsearch -x -p 389 -h localhost -w YOURPASSWD -D 'cn=admin,dc=componence,dc=com' objectClass=*&lt;br /&gt;&lt;br /&gt;It should show all you added and set.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: monospace;"&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-113874076096101374?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/113874076096101374'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/113874076096101374'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2006/01/installing-ldap-on-debian.html' title='Installing LDAP on Debian'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-113845989367398639</id><published>2006-01-28T06:46:00.000-08:00</published><updated>2006-01-28T07:18:37.156-08:00</updated><title type='text'>Waiting for all threads to end in Java</title><content type='html'>Looking in Google for some easy out-of-the-box way for waiting for all threads to end and then continue the main() (or something) method, I found that no simple way was indicated anywhere. Use thread.join(). Yeah sure, only problem is that I have multiple threads and I want all of them to run and time the running time.&lt;br /&gt;&lt;br /&gt;For example: I have 4 threads:&lt;br /&gt;&lt;br /&gt;Thread t1,t2,t3,t4;&lt;br /&gt;&lt;br /&gt;which I run from a main() method in a Java class. The main method looks like this:&lt;br /&gt;&lt;br /&gt;public void main(String[] args) {&lt;br /&gt;... some stuff before&lt;br /&gt;&lt;br /&gt;// first run&lt;br /&gt;t1.start();&lt;br /&gt;t2.start();&lt;br /&gt;t3. start();&lt;br /&gt;t4.start();&lt;br /&gt;&lt;br /&gt;// second run&lt;br /&gt;t1.start();&lt;br /&gt;t2.start();&lt;br /&gt;t3. start();&lt;br /&gt;t4.start();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;Now I want to not start the second run before the first is over. A way to do this, is by running:&lt;br /&gt;&lt;br /&gt;public void main(String[] args) {&lt;br /&gt;... some stuff before&lt;br /&gt;&lt;br /&gt;// first run&lt;br /&gt;t1.start();&lt;br /&gt;t2.start();&lt;br /&gt;t3. start();&lt;br /&gt;t4.start();&lt;br /&gt;&lt;br /&gt;// wait till all of these are done&lt;br /&gt;t1.join();&lt;br /&gt;t2.join();&lt;br /&gt;t3. join();&lt;br /&gt;t4.join();&lt;br /&gt;... etc&lt;br /&gt;&lt;br /&gt;For this trivial case, this is ok, but in the real program I am writing, a lot of threads are started, for instance from classes.methods all over the place, making keeping references to them for joining quite a challenge.&lt;br /&gt;&lt;br /&gt;Anyway; Google did not indicate to me a straight, simple and generic way of doing it, so I did the following:&lt;br /&gt;&lt;br /&gt;class ThreadCheck extends Thread {&lt;br /&gt;    List&lt;thread&gt; l = new ArrayList&lt;thread&gt;();&lt;br /&gt;&lt;br /&gt;    public void queueThread(Thread t) {&lt;br /&gt;        l.add(t);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;   public void run() {&lt;br /&gt;           for (int i=0;i&amp;lt;l.size();i++) {&lt;br /&gt;               try {&lt;br /&gt;                   l.get(i).join();&lt;br /&gt;               } catch (Exception e) {&lt;br /&gt;                   e.printStackTrace();&lt;br /&gt;               }&lt;br /&gt;           }&lt;br /&gt;       }&lt;br /&gt;&lt;br /&gt;Now you can add your Threads to the object;&lt;br /&gt;&lt;br /&gt;tc=ThreadCheck();&lt;br /&gt;t1.start();&lt;br /&gt;tc.queueThread(t1);&lt;br /&gt;&lt;/thread&gt;&lt;/thread&gt;t2.start();&lt;br /&gt;tc.queueThread(t2);&lt;br /&gt;etc&lt;br /&gt;&lt;br /&gt;I usually pass tc to the the Thread when creating it, so it can queue itself after it is started; this makes it even easier, because you don't need any references to the threads after creation.&lt;br /&gt;&lt;thread&gt;&lt;thread&gt;&lt;br /&gt;Then you can start the tc;&lt;br /&gt;&lt;br /&gt;tc.start();&lt;br /&gt;&lt;br /&gt;and make sure all ends only when all threads are done:&lt;br /&gt;&lt;br /&gt;tc.join();&lt;br /&gt;&lt;br /&gt;To time the execution:&lt;br /&gt;&lt;br /&gt;&lt;/thread&gt;&lt;/thread&gt;long st= System.currentTimeMillis();&lt;br /&gt;&lt;thread&gt;&lt;thread&gt;i&lt;l.size();i++) try="" join="" catch="" exception="" e="" printstacktrace="" i=""&gt;&lt;l.size();i++) try="" catch="" exception="" e="" printstacktrace="" after="" this="" add="" your="" threads="" object="" tc="ThreadCheck();" t1="" t2="" t3="" t4="" and="" then="" to="" make="" sure="" current="" class="" will="" wait="" for="" all="" of="" these="" start="" join="" you="" can="" time="" execution="" with="" the="" following="" code="" long="" st="System.currentTimeMillis();"&gt;&lt;thread&gt;&lt;thread&gt;&lt;thread&gt;&lt;thread&gt;&lt;l.size();i++) try="" catch="" exception="" e="" printstacktrace="" before="" any="" create="" a="" object="" tc="new" threadcheck="" now="" in="" method="" some="" thread="" put="" public="" void="" true="" something="" this="" after="" your="" are="" started="" simply="" run="" start="" join="" you="" can="" time="" the="" running="" of="" all="" threads="" by="" adding="" long="" st="System.currentTimeMillis();"&gt;&lt;/l.size();i++)&gt;&lt;/thread&gt;tc.start(); tc.join();&lt;br /&gt;long et= System.currentTimeMillis()-st;&lt;br /&gt;System.out.println("Stuff ran for "+et+" milliseconds");&lt;br /&gt;&lt;br /&gt;The above method works very well, but if anyone knows a better method, please mail me!&lt;/thread&gt;&lt;/thread&gt;&lt;/thread&gt;&lt;/l.size();i++)&gt;&lt;/l.size();i++)&gt;&lt;/thread&gt;&lt;/thread&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-113845989367398639?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/113845989367398639'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/113845989367398639'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2006/01/waiting-for-all-threads-to-end-in-java.html' title='Waiting for all threads to end in Java'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-113633595265711826</id><published>2006-01-03T16:46:00.000-08:00</published><updated>2006-01-03T16:59:03.830-08:00</updated><title type='text'>Catching Post Redirects with HttpClient</title><content type='html'>For some very good reasons, RFC 2616 and HttpClient do not allow automatic POST redirects. A good reason, but irritating it is nontheless.&lt;br /&gt;I had to get around it today for a bunch of cases which are clear and very common; the case where a POST continues into a GET. For instance; you entered a login/password and are redirected to another page when it is right/wrong without the need for the POST info to be posted to that page also.&lt;br /&gt;&lt;br /&gt;The following code has been written for a simple proxy server, so everything is passed to the response;&lt;br /&gt;&lt;br /&gt;First of all, you need to know if there is a redirect going on;&lt;br /&gt;&lt;br /&gt;method is a PostMethod, request is the HttpServletRequest, response is the HttpServletResponse;&lt;br /&gt;&lt;br /&gt;if (request.getMethod().equals("POST") &amp;&amp;amp; method.getResponseHeader("location")!=null) {&lt;br /&gt;&lt;br /&gt;Then you don't need the current method anymore, because you are redirecting;&lt;br /&gt;&lt;br /&gt;method.releaseConnection();&lt;br /&gt;&lt;br /&gt;Get the location to redirect to;&lt;br /&gt;&lt;br /&gt;String location = method.getResponseHeader("location").getValue();&lt;br /&gt;           &lt;br /&gt;And make a new GetMethod:&lt;br /&gt;&lt;br /&gt;method = new GetMethod(dst+'/'+location);&lt;br /&gt;&lt;br /&gt;dst is the destination domain which you know ofcourse, because you cannot use HttpClient without it.&lt;br /&gt;&lt;br /&gt;Run the method;&lt;br /&gt;&lt;br /&gt;statusCode = client.executeMethod(method);&lt;br /&gt;&lt;br /&gt;Make sure the response knows that this is another URL: you can experiment with this to show &lt;span style="font-weight: bold;"&gt;any&lt;/span&gt; URL in the browser of the client:&lt;br /&gt;&lt;br /&gt;response.setStatus(HttpStatus.SC_MOVED_TEMPORARILY);&lt;br /&gt;response.setHeader("Location", location);&lt;br /&gt;&lt;br /&gt;This works fine for the cases I tried like logging in and filling forms.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-113633595265711826?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/113633595265711826'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/113633595265711826'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2006/01/catching-post-redirects-with.html' title='Catching Post Redirects with HttpClient'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-113602533974211280</id><published>2005-12-31T02:26:00.000-08:00</published><updated>2005-12-31T09:30:19.433-08:00</updated><title type='text'>Windows XP and Samba connections</title><content type='html'>When working for a long time with XP without resetting (yep, that's error number one right there), my laptop, when taken from location A to location B and back to A seems to be unable to connect to some Samba(SMB) resources protected with a password. Windows reports that my credentials (username/password) are incorrect while they are not.&lt;br /&gt;&lt;br /&gt;I haven't been able to find out what causes this, but I have found how to work around this without resetting. It was quite trivial actually, but when talking to other people they would simply comment; 'just reboot, all will be fine'. This is not ok with me, because I use hibernate on my laptop so I don't have to wait to reboot Windows, which is still very very slow. Usually after a few days of hibernations, Windows starts to break; it doesn't work properly anymore; windows don't open/close, networking problems like described here today etc. I usually first kill explorer.exe with taskmgr and then restart it, if that doesn't work I log off and on (still takes a lot less than rebooting completely). This usually does the trick, except for the samba problem...&lt;br /&gt;&lt;br /&gt;To see if you have the problem; just type a resource into explorer, for instance;&lt;br /&gt;&lt;br /&gt;\\10.0.0.13\store&lt;br /&gt;&lt;br /&gt;in my case.&lt;br /&gt;&lt;br /&gt;It will be stuck for a while and then tell you you don't have enough rights on the resource and to contact your admin.&lt;br /&gt;&lt;br /&gt;Open a cmd prompt (left-windows-r + cmd + enter) and type:&lt;br /&gt;&lt;br /&gt;net use&lt;br /&gt;&lt;br /&gt;You will see the connection you are trying to open in the list, frustratingly enough probably with a status  'OK' (no it isn't you cannot open it you piece of ()*%#@%**)#@).&lt;br /&gt;&lt;br /&gt;Then type:&lt;br /&gt;&lt;br /&gt;net use \\10.0.0.13\store /delete&lt;br /&gt;&lt;br /&gt;And then try to open the connection again. It'll work now.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-113602533974211280?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/113602533974211280'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/113602533974211280'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2005/12/windows-xp-and-samba-connections.html' title='Windows XP and Samba connections'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-113595450369183622</id><published>2005-12-30T06:34:00.000-08:00</published><updated>2005-12-30T06:57:55.706-08:00</updated><title type='text'>Moving servers without changing of IPs. No hassle migrations by proxy.</title><content type='html'>Ever had to move a bunch of servers (in our case about 30) to another location in a hurry? Every wondered if it would be easy to give your clients the same ip address before and after the migration, at least for a little while until they have their DNS's updated?&lt;br /&gt;&lt;br /&gt;Well, it is easy in fact. How? By using a neat little program called &lt;a href="http://freshmeat.net/redir/tcpproxy/50603/url_homepage/tcpproxy.yawk"&gt;tcpproxy&lt;/a&gt;. This is actually all you need. You simply wip up a config file;&lt;br /&gt;&lt;br /&gt;/etc/tcpproxy.conf&lt;br /&gt;&lt;br /&gt;port 22&lt;br /&gt;# old ip&lt;br /&gt;interfaces 192.168.0.1&lt;br /&gt;# new ip&lt;br /&gt; server 192.168.1.1&lt;br /&gt;&lt;br /&gt;and run ./tcpproxy&lt;br /&gt;&lt;br /&gt;Two servers are moved in need of port 22? Simple, just do:&lt;br /&gt;&lt;br /&gt;port 22&lt;br /&gt;# old ip&lt;br /&gt;interfaces 192.168.0.1&lt;br /&gt;# new ip&lt;br /&gt; server 192.168.1.1&lt;br /&gt;# old ip&lt;br /&gt; interfaces 192.168.0.2&lt;br /&gt;# new ip&lt;br /&gt;  server 192.168.1.2&lt;br /&gt;&lt;br /&gt;etc.&lt;br /&gt;&lt;br /&gt;After entering a bunch of servers like this (up to thirty in our case, with every servers having bunches of open ports), you get a bit tired of this format. So let's get our trusty Perl working this for us.&lt;br /&gt;&lt;br /&gt;Personally I like configuration formats which are clear, simple and fast. So I wipped up the following format:&lt;br /&gt;&lt;br /&gt;servername:oldip:newip:ports&lt;br /&gt;&lt;br /&gt;for example:&lt;br /&gt;&lt;br /&gt;killer:34:138:22,80,81,8080&lt;br /&gt;&lt;br /&gt;and another one:&lt;br /&gt;&lt;br /&gt;killer:34:138:22,80,81,8080&lt;br /&gt;killer2:35:139:22,80,81,143,993&lt;br /&gt;&lt;br /&gt;etc.&lt;br /&gt;&lt;br /&gt;As you might notice (I hope); the ip address is not complete; in our case, we move from one network to another in which the first 3 numbers in the ip address are the same. For instance:&lt;br /&gt;&lt;br /&gt;Before IP: 192.168.0.*&lt;br /&gt;After IP: 192.168.1.*&lt;br /&gt;&lt;br /&gt;The script I made to read in the configuration file should have some configuration settings:&lt;br /&gt;&lt;br /&gt;# settings&lt;br /&gt;$oldr = "192.168.0"; # old ip address range&lt;br /&gt;$newr = "192.168.1"; # new ip address range&lt;br /&gt;$eth = "eth0"; # ethernet card to make aliases for&lt;br /&gt;&lt;br /&gt;An observant reader might notice that I added the ethernet card; this is because we want to use one machine for the forwarding, not as many machines as there were before :) Also we would want the settings for this forwarding machine to be auto-generated. For the above case, we need to have:&lt;br /&gt;&lt;br /&gt;ifconfig eth0:0 192.168.0.1 up&lt;br /&gt;ifconfig eth0:1 192.168.0.2 up&lt;br /&gt;&lt;br /&gt;To make tcpproxy to be able to listen to incoming requests on those addresses.&lt;br /&gt;&lt;br /&gt;In case there already are alias interfaces on $eth, we need to figure out what they are, so we can decide where to start counting new aliases:&lt;br /&gt;&lt;br /&gt;# calc interface start&lt;br /&gt;$count = `ifconfig|grep $eth|tail -n 1|awk '{print \$1}'|grep :|sed -e s/$eth\://`;&lt;br /&gt;if ($count eq "") {&lt;br /&gt;$count = 0;&lt;br /&gt;} else {&lt;br /&gt;$count++;&lt;br /&gt;}&lt;br /&gt;$first = $count;&lt;br /&gt;&lt;br /&gt;Next step is to generate all the settings for the /etc/tcpproxy.conf file and to generate a set and unset interface file for you to run to get the computer in the proper mode to listen to all incoming requests:&lt;br /&gt;&lt;br /&gt;open(F, $f);&lt;br /&gt;open(SET, "&gt; ./set$eth.sh");&lt;br /&gt;open(UNSET, "&gt; ./unset$eth.sh");&lt;br /&gt;print SET "#!/bin/sh\n";&lt;br /&gt;print UNSET "#!/bin/sh\n";&lt;br /&gt;while(&lt;f&gt;) {&lt;br /&gt;chomp;&lt;br /&gt;next if /^$/;&lt;br /&gt;($umln,$ipo,$ipn,$pts) = split(/:/);&lt;br /&gt;print SET "# $umln\nifconfig $eth:$count $oldr.$ipo up\n";&lt;br /&gt;print UNSET "# $umln\nifconfig $eth:$count down\n" if $count == $first;&lt;br /&gt;$count++;&lt;br /&gt;foreach(split(/,/,$pts)) {&lt;br /&gt; $port{$_}.="# $umln\n";&lt;br /&gt; $port{$_}.=" interface $oldr.$ipo\n";&lt;br /&gt; $port{$_}.="  server $newr.$ipn\n";&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;close F;&lt;br /&gt;close SET;&lt;br /&gt;close UNSET;&lt;br /&gt;&lt;br /&gt;We cannot write the tcpproxy.conf as we go along, because it is only allowed to have one&lt;br /&gt;&lt;br /&gt;port X&lt;br /&gt;&lt;br /&gt;per set of interfaces and servers. In the above code we collected all ports with their interfaces settings, contained in $port.&lt;br /&gt;&lt;br /&gt;We only have to put these into a nice string which is, in fact, the /etc/tcpproxy.conf file; we leave the saving of it to the reader. For fun it is nicely sorted by port :)&lt;br /&gt;&lt;br /&gt;foreach(sort {$a &lt;=&gt; $b} keys %port) {&lt;br /&gt; $tot .= "port $_\n";&lt;br /&gt; $tot .= $port{$_};&lt;br /&gt; $tot .= "\n";&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;Have fun!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/f&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-113595450369183622?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/113595450369183622'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/113595450369183622'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2005/12/moving-servers-without-changing-of-ips.html' title='Moving servers without changing of IPs. No hassle migrations by proxy.'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-112966713905687227</id><published>2005-10-18T13:18:00.000-07:00</published><updated>2005-10-18T13:25:39.063-07:00</updated><title type='text'>Ok, so maybe you should store everything in gmail...</title><content type='html'>I lately have been contemplating putting all my mails and some other content into Gmail. Why? Because Google is ofcourse a great searchengine, I don't give a ... about them 'invading my privacy' (running some statistical crap over mails to show some non-intrusive ads) and I find the AJAX client great.&lt;br /&gt;&lt;br /&gt;So... I decided to take the step and send all my mail to both my Cyrus IMAP server and Gmail. I migrated all my IMAP mail (hundreds of thousands of mails) to Gmail using;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;/code&gt;find . -type f -maxdepth 1 -name "*?." -printf "%T@ %h/%f\\n" |sort -n |colrm 1 11 |xargs -i bash -c "echo {} ; sendmail &lt; {} myaddress@gmail.com ; sleep 2"&lt;br /&gt;&lt;br /&gt;(which I found on some webpage which I forgot)&lt;br /&gt;&lt;br /&gt;It 'migrates' one folder at a time ; you need access to the linux system on which the IMAP server (must be Cyrus!) resides.&lt;br /&gt;&lt;br /&gt;I will put my experiences here soon.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-112966713905687227?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/112966713905687227'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/112966713905687227'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2005/10/ok-so-maybe-you-should-store.html' title='Ok, so maybe you should store everything in gmail...'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-112824104360197832</id><published>2005-10-02T01:10:00.000-07:00</published><updated>2005-12-13T11:48:45.456-08:00</updated><title type='text'>Ripping DVDs with Linux</title><content type='html'>Under Windows I never could rip DVDs in a working fashion; I have, under my XP Prof installation, about 40 tools installed which all promise easy ripping, but none of them work. You can rip the VOBs, but then they have wrong language, wrong subtitles and ofcourse they are 4+ gb big. When trying to make 'ok VOB rips' into AVI's or MPG's I tried integrated tools or non-integrated tools; both had the same effect; it didn't work. After hours of 'transcoding' there would be a file 'bla.avi', which would be, in reality complete crap.&lt;br /&gt;&lt;br /&gt;Under Linux, I hoped, things might be better. At first, this appeared not the be the case ; I have been, for hours, muttering around with dvdrip which wouldn't compile (well, GTK-Perl wouldn't). This is probably because of that bastard x86_64 architecture of mine.&lt;br /&gt;&lt;br /&gt;Anyway; it seemed that mplayer has native support of ripping dvds :) And ofcourse, mplayer rocks!&lt;br /&gt;&lt;br /&gt;So, how-to very easily rip dvds with mplayer:&lt;br /&gt;&lt;br /&gt;- get mplayer source (from http://mplayerhq.hu)&lt;br /&gt;- try ./configure&lt;br /&gt;- if you have gcc 4 installed, configure will whine about that it cannot continue; you can switch off the check for gcc; don't, because with gcc 4, mplayer won't compile; instead, install compat-gcc-32 and run ./configure --cc=gcc32&lt;br /&gt;- after compilation, there are two binaries; mplayer and mencoder&lt;br /&gt;- to check out what you want to rip with which language and which subtitles (if any), use;&lt;br /&gt;&lt;br /&gt;mplayer dvd://NUMBER -alang LANG -slang LANG&lt;br /&gt;&lt;br /&gt;For instance (for english and track 1);&lt;br /&gt;&lt;br /&gt;mplayer dvd://1 -alang en -slang en&lt;br /&gt;&lt;br /&gt;You will see something like this;&lt;br /&gt;&lt;br /&gt;There are 22 titles on this DVD.&lt;br /&gt;There are 37 chapters in this DVD title.&lt;br /&gt;There are 1 angles in this DVD title.&lt;br /&gt;DVD successfully opened.&lt;br /&gt;Selected DVD audio channel: 128 language: en&lt;br /&gt;Selected DVD subtitle channel: 0 language: en&lt;br /&gt;&lt;br /&gt;- repeat the previous step until you have exactly what you want to rip&lt;br /&gt;- to start ripping, use the following command:&lt;br /&gt;&lt;br /&gt;./mencoder dvd://4 -alang en -slang en -ovc lavc -oac lavc -o test.avi&lt;br /&gt;&lt;br /&gt;You can set the aspect ratio, I always use;&lt;br /&gt;&lt;br /&gt;./mencoder dvd://4 -aspect 16:9 -alang en -slang en -ovc lavc -oac lavc -o test.avi&lt;br /&gt;&lt;br /&gt;If you don't include it, your movie might appear 'squared' and when playing fullscreen, this is not that nice :)&lt;br /&gt;&lt;br /&gt;- the above won't rip the subtitles though; you need to use the following to get the actual subtitles;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;./mencoder dvd://4 -aspect 16:9-alang en -slang en -ovc lavc -oac lavc -vobsubout subtitles -vobsuboutindex 0 -sid 0 -o test.avi &lt;/pre&gt;&lt;br /&gt;where the vobsuboutindex and sid numbers are the number you saw when playing the movie with mplayer here;&lt;br /&gt;&lt;br /&gt;Selected DVD subtitle channel: 0 language: en&lt;br /&gt;&lt;br /&gt;- when finished ripping, you can play the movie with:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;mplayer test.avi -vobsub subtitles&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt; That's all !&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-112824104360197832?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/112824104360197832'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/112824104360197832'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2005/10/ripping-dvds-with-linux.html' title='Ripping DVDs with Linux'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-112715988849386458</id><published>2005-09-19T12:55:00.000-07:00</published><updated>2005-09-20T04:29:13.773-07:00</updated><title type='text'>Installing FC4 on an Acer Ferrari 3400</title><content type='html'>Installing FC4 went even better than installing FC3; you also need to start with&lt;br /&gt;&lt;br /&gt;linux nofb&lt;br /&gt;&lt;br /&gt;to make sure you are seeing anything during startup. The rest is straightforward; you need&lt;br /&gt;to select a 1400x1050 Generic LCD screen to get the best resolution going. Further everything&lt;br /&gt;will go fine.&lt;br /&gt;&lt;br /&gt;Except the wireless ofcourse.&lt;br /&gt;&lt;br /&gt;To get it running, you need ndiswrapper with the 64 bit Windows driver for the Broadcom card.&lt;br /&gt;&lt;br /&gt;Search for: 64-bit_Broadcom_54g_Drivers.zip on google to find the right drivers and download the ndiswrapper from the sourceforge.net site.&lt;br /&gt;&lt;br /&gt;Unpack the ndiswrapper package and build it:&lt;br /&gt;&lt;br /&gt;make&lt;br /&gt;make install&lt;br /&gt;&lt;br /&gt;Unpack the Broadcom drivers, and use&lt;br /&gt;&lt;br /&gt;ndiswrapper -i netbc564.inf&lt;br /&gt;&lt;br /&gt;Then you can load the ndiswrapper into the driver:&lt;br /&gt;&lt;br /&gt;modprobe ndiswrapper&lt;br /&gt;&lt;br /&gt;Now you can lookup what there is in your current wireless lan:&lt;br /&gt;&lt;br /&gt;iwlist wlan0 scan&lt;br /&gt;&lt;br /&gt;It should show a list (provided you are somewhere in reach of a WIFI lan)&lt;br /&gt;&lt;br /&gt;You can connect to a specific access point, by doing;&lt;br /&gt;&lt;br /&gt;iwconfig wlan0 essid "AccessPointName"&lt;br /&gt;&lt;br /&gt;(You actually see the ESSID name when running the iwlist scan command)&lt;br /&gt;&lt;br /&gt;You don't HAVE to do this; you can let the driver pick an accesspoint itself.&lt;br /&gt;&lt;br /&gt;If you have WPA installed, you need wpa_supplicant; get it and install it.&lt;br /&gt;&lt;br /&gt;A simple config I am using looks like this:&lt;br /&gt;&lt;br /&gt;network={&lt;br /&gt;       ssid="AccessPointName"&lt;br /&gt;       proto=WPA&lt;br /&gt;       key_mgmt=WPA-PSK&lt;br /&gt;       pairwise=TKIP&lt;br /&gt;       group=TKIP&lt;br /&gt;       psk="ThisIsYourPassword"&lt;br /&gt;       priority=2&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;This should be in your&lt;br /&gt;&lt;br /&gt;/etc/wpa_supplicant.conf&lt;br /&gt;&lt;br /&gt;and then switch the WPA encryption on with:&lt;br /&gt;&lt;br /&gt;wpa_supplicant -iwlan0 -c/etc/wpa_supplicant.conf -D ndiswrapper -B&lt;br /&gt;&lt;br /&gt;If you have a DHCP server, then you can get the IP address like this:&lt;br /&gt;&lt;br /&gt;dhclient wlan0&lt;br /&gt;&lt;br /&gt;Or you can do it by hand with something like this (depending on your network);&lt;br /&gt;&lt;br /&gt;ifconfig wlan0 192.168.1.194&lt;br /&gt;route add default gw 192.168.1.1&lt;br /&gt;&lt;br /&gt;Now everything is working!&lt;br /&gt;&lt;br /&gt;Playing media files (like MP3s) is not standard in the applications like Gnome Music Player or&lt;br /&gt;XMMS under FC4. You need some adjustments for that; do the following:&lt;br /&gt;&lt;br /&gt;rpm -ivh http://rpm.livna.org/fedora/4/i386/RPMS.lvn/livna-release-4-0.lvn.5.4.noarch.rpm&lt;br /&gt;&lt;br /&gt;Now you can install all cool stuff; to get MP3s working, do this:&lt;br /&gt;&lt;br /&gt;yum install libmad&lt;br /&gt;yum install libid3tag&lt;br /&gt;yum install gstreamer-plugins-mp3&lt;br /&gt;&lt;br /&gt;If you get any errors when you try to play, run&lt;br /&gt;&lt;br /&gt;gstreamer-properties&lt;br /&gt;&lt;br /&gt;and try some different configurations until it works. Then the music player should also work.&lt;br /&gt;&lt;br /&gt;To burn CD/DVD I use k3b; use&lt;br /&gt;&lt;br /&gt;yum install k3b&lt;br /&gt;&lt;br /&gt;to get it installed.&lt;br /&gt;&lt;br /&gt;Enjoy!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-112715988849386458?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/112715988849386458'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/112715988849386458'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2005/09/installing-fc4-on-acer-ferrari-3400.html' title='Installing FC4 on an Acer Ferrari 3400'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-112189670054330671</id><published>2005-07-20T14:54:00.000-07:00</published><updated>2005-07-20T14:58:20.556-07:00</updated><title type='text'>Windows 2003 and MySQL</title><content type='html'>A short post here. Had to install and run MySQL on Windows 2003. Didn't work.&lt;br /&gt;Just used the standard install for 4.0.25; it wouldn't start, not from a service and not from winmysqladmin.exe. Everything seemed ok though, but nothing in the logs and the Windows event viewer kept saying it 'couldn't find the file'. Which was rubbish.&lt;br /&gt;Tried 3.23.58 which didn't work either. I just wanted MySQL to tell me what was wrong, but it said nothing, it just died.&lt;br /&gt;&lt;br /&gt;Finally I got it to work using mysqld -T ; I don't know what that is, but it works. Nice experience with Windows again :) Thank god for apt-get install mysql-server!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-112189670054330671?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/112189670054330671'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/112189670054330671'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2005/07/windows-2003-and-mysql.html' title='Windows 2003 and MySQL'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-112059959220669075</id><published>2005-07-05T14:34:00.000-07:00</published><updated>2005-07-05T14:43:43.800-07:00</updated><title type='text'>Dragging and dropping controls in RealBasic</title><content type='html'>Someone recently asked me to figure out how to make an application to drag &amp; drop controls on a canvas in RealBasic (RealBasic 2005 to be exact). I thought that about a billion people would have done this by now and would have put their stuff on the web. This turned out not to be true.&lt;br /&gt;&lt;br /&gt;The way to do it is actually trivial in any event-driven language, but in RealBasic it seems even easier :)&lt;br /&gt;&lt;br /&gt;I will show the dragging and dropping of a pushbutton; you can figure out the rest for yourself. Do not pay attention to the quality of the code; I was only supposed to figure out how to do it, not win any prices!&lt;br /&gt;&lt;br /&gt;Make a Window and put a PushButton on it. Now add some properties:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;obj as Object&lt;/li&gt;   &lt;li&gt;x as Integer&lt;/li&gt;   &lt;li&gt;y as Integer&lt;/li&gt;   &lt;li&gt;move as Boolean&lt;/li&gt; &lt;/ul&gt; Put in the MouseDown of the PushButton:&lt;br /&gt;&lt;br /&gt;obj = me&lt;br /&gt;return true&lt;br /&gt;&lt;br /&gt;and in the MouseUp of the PushButton:&lt;br /&gt;&lt;br /&gt;obj = nil&lt;br /&gt;return true&lt;br /&gt;&lt;br /&gt;Now put in the MouseMove of the Window:&lt;br /&gt;&lt;br /&gt;dim ctl as RectControl&lt;br /&gt;&lt;br /&gt;if  obj&lt;&gt;nil then&lt;br /&gt;  ctl = RectControl(obj)&lt;br /&gt;end if&lt;br /&gt;&lt;br /&gt;if (not move and obj &lt;&gt; nil) then&lt;br /&gt;  dx = x - ctl.Left&lt;br /&gt;  dy = y - ctl.Top&lt;br /&gt;  move = true&lt;br /&gt;  MouseCursor = System.Cursors.ArrowAllDirections&lt;br /&gt;end if&lt;br /&gt;&lt;br /&gt;if (move and obj = nil) then&lt;br /&gt;  move = false&lt;br /&gt;  MouseCursor = System.Cursors.StandardPointer&lt;br /&gt;end if&lt;br /&gt;&lt;br /&gt;if (move and x &gt;0 and y&gt;0 and x &lt; me.width and y &lt; me.Height)  then&lt;br /&gt;  ctl.Left = x - dx&lt;br /&gt;  ctl.Top = y-dy&lt;br /&gt;  me.refresh&lt;br /&gt;end if&lt;br /&gt;&lt;br /&gt;And that's it :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-112059959220669075?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/112059959220669075'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/112059959220669075'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2005/07/dragging-and-dropping-controls-in.html' title='Dragging and dropping controls in RealBasic'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-111840374890323730</id><published>2005-06-10T04:27:00.000-07:00</published><updated>2005-06-10T04:42:28.906-07:00</updated><title type='text'>Scaling and growing...</title><content type='html'>After my clustering experiments which you read about in my last post we were capable of handling more than a 1000 concurrent visitors. We will see if the current growth can be managed by this clustering on the 4 systems currently running the site. It is clear to me now that the bottleneck was actually the MySQL, not the web part. Switching off the second webserver makes no difference, while switching off the second MySQL will completely stop the site from responding.  So I removed the one webserver and the site is running on 3 webservers now.&lt;br /&gt;&lt;br /&gt;The MySql installation has been tweaked for absolute performance with all the tricks in the books, but it cannot do more than it it doing now on that hardware. I need to figure out a way to see, in the next concurrent userbarrier, which part of the system needs improvement. I will think about it; if anyone has an idea; let's have it (put a comment please).&lt;br /&gt;&lt;br /&gt;My next projects are;&lt;br /&gt;&lt;br /&gt;- make a seperate site for chat and use that instead of the current chat (dunno which chat yet; have to find a nice one still)&lt;br /&gt;- make a seperate site for the forum and use that instead of the current forum (probably phpbb) &lt;br /&gt;- making a MySQL/PHP cache for the database queries on the current site&lt;br /&gt;- fixing the master-slave replication so it won't fail if the master fails&lt;br /&gt;&lt;br /&gt;More on this subject... Later.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-111840374890323730?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/111840374890323730'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/111840374890323730'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2005/06/scaling-and-growing.html' title='Scaling and growing...'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-111824001991321905</id><published>2005-06-08T06:29:00.000-07:00</published><updated>2005-06-08T07:13:39.920-07:00</updated><title type='text'>Simple loadbalancing with PHP &amp; MySQL</title><content type='html'>I am running different sites on a lot of different hardware configurations. When a site becomes too slow you have different options:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;   &lt;li&gt;buy a new,faster server&lt;/li&gt;   &lt;li&gt;buy more servers&lt;/li&gt;   &lt;li&gt;fix the software (optimize; better/more cache)&lt;/li&gt; &lt;/ul&gt;&lt;br /&gt;Usually we host sites built on Java/J2EE platform; these sites are made for medium size to (very) big companies and are all built to last and the be scalable. Clustering/failover/loadbalancing are options which are built into these systems by default. The main products my employer sells support clustering out-of-the-box.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Now enter my hobby projects, all of them in PHP and written in a few weekends and nights. One of them got a bit out of hand. When there were 75-100 people concurrent, my single CPU, cheapo hardware took 20 secs to render an average page. The entire site was not cached, it was loaded with features (the most feature-rich dating platform in the world, I dare to say) and written badly.&lt;br /&gt;&lt;br /&gt;This site is running on very cheap (&lt; Euro 300) hardware (Celeron 2,4 with 512 mb mem and 2 * 40 gb IDE hds); these boxes are homemade with the cheapest material money can buy. It is hardly possible to do it cheaper than that. Why did I choose this? Because it is actually a free (as in beer) site. So I don't want to spend a lot of money on hardware/hosting/anything.&lt;br /&gt;&lt;br /&gt;I first fixed the code to be slightly more efficient and started, at the same time, to build in cache.  You must know; datingsite have caching 'challenges', because users are continuesly doing searches and changing stuff while being logged-on. So I had to make cache-per-person for most of the pages.  After these changes the site could hold out, on the same hardware, to 400-500 concurrent users.&lt;br /&gt;&lt;br /&gt;After a while, the amount of concurrent users per day began to go over 500 and after a while, even over 600. The pages, at night, took 20 sec again to load :(&lt;br /&gt;&lt;br /&gt;The site was completely not prepared for loadbalancing, in any way. So the next step I took was seperating the webpart and the database part and put them on different servers. You have to know that the webpart, with all user photos weighs about 4 gigabytes currently (with more than 30.000 members) and the database is 3 gigabytes. I seperated it on 2 servers with the same homemade crappy hardware described above.&lt;br /&gt;This trick was great; the site could handle up to 700-800 users with ease suddenly.&lt;br /&gt;&lt;br /&gt;But ofcourse, it was still growing and the 800 concurrent level was made 4 weeks ago. More users made the site slower and slower and slower and.......&lt;br /&gt;&lt;br /&gt;The problem seemed to be high traffic on both the webfrontend and the database. The webfrontend could easily be fixed; I would add another box (or even more) and DNS them to be called www1, www2, www3 etc. Then I would have the index on the main domain throw a user to one of those boxes randomly:&lt;br /&gt;&lt;br /&gt;$server[]="www1";&lt;br /&gt;$server[]="www2";&lt;br /&gt;$server[]="www3";&lt;br /&gt;$r = rand(0,sizeof($server));&lt;br /&gt;header("Location: ".$server[$r]);&lt;br /&gt;&lt;br /&gt;This is the real lame-brain loadbalancing; better loadbalancing would be, ofcourse, using a hardware loadbalancer or a BIND DNS round-robin loadbalancer. But for hardware I don't have the money and for software I would need the domain to be managed by my DNS and it isn't and the provider I have it at doesn't know what loadbalancing is. So I will move, but for now, this works fine.&lt;br /&gt;&lt;br /&gt;This helped a bit, but ofcourse overloaded the MySQL database servicing all these frontends...&lt;br /&gt;&lt;br /&gt;Balancing MySQL is a bit harder. It is actually much harder. You need to be capable of replicating the MySQL to different servers and this is difficult; MySQL only support master-slave replication which is quite lame; you cannot write to the slaves. Also, you need to put on Logs for this replication which take I/O power and fill up your harddisk space fast.&lt;br /&gt;&lt;br /&gt;So I decided to do this differently; I added another box (running 4 boxes now) and rewrote the software by changing all references to mysql_query to _mysql_query. I tested using:&lt;br /&gt;&lt;br /&gt;function _mysql_query($qry) {&lt;br /&gt; return mysql_query($qry);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;When this worked, I filled in this method:&lt;br /&gt;&lt;br /&gt; $master_db = make_mysql_connection(MASTER_DB);&lt;br /&gt; $slave_db[] = make_mysql_connection(SLAVE_DB1);&lt;br /&gt;&lt;br /&gt; function __mysql_query($qry) {&lt;br /&gt;  global $master_db;&lt;br /&gt;  global $slave_db;&lt;br /&gt;  $cmd = strtolower(substr($qry, 0, 6));&lt;br /&gt;  $conn = $master_db;&lt;br /&gt;  if ($cmd == "select") {&lt;br /&gt;   $choice = rand(0, 10);&lt;br /&gt;   if ($choice &amp;gt; 1 &amp;&amp;amp; $slave_db[0]) {&lt;br /&gt;    $conn = $slave_db[0];&lt;br /&gt;   }&lt;br /&gt;  } else {&lt;br /&gt;   for ($i=0;$i&amp;lt;sizeof($slave_db);$i++) {&lt;br /&gt;    if ($slave_db[$i]) {&lt;br /&gt;     mysql_query($qry, $slave_db[$i]);&lt;br /&gt;    }&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt;  return mysql_query($qry, $conn);&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt;This way it will do all writes to all slaves and the master, and it will alternate reads between the master and the slave to some given random %.&lt;br /&gt;Flaws: I will fix this function to round robin between X slaves &lt;span style="font-weight: bold;"&gt;and&lt;/span&gt; I will fix it to fail a slave (after which you have to re-make it with a DB dump from the master. For this last problem I will also figure something out I hope.&lt;br /&gt;&lt;br /&gt;The current system is capable of packing a much larger punch and it is actually quite scalable, cheap and very easy to make and setup, even in environments you don't have control over the MySQL and Apache installs.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-111824001991321905?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/111824001991321905'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/111824001991321905'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2005/06/simple-loadbalancing-with-php-mysql.html' title='Simple loadbalancing with PHP &amp; MySQL'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-111813376599310018</id><published>2005-06-07T01:07:00.000-07:00</published><updated>2005-06-07T01:42:45.996-07:00</updated><title type='text'>Aaaargghhh Session mixing in PHP</title><content type='html'>I am webmaster of a free dating site for Dutch people. After passing the 30000 members, we started to experience problems with the session handling. People started to receive the same session ids. Ofcourse this is not very nice for a dating site :)&lt;br /&gt;After searching a bit on Google, I found people with similar problems. They 'fixed' it by adding entropy file = /dev/urandom and entropy length = 64. Problem was, I already had this set for my site... So that didn't work.&lt;br /&gt;To fix it, I simply created the following code;&lt;br /&gt;&lt;br /&gt; function _session_start() {&lt;br /&gt;  $ipad = $_SERVER["REMOTE_ADDR"];&lt;br /&gt;  $ipad = str_replace(".", "c", $ipad)."c";&lt;br /&gt;  if (!session_id()) {&lt;br /&gt;    session_start();&lt;br /&gt;  }&lt;br /&gt;  if (substr(session_id(), 0, strlen($ipad))!=$ipad) {&lt;br /&gt;   session_destroy();&lt;br /&gt;   $ipad .= gen_rand(35);&lt;br /&gt;   session_id($ipad);&lt;br /&gt;   session_start();&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt;were gen_rand generates 35 random letters and numbers. Replace &lt;span style="font-weight: bold;"&gt;all  &lt;/span&gt;your session_start() with _session_start() and all will be fine.&lt;br /&gt;&lt;br /&gt;On a datingsite this works fine; no big companies behind one IP address. You can use more eleborate schemes for creating this session id. For instance, adding a second random cookie on the client will actually make the chance of duplicate ids very very small.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-111813376599310018?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/111813376599310018'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/111813376599310018'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2005/06/aaaargghhh-session-mixing-in-php.html' title='Aaaargghhh Session mixing in PHP'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-111643916044647920</id><published>2005-05-18T10:48:00.000-07:00</published><updated>2005-05-18T11:06:50.093-07:00</updated><title type='text'>Crossplaform document document indexing with Lucene and OpenOffice</title><content type='html'>When you have ever worked with Lucene you know that, to index your documents, you have to convert your documents to text. This text is used by Lucene to create the index for the document.&lt;br /&gt;For most formats there are convertors which are either written in Java or native. The problem is that you need to write indexing classes for a lot of different documents; you have to use a lot of different libraries and you have have to make sure your deployment machine contains those libraries...&lt;br /&gt;&lt;br /&gt;...or you just install OpenOffice (&lt;a href="http://www.openoffice.org/"&gt;http://www.openoffice.org&lt;/a&gt;) !&lt;br /&gt;&lt;br /&gt;OpenOffice is capable of opening most productivity tool formats and even more formats are in the making as we speak. Opening Word, Excel, Powerpoint, Access, dBase, WordPerfect, all StarOffice and OpenOffice formats, Lotus 1-2-3, HTML, XML and much more are no problem for the latest version of OpenOffice.&lt;br /&gt;&lt;br /&gt;Now only to get a document converted for indexing with Lucene. This is extremely trivial. I assume you have installed OpenOffice 1.9+ Beta.&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;   &lt;li&gt;Open Writer&lt;/li&gt;   &lt;li&gt;Goto Tools -&gt; Macros -&gt; Organize Macros&lt;/li&gt;   &lt;li&gt;Click on the Libraries tab&lt;br /&gt; &lt;/li&gt;   &lt;li&gt;Select 'My Dialogs &amp; Dialogs'&lt;br /&gt; &lt;/li&gt;   &lt;li&gt;Click on New&lt;/li&gt;   &lt;li&gt;Type 'MyLibraries'&lt;br /&gt; &lt;/li&gt;   &lt;li&gt;Click on 'Modules'&lt;/li&gt;&lt;li&gt;Click on 'MyLibraries'&lt;/li&gt;   &lt;li&gt;Click on New&lt;/li&gt;   &lt;li&gt;Type 'Conversion'&lt;/li&gt;   &lt;li&gt;Select 'Conversion'&lt;br /&gt;  &lt;/li&gt;   &lt;li&gt;Click on Edit&lt;/li&gt;   &lt;li&gt;Copy/paste the following code into the editor:&lt;/li&gt;  &lt;/ol&gt;&lt;br /&gt;&lt;blockquote&gt;Sub ConvertWordToTxt( cFile )&lt;br /&gt;   cURL = ConvertToURL( cFile )&lt;br /&gt;  &lt;br /&gt;   ' Open the document.&lt;br /&gt;   ' Just blindly assume that the document is of a type that OOo will&lt;br /&gt;   '  correctly recognize and open -- without specifying an import filter.&lt;br /&gt;   oDoc = StarDesktop.loadComponentFromURL( cURL, "_blank", 0, Array(_&lt;br /&gt;            MakePropertyValue( "Hidden", True ),_&lt;br /&gt;            ) )&lt;br /&gt; &lt;br /&gt; &lt;br /&gt;   cFile = Left( cFile, Len( cFile ) - 4 ) + ".txt"&lt;br /&gt;   cURL = ConvertToURL( cFile )&lt;br /&gt;  &lt;br /&gt;   ' Save the document using a filter.  &lt;br /&gt;   oDoc.storeToURL( cURL, Array(_&lt;br /&gt;            MakePropertyValue( "FilterName", "Text" ),_&lt;br /&gt;            )&lt;br /&gt;  &lt;br /&gt;   oDoc.close( True )&lt;br /&gt;End Sub&lt;br /&gt;Function MakePropertyValue( Optional cName As String, Optional uValue ) As com.sun.star.beans.PropertyValue&lt;br /&gt;   Dim oPropertyValue As New com.sun.star.beans.PropertyValue&lt;br /&gt;   If Not IsMissing( cName ) Then&lt;br /&gt;      oPropertyValue.Name = cName&lt;br /&gt;   EndIf&lt;br /&gt;   If Not IsMissing( uValue ) Then&lt;br /&gt;      oPropertyValue.Value = uValue&lt;br /&gt;   EndIf&lt;br /&gt;   MakePropertyValue() = oPropertyValue&lt;br /&gt;End Function &lt;/blockquote&gt;&lt;br /&gt;Now hit CRTL-s and close Writer.&lt;br /&gt;&lt;br /&gt;You can now run this code like this:&lt;br /&gt;&lt;br /&gt;"c:\program files\OpenOffice.org 1.9.79\program\soffice" -invisible "macro:///MyLibraries.Conversion.ConvertWordToPDF(DOCUMENTNAME)"&lt;br /&gt;&lt;br /&gt;Substitute DOCUMENTNAME with your document and your document will be converted to .txt.&lt;br /&gt;&lt;br /&gt;I will explore using this within Lucene a bit later!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-111643916044647920?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/111643916044647920'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/111643916044647920'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2005/05/crossplaform-document-document.html' title='Crossplaform document document indexing with Lucene and OpenOffice'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-111633065163113228</id><published>2005-05-17T04:42:00.000-07:00</published><updated>2005-05-18T04:56:39.710-07:00</updated><title type='text'>Making your own storage server with cheap hardware</title><content type='html'>Yesterday I started working on a cheap storage server. I had the following requirements:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;   &lt;li&gt;I needed a versioning file system (so every document I store is versioned)&lt;/li&gt;   &lt;li&gt;I needed access via Webdav, also for this versioning&lt;/li&gt;   &lt;li&gt;It should have easy install&lt;br /&gt;&lt;/li&gt;   &lt;li&gt;I wanted to use cheap hardware (my 400 mhz system I have gathering dust in my cupboard should do nicely)&lt;br /&gt;&lt;/li&gt;   &lt;li&gt;I wanted to user friendly tools to support the system (under both Windows and Linux) &lt;/li&gt;   &lt;li&gt;It had to be secure (SSL enabled on all levels)&lt;/li&gt;&lt;li&gt;It must be searchable, whatever document I throw in (doc, xls, odt, wpd, txt, xml, html, mp3 etc)&lt;br /&gt;&lt;/li&gt;  &lt;/ol&gt;&lt;br /&gt;After a bit of searching, it became clear I would use Apache 2 and Subversion under Linux to achieve my goal.&lt;br /&gt;&lt;br /&gt;The steps I took to install it all where;&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;   &lt;li&gt;Install Fedora Core 3, server install with all installation options marked off and SELinux off (!)&lt;br /&gt;&lt;/li&gt;   &lt;li&gt;Get the network verified and working&lt;/li&gt;   &lt;li&gt;Import the GPG key:&lt;br /&gt; &lt;pre&gt;rpm --import http://www.fedora.us/FEDORA-GPG-KEY&lt;span style="font-family:georgia,serif;"&gt;&lt;/span&gt;&lt;/pre&gt;   &lt;/li&gt;   &lt;li&gt;&lt;span style="font-family:georgia,serif;"&gt;Install Apache: yum install httpd&lt;/span&gt;&lt;/li&gt;   &lt;li&gt;&lt;span style="font-family:georgia,serif;"&gt;Install mod_ssl: yum install mod_ssl&lt;br /&gt; &lt;/span&gt;&lt;/li&gt;   &lt;li&gt;&lt;span style="font-family:georgia,serif;"&gt;Install Subversion: yum install subversion&lt;/span&gt;&lt;/li&gt;   &lt;li&gt;&lt;span style="font-family:georgia,serif;"&gt;Install mod_dav_svn: &lt;/span&gt;&lt;span class="code"&gt;yum install mod_dav_svn&lt;/span&gt;&lt;/li&gt; &lt;/ol&gt;Now your FC installation is ready to go; it already fixed a key for you so the SSL installation is ready.&lt;br /&gt;&lt;br /&gt;Make the repository directory:&lt;br /&gt;&lt;br /&gt;mkdir /home/svn&lt;br /&gt;&lt;br /&gt;chown -R apache.apache /home/svn&lt;br /&gt;&lt;br /&gt;Make the directory for your security:&lt;br /&gt;&lt;br /&gt;mkdir /home/secvsn&lt;br /&gt;&lt;br /&gt;chgrp -R apache /home/secsvn&lt;br /&gt;chmod -R 750 /home/secsvn&lt;br /&gt;&lt;br /&gt;You have to change the configuration of Subversion under Apache; it is stored here;&lt;br /&gt;&lt;br /&gt;/etc/httpd/conf.d/subversion.conf&lt;br /&gt;&lt;br /&gt;Add the following:&lt;br /&gt;&lt;br /&gt;&amp;lt;Location /svn&amp;gt;&lt;br /&gt;DAV svn&lt;br /&gt;SVNPath /home/svn&lt;br /&gt;SVNAutoversioning on&lt;br /&gt;AuthType Basic&lt;br /&gt;AuthName "My SVN Repository"&lt;br /&gt;AuthUserFile /home/secsvn/passwd&lt;br /&gt;AuthzSVNAccessFile /home/secsvn/access&lt;br /&gt;Require valid-user&lt;br /&gt;&amp;lt;/Location&amp;gt;&lt;br /&gt;&lt;br /&gt;Make the password file:&lt;br /&gt;&lt;br /&gt;htpasswd -cm /home/secvwn/passwd john&lt;br /&gt;&lt;br /&gt;and type a password.&lt;br /&gt;&lt;br /&gt;Then make the access file:&lt;br /&gt;&lt;br /&gt;cat &gt; /home/secsvn/access&lt;br /&gt;[/]&lt;br /&gt;john = rw&lt;br /&gt;&lt;br /&gt;Meaning that john can read and write the entire repository so far. You can add more users if you want ofcourse; read the SVN book to see the syntax.&lt;br /&gt;&lt;br /&gt;Start Apache:&lt;br /&gt;&lt;br /&gt;/etc/init.d/httpd start&lt;br /&gt;&lt;br /&gt;To make sure it starts at the start of the OS:&lt;br /&gt;&lt;br /&gt;chkconfig httpd on&lt;br /&gt;&lt;br /&gt;Now it should work; make sure you have the firewall open for Apache port 80, if you do not know or have this yet, type;&lt;br /&gt;&lt;br /&gt;system-config-securitylevel&lt;br /&gt;&lt;br /&gt;and set Apache to the list of allowed services.&lt;br /&gt;&lt;br /&gt;From another computer, try;&lt;br /&gt;&lt;br /&gt;http://your.ip/svn/&lt;br /&gt;&lt;br /&gt;This should ask your for a name and password; this is the aforementioned and created user 'john'.&lt;br /&gt;&lt;br /&gt;If you enter the user and it does not work, look in the /var/log/httpd/error.log file for clues. If there is something wrong with permissions, you problably mounted the repository on another drive and have SELinux security on. To fix this, either turn SELinux off or give the repository the right credentials (Google this).&lt;br /&gt;&lt;br /&gt;[TODO: howto switch on SSL for this service]&lt;br /&gt;&lt;br /&gt;How I made the search I will put somewhere here later, because it appeared my network card was broken and network switched off automatically after 30 minutes of use on the system.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-111633065163113228?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/111633065163113228'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/111633065163113228'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2005/05/making-your-own-storage-server-with.html' title='Making your own storage server with cheap hardware'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-111622859238608630</id><published>2005-05-16T00:21:00.000-07:00</published><updated>2005-05-16T01:28:09.663-07:00</updated><title type='text'>Executing files with Windows native handler</title><content type='html'>As I am currently building a cross platform file-manager for our document management tool in Java, I am in need for a way to have files executed by the Windows (and other OSes, but for most clients; Windows) shell as they would be executed when clicking on them in the Windows file explorer.&lt;br /&gt;&lt;br /&gt;Doing this in Java is quite easy and a lot of people already figured that out, you simply use the rundll32 command to execute the following:&lt;br /&gt;&lt;br /&gt;rundll32 url.dll,FileProtocolHandler URL&lt;br /&gt;&lt;br /&gt;where URL can be something on internet or on your local drive. Say you want to 'run' a .txt file on your c:  drive:&lt;br /&gt;&lt;br /&gt;rundll32 url.dll,FileProtocolHandler file:///mytextfile.txt&lt;br /&gt;&lt;br /&gt;opens, on my system with notepad.&lt;br /&gt;&lt;br /&gt;The problem with this method is, that if there is no handler, nothing will happen...&lt;br /&gt;&lt;br /&gt;After playing around a bit with the registry I found the following;&lt;br /&gt;&lt;br /&gt;reg query HKCR\.ext&lt;br /&gt;&lt;br /&gt;gives you information about the extension and what Windows will do with it.&lt;br /&gt;&lt;br /&gt;In general, as I have discovered (correct me if I am wrong please!), if &lt;no&gt; is in the result, the file can and will be executed by Windows.  You can even use it to extract the file type. Example:&lt;br /&gt;&lt;br /&gt;C:\&gt;reg query HKCR\.dot&lt;br /&gt;&lt;br /&gt;! REG.EXE VERSION 3.0&lt;br /&gt;&lt;br /&gt;HKEY_CLASSES_ROOT\.dot&lt;br /&gt;&lt;no&gt;&amp;lt;NO NAME&amp;gt; REG_SZ  OpenOffice.org.dot&lt;br /&gt;&lt;br /&gt;HKEY_CLASSES_ROOT\.dot\PersistentHandler&lt;br /&gt;&lt;br /&gt;So the code for running a file with the default associated application under Windows would be:&lt;br /&gt;&lt;/no&gt;&lt;/no&gt;       &lt;br /&gt;&lt;blockquote&gt;String file = "/test.html";&lt;br /&gt;       String ext = file.substring(file.lastIndexOf('.'));&lt;br /&gt;&lt;br /&gt;     Process p = Runtime.getRuntime().exec("reg query HKCR\\" + ext);&lt;br /&gt;     InputStream in = p.getInputStream();&lt;br /&gt;     p.waitFor();&lt;br /&gt;     byte[] buffer = new byte[in.available()];&lt;br /&gt;    in.read(buffer);&lt;br /&gt;    String result = new String(buffer);&lt;br /&gt;    in.close();&lt;br /&gt;&lt;br /&gt;    if (result.indexOf("&amp;lt;NO NAME&amp;gt;") &gt; -1) {&lt;br /&gt;p = Runtime.getRuntime().exec("rundll32 url.dll,FileProtocolHandler file://"+file);&lt;br /&gt;    } else {&lt;br /&gt;            System.err.println("No handler available for "+file);&lt;br /&gt;    }&lt;br /&gt;&lt;/blockquote&gt;&lt;no&gt;&lt;br /&gt;&lt;/no&gt;&lt;no&gt;There are probably ways to do this faster/easier, but currently we are not in need of this. However, if you know ways to do it, please comment on this post.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/no&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-111622859238608630?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/111622859238608630'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/111622859238608630'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2005/05/executing-files-with-windows-native.html' title='Executing files with Windows native handler'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-9974736.post-111619534313311046</id><published>2005-05-15T15:00:00.000-07:00</published><updated>2005-05-15T15:23:30.236-07:00</updated><title type='text'>Installing Linux on an Acer Ferrari 3400</title><content type='html'>I recently got to pick new notebook at my work to program Java on; because I like gadgets and because I have been wanting to test out those nice 64 bit processors for a long time already, I pick the Acer Ferrari. The Ferrari logo is a bit of shame (not enough money to buy the car, but still have a Ferrari is kinda sad). The red colour is nice though, and the system is thin and not too heavy.&lt;br /&gt;&lt;br /&gt;Windows 64 bit is too new and not included. And why would I want to use Windows anyway?&lt;br /&gt;Lazy as I am, I did not check if any Linux would run on it. I just assumed it would. After a bit of websearching I decided to try some distributions: Ubuntu 64 bit, Knoppix 64 bit and, last but not least Fedora Core 3 64 bit.&lt;br /&gt;&lt;br /&gt;FC3 was the only Linux which installed nicely and detected almost everything. Be sure to start the install with "linux nofb", otherwise you'll see a very black screen during the install. The install will go flawless.&lt;br /&gt;&lt;br /&gt;To use the wireless lan which is integrated under a 64 bit system, you'll need the 64 bit Windows driver for this Broadcom chipset. You can pick up the driver here; http://ubuntuforums.org/attachment.php?attachmentid=186&lt;br /&gt;Then you should install ndiswrapper (http://ndiswrapper.sourceforge.net). Getting it to work is trivial;&lt;br /&gt;&lt;br /&gt;tar xvzf ndiswrapper.tgz&lt;br /&gt;cd ndiswrapper&lt;br /&gt;make&lt;br /&gt;make install&lt;br /&gt;ndiswrapper -i netbc564.inf&lt;br /&gt;modprobe ndiswrapper&lt;br /&gt;iwlist wlan0 scan&lt;br /&gt;&lt;br /&gt;now you should see a list of detected networks; if not, something is wrong.&lt;br /&gt;&lt;br /&gt;If your computer hangs after the modprobe command, you probably have more than 1 gb of memory and not the latest version of ndiswrapper. I fixed the ndiswrapper together with the guys maintaining the wrapper (long live Open Source!); it took 1 day to figure out what it was and fix the bug (https://sourceforge.net/tracker/?func=detail&amp;atid=604450&amp;amp;aid=1169978&amp;group_id=93482).&lt;br /&gt;&lt;br /&gt;After the wireless station is detected, you should make the network work;&lt;br /&gt;&lt;br /&gt;ifconfig wlan0 some_ip up&lt;br /&gt;route add default gw some_gw up&lt;br /&gt;&lt;br /&gt;When using WEP or other encryption, some more steps are required (Google for iwlist, iwconfig etc).&lt;br /&gt;&lt;br /&gt;I work happily with a 64 bit Linux system now, but I still have one problem; the battery overview is incorrect. I use FC3 with KDE and the default notebook app which shows battery status, but the status is actually wrong. If anyone has a fix, please comment on this post!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9974736-111619534313311046?l=brainfish-eat-fishbrain.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/111619534313311046'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9974736/posts/default/111619534313311046'/><link rel='alternate' type='text/html' href='http://brainfish-eat-fishbrain.blogspot.com/2005/05/installing-linux-on-acer-ferrari-3400.html' title='Installing Linux on an Acer Ferrari 3400'/><author><name>tycho</name><uri>http://www.blogger.com/profile/03157313039640117008</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry></feed>
