Two MacBook Airs could live inside the lid of the Dell Inspiron 6000.
Cloning a drive the ‘dd’ way
Here’s how I cloned a drive with bad sectors using ‘dd‘.
Since I did this on a Mac, I saved the output image file as a ‘.img’ file. This would give me the ability to mount the image after I created it if I needed to get individual files.
Clone the failing drive to an image file, skip bad sector errors with ‘noerror’:
- Connect the drive to a Unix / Linux machine – do not mount the disk
- Find the drive name in /dev (for me it was /dev/disk1)
- Verify the host system has enough local storage to create the image, and in a terminal type:
sudo dd conv=noerror,sync if=/dev/disk1 of=disk.img
- Give it time to create the image. You may see errors when it hits bad sectors, but it’ll keep running thanks to ‘noerror’.
Copying from the image file to the new drive:
- Connect the new drive and make sure it isn’t mounted (if it’s really new it shouldn’t have any file system or partitions at all)
- Find the drive name in /dev (for me it was /dev/disk1)
- Type in a terminal:
sudo dd conv=noerror,sync if=disk.img of=/dev/disk1
- Give it time to copy from the image to the new disk.
The nice thing is that it copies everything. For me, the MBR was still there along with all partitions. If you wanted to just copy a single partition you could just be more specific (/dev/disk1s1 or however your system represents them). If the new drive was larger than the original drive, you’ll notice that there will be unallocated space. You can either create a separate partition, or use a utility to grow an existing one. Recent versions of Windows and OS X have this capability built in.
On boot, the machine I was repairing recognized the filesystem was dirty (it was a Windows XP machine / NTFS), and immediately ran a SCANDISK. I also manually ran it again once I booted into the system, and also ran ‘sfc /scannow’ to verify the system files were intact.
That’s all you have to do. No expensive cloning software needed, just the power of Unix / Linux.
Nagios alerts using sSMTP
I’ve been running Nagios on my systems at home (yes, I’m that big of a nerd) for a week or so, but didn’t get around to setting up e-mail alerts until now. There are a few ways to go about doing this, but I’ll describe the way I got it going. Since I’m not running a mail server on any of my machines I use Google Apps to handle e-mail for my domains. I rather have ‘the Google’ deal with all of that for me (and they do a great job).
For this particular instance I was running Ubuntu Server 8.04.4 LTS, but these steps should work fine on other versions and distros.
1. Install sSMTP and mailx
sudo apt-get install ssmtp mailx
2. Configure sSMTP by editing /etc/ssmtp/ssmtp.conf
# Config file for sSMTP sendmail # # The person who gets all mail for userids < 1000 # Make this empty to disable rewriting. root=[your user account]@[yourdomain.com] # The place where the mail goes. The actual machine name is required no # MX records are consulted. Commonly mailhosts are named mail.domain.com mailhub=smtp.gmail.com:587 # Where will the mail seem to come from? rewriteDomain= # The full hostname hostname=[some hostname here] UseTLS=YES UseSTARTTLS=YES AuthMethod=LOGIN AuthUser=[your user account]@[your domain] AuthPass=[your password] # Are users allowed to set their own From: address? # YES - Allow the user to specify their own From: address # NO - Use the system generated From: address # This is optional if you're going to use revaliases - I didn't FromLineOverride=YES
3. Lock down /etc/ssmtp/ssmtp.conf to help protect your plaintext password
sudo chown root:nagcmd /etc/ssmtp/ssmtp.conf sudo chmod 640 /etc/ssmtp/ssmtp.conf
4. Alter your Nagios commands.cfg file for the correct mail path (for Ubuntu at least)
sudo vim /usr/local/nagios/etc/objects/commands.cfg
And change all instances of /bin/mail to /usr/bin/mail. Be sure to reload your Nagios configuration after making these changes.
That should be it! If you’re having trouble, break things down to troubleshoot. First test out sSMTP by doing the following:
sudo -vvv ssmtp somebody@somedomain.com
Write a message, press enter, then hit CTRL+D. If that works successfully but Nagios still isn’t sending alerts, be sure to check the Event Log in the Nagios interface to see if there are any errors.
I don’t know if you can really call this a bug, but it’s certainly something that needs to be dealt with. After implementing the jQuery Nivo Slider plugin (which is great when it works), I was getting the following error in the JavaScript console in Chrome during every image transition:
Uncaught TypeError: Cannot call method 'substr' of undefined
The transitions were working, but the previous image wasn’t ‘overlayed’ by the next image – it would just disappear and the new one would appear. It was almost like something else was there. Looking back at my ‘raw’ HTML code in the WordPress post, I had all three images in sequential order, but neatly aligned by pressing enter after each. What I didn’t know was that WordPress, even in HTML mode, was adding <br /> tags after I pressed enter, causing this problem.
Solution: Make the <img> tags back to back on the same line, thus removing the automatically generated <br /> tags.
It appears that with the latest update, Twitter has replaced their dock icon from the original sleek black color to a brighter blue. I really liked the original black, so this is how I went back to it.
1. Download the original icon here
2. Open up Applications and find the Twitter app
3. Right-click the app and select ‘Show Package Contents’
4. Go to Contents, then Resources
5. Locate ‘Icon.icns’ then copy and paste itself in the same folder (this is optional, but we’re creating a backup)
6. Put in your password if prompted
7. Take the file you downloaded in step 1 and paste it into the same folder
8. Click ‘Replace’ when prompted
9. Put in your password if prompted
10. Move the Twitter app out of the dock, then load it up
You’re done! You should now have the original black Twitter app icon.
Keep in mind that with any future updates, you’ll probably have to repeat this process.
Here’s a little Python script I cooked up for work. We often have to change the custom LCD string on boxes if the machine is given a new name. Before, we’d have to restart a machine to access the DRAC configuration to change the name. With this script, all you have to do is enable IPMI through the DRAC remotely (if it isn’t already enabled), and know the correct credentials.
If the LCD isn’t set to view the custom string, you should be able to change it from the front of the box. As you can see, the function that I have commented out at the bottom is supposed to do this for you, but I never got it to work.
2023 update: Check out Pierre’s solution which properly sets the mode!
You may have to change ‘/usr/sbin/ipmitool’ to your appropriate path.
#!/usr/bin/python import os # Tanner Stokes - tannr.com - 2-26-10 # This script changes the LCD user string on Dell machines that conform to IPMI 2.0 sp_hostname = raw_input ("\nEnter DNS or IP of SP: "); user_string = raw_input("Enter LCD string: ") hex_string = "" for x in user_string: hex_string += hex(ord(x)) # add space between each hex output hex_string += " " print '\nTrying to change LCD string on '+sp_hostname+'...' return_val = os.system('/usr/sbin/ipmitool -H '+sp_hostname+' -I lan -U root raw 0x6 0x58 193 0 0 '+str(len(user_string))+' '+hex_string) if (return_val == 0): print 'LCD string changed successfully.\n' else: print '\nNon-zero return value, something went wrong.' print 'Make sure IPMI is enabled on the remote host and the DNS or IP is correct.\n' # this function supposedly sets the user string to show on the LCD, but never got it to work # this can be changed from the front of the box anyway # os.system('/usr/sbin/ipmitool -H '+sp_dns+' -I lan -U root raw 0x6 0x58 194 0')
6-6-12 – This script is really old and may not work with current versions of Growl. There are some good libraries to choose from and I’d recommend looking at them instead.
Updated 12-4-10 – minor code updates
I have yet another script. This one is actually my first one in Python, which is kind of sad after all the good things I’ve heard about the language. This time I didn’t actually write the entire script – I simply added to one that had already been written to give it more functionality.
The original script was found here: http://the.taoofmac.com/space/Projects/netgrowl and almost all credit goes to it’s author, as I only added a little bit more to it.
What this version does is send a Growl message over UDP to a Mac (running Growl and configured to listen for incoming notifications) using Python. I thought this was really cool – I could script my remote Linux machines (or whatever OS) to send messages to my main Mac.
What I added was the ability to have command line arguments so that it would be easier to change options on the fly and also easier to script.
Running ./netgrowl.py -h
will give you the following:
#!/usr/bin/env python # Updated 12-4-2010 # Altered 1-17-2010 - Tanner Stokes - www.tannr.com # Added support for command line arguments # ORIGINAL CREDITS # """Growl 0.6 Network Protocol Client for Python""" # __version__ = "0.6.3" # __author__ = "Rui Carmo (http://the.taoofmac.com)" # __copyright__ = "(C) 2004 Rui Carmo. Code under BSD License." # __contributors__ = "Ingmar J Stein (Growl Team), John Morrissey (hashlib patch)" try: import hashlib md5_constructor = hashlib.md5 except ImportError: import md5 md5_constructor = md5.new import struct # needed for command line arguments import sys import getopt from socket import AF_INET, SOCK_DGRAM, socket GROWL_UDP_PORT=9887 GROWL_PROTOCOL_VERSION=1 GROWL_TYPE_REGISTRATION=0 GROWL_TYPE_NOTIFICATION=1 def main(argv): # default to sending to localhost host = "localhost" # default title title = "Title" # default description description = "Description" # default priority priority = 0 # default stickiness sticky = False # if no arguments are given, show usage if(len(argv) < 1): usage() try: opts, args = getopt.getopt(argv, "hH:t:d:p:s") except getopt.GetoptError: usage() for opt, arg in opts: if opt in ("-h"): usage() elif opt in ("-H"): host = arg elif opt in ("-t"): title = arg elif opt in ("-d"): description = arg elif opt in ("-p"): # acceptable values: -2 to 2 priority = int(arg) elif opt in ("-s"): sticky = True # connect up to Growl server machine addr = (host, GROWL_UDP_PORT) s = socket(AF_INET,SOCK_DGRAM) # register application with remote Growl p = GrowlRegistrationPacket() p.addNotification() # send registration packet s.sendto(p.payload(), addr) # assemble notification packet p = GrowlNotificationPacket(title=title, description=description, priority=priority, sticky=sticky) # send notification packet s.sendto(p.payload(), addr) s.close() def usage(): print """Usage: ./netgrowl.py [-hs] [-H hostname] [-t title] [-d description] [-p priority] Send Growl messages over UDP -h help -H specify host -t title -d description -p priority [-2 to 2] -s make sticky""" sys.exit(1) class GrowlRegistrationPacket: """Builds a Growl Network Registration packet. Defaults to emulating the command-line growlnotify utility.""" def __init__(self, application="NetGrowl", password = None ): self.notifications = [] self.defaults = [] # array of indexes into notifications self.application = application.encode("utf-8") self.password = password # end def def addNotification(self, notification="Command-Line Growl Notification", enabled=True): """Adds a notification type and sets whether it is enabled on the GUI""" self.notifications.append(notification) if enabled: self.defaults.append(len(self.notifications)-1) # end def def payload(self): """Returns the packet payload.""" self.data = struct.pack( "!BBH", GROWL_PROTOCOL_VERSION, GROWL_TYPE_REGISTRATION, len(self.application) ) self.data += struct.pack( "BB", len(self.notifications), len(self.defaults) ) self.data += self.application for notification in self.notifications: encoded = notification.encode("utf-8") self.data += struct.pack("!H", len(encoded)) self.data += encoded for default in self.defaults: self.data += struct.pack("B", default) self.checksum = md5_constructor() self.checksum.update(self.data) if self.password: self.checksum.update(self.password) self.data += self.checksum.digest() return self.data # end def # end class class GrowlNotificationPacket: """Builds a Growl Network Notification packet. Defaults to emulating the command-line growlnotify utility.""" def __init__(self, application="NetGrowl", notification="Command-Line Growl Notification", title="Title", description="Description", priority = 0, sticky = False, password = None ): self.application = application.encode("utf-8") self.notification = notification.encode("utf-8") self.title = title.encode("utf-8") self.description = description.encode("utf-8") flags = (priority & 0x07) * 2 if priority < 0: flags |= 0x08 if sticky: flags = flags | 0x0100 self.data = struct.pack( "!BBHHHHH", GROWL_PROTOCOL_VERSION, GROWL_TYPE_NOTIFICATION, flags, len(self.notification), len(self.title), len(self.description), len(self.application) ) self.data += self.notification self.data += self.title self.data += self.description self.data += self.application self.checksum = md5_constructor() self.checksum.update(self.data) if password: self.checksum.update(password) self.data += self.checksum.digest() # end def def payload(self): """Returns the packet payload.""" return self.data # end def # end class if __name__ == '__main__': # send command line arguments to main() function main(sys.argv[1:])
I played around tonight with making my iPod touch an auxiliary display. I thought it may be neat to just have random real-time public tweets cycle through on it so I made the following. As you can see there’s nothing too smooth about it yet – no AJAXiness implemented as this was purely proof of concept.
I think this is pretty cool for a Happy Meal toy…