SysAdmin's Journey

User-level Configuration of CPU Speed in Gnome Under Ubuntu

When I ran Fedora on my laptop, I loved how I could manually set the CPU speed in Gnome using the “CPU Frequency Scaling Monitor” applet.  I noticed that I could not do this under Ubuntu (you can monitor speed, but you can’t change it). It’s actually a feature, not a bug.  In order to change CPU frequency, the binary needs to be SUID, which Ubuntu doesn’t enable by default.  In order to change this behavior, run the following: sudo dpkg-reconfigure gnome-applets

Answer “Yes” to the question regarding cpufreq-selector.  You will immediately get the ability to change your CPU frequency - no reboot, no restart of Gnome, not even the applet needs restarted!

The Power and Simplicity of ELOG

Follow the jump to read more about ELOG, the best little logbook available! When I read the LifeHacker article about how to simplify troubleshooting with a ChangeLog, I immediately thought about one of my favorite webapps - ELOG. Written by Stefan Ritt, ELOG aims to be simple, self-contained, performant, and extendable. It achieves all of these goals and surpasses them. ELOG is written in C, and is it’s own webserver. No need to run Apache, it’s got it’s own. It’s single threaded, but for what it is, one thread is enough. We use it to keep track of our servers at work, we have a ServerLog logbook. We also use it as a Change Request management tool. It has done both for us without a hiccup, let alone a crash in the two years we’ve used it. A feature request I made to Stefan was implemented that same week! Anyways, if you’re looking for an application to log entries of data over time, look no further than ELOG!

Quick and Easy Apache SSL on CentOS

Follow the jump to find out how you can quickly and easily setup your own SSL certificate and install it into Apache on CentOS/RHEL. First, we need to install the crypto-utils package, which gives us the super-handy genkey command.  We’ll also pull in mod_ssl at the same time: yum install crypto-utils mod_ssl

With that out of the way, let’s run genkey for our sample domain, genkey –days=3650

  1. Click Next
  2. Highlight “1024”, click Next
  3. Click No
  4. Fill in the form fields, making sure that the Common Name is the name you’ll be typing in your browser’s URL bar.  Click Next
  5. Don’t select “Encrypt the private key” unless you want to type in the passphrase every time you start Apache.  Click Next.

Now, we have our keys generated, we just need to tell Apache to use them.  Please note:The SSLCertificateFile changes the file extension from crtto cert! SSLCertificateFile /etc/pki/tls/certs/ SSLCertificateKeyFile /etc/pki/tls/private/

Restart Apache, and test it out!

Simple and Effective Apache+MySQL Backups for Your Blog/CMS

As part of setting up my new Linode host, I needed a quick, easy, and maintanable way to create backups of my LAMP webapps.  Follow the jump to see how I set up my backup strategy.

DISCLAIMER: I make no guarantees to the effectiveness of this script. It works for me, and it should work for you, but it is up to you to test it! Also note, you need to have SSH access and root privileges to your server.

I needed a quick way to get a backup strategy in place that would create a daily snapshot of my Wordpress and Drupal code and MySQL databases.  Basically, I keep a 7 day rotation of each webapp’s code and MySQL, so that if I do something to break my app, I can at least restore it back to the previous day’s state.  Also, before I install a new plugin or hack on a theme, I can create a snapshot by firing off one script.

I had an advantage since I was starting things from scratch - I could name things consistently.  One of the assumptions that is made is that the directory name of the Apache DocumentRoot of your webapp is the same as the name of your MySQL database.  Obviously, you can’t go changing your MySQL db names around very easily, but you can use symbolic links to make your document root’s have the same name as your DB.

First, let’s setup our hypothetical webapp, which will be a wordpress blog.  We’ll call it MySite_wp.  For the purpose of this example, we have a directory /apps/MySite_wp which is the document root for the Wordpress installation.  There is a directory named /apps/snapshots/ where we will store our daily snapshots of our document root, and a directory named /apps/mysqlbackups/ where we will store our MySQL database backups.  Finally, our custom scripts will be stored in /apps/scripts.

Step One: Backup MySQL

First, let’s setup our script that does our MySQL backup.  This is a shell script that I wrote because the scripts offered by Zmanda were a little overkill for what I wanted.  I therefore came up with my own shell script that will backup any db you specify on the command line.  Let’s create this script, and name it /apps/scripts/


#set -x


cmp_versions() {
   [ "$1" == "$2" ] && return 10

   ver1front=`echo $1 | cut -d "." -f -1`
   ver1back=`echo $1 | cut -d "." -f 2-`
   ver2front=`echo $2 | cut -d "." -f -1`
   ver2back=`echo $2 | cut -d "." -f 2-`

   if [ "$ver1front" != "$1" ] || [ "$ver2front" != "$2" ]; then
      [ "$ver1front" -gt "$ver2front" ] && return 11
      [ "$ver1front" -lt "$ver2front" ] && return 9

      [ "$ver1front" == "$1" ] || [ -z "$ver1back" ] && ver1back=0
      [ "$ver2front" == "$2" ] || [ -z "$ver2back" ] && ver2back=0
      cmp_versions "$ver1back" "$ver2back"
      return $?
      [ "$1" -gt "$2" ] && return 11 || return 9

get_dump_opts() {
  cmp_versions "$VERSION" "4.1.0"
  if [ $RV -eq 9 ]; then
    MYDUMP="$MYDUMP --skip-lock-tables --all"
    cmp_versions "$VERSION" "4.1.2"
    if [ $RV -eq 11 ]; then
      MYDUMP="$MYDUMP --default-character-set=utf8 --create-options"
      MYDUMP="$MYDUMP --default-character-set=utf8 --all"

SCRIPTDIR=`dirname $0`
if [[ "$SCRIPTDIR" == "." || -z "$SCRIPTDIR" ]]; then
MYDUMP="$MYSQLBIN/mysqldump --user=$USER --password=$PASS --opt --extended-insert \

VERSION=`$MYSQLBIN/mysqladmin --user $USER --password=$PASS version | \
 grep "Server version" | awk '{ print $3; }'`

if [ -z "$1" ]; then
  echo "I need a database to back up!!!"
  exit 1


while [ ! -z "$1" ]; do
   touch $DEST/$DB.sql
   chmod 400 $DEST/$DB.sql
   #Version specific dump
   $MYDUMP $DB > $DEST/$DB.sql
   if [ $? -ne 0 ]; then
     echo "MySQL Dump of $DB had an error!"
     exit 1

$MYSQL --user=$USER --password=$PASS \

if [ $? -ne 0 ]; then
  echo "MySQL log purge had an error!"
  exit 1

if [ ! -e $LOGROTATECFG ]; then
# Rotate MySQL backups
$DEST/*.sql {
   rotate 7

if [ ! -x $LOGROTATE ]; then
  echo "Logrotate not executable, skipping rotation"
  exit 1
  if [ $? -ne 0 ]; then
    echo "Logrotate had an error!"
    exit 1

Now, make sure you edit the variables at the top of this script to your installation. Since this script contains the root password to your MySQL install, run

chmod 700 /apps/scripts/

to make it so only the root user can view the password.

Now, let’s test the script. Jump out to a command prompt, and run ‘/apps/scripts/ MySite_wp’. Once that’s done, look in the /apps/mysqlbackups/archives directory, and you should see a gzipped sql file sitting there. Step one, done!

Step Two: Backup the Document Root

Now, we need to setup the script that will backup our actual files (usually php files). Now, most of us have very little data that actually changes from day to day in our PHP files. Most of the dynamic data is stored in the database. So, to prevent wasting a bunch of space backing up the exact same file multiple times, we will leverage the hard linking feature of rsync. Please note that this script is not my own, the majority of the code comes from Mike Rubel’s site. Now, create the file /apps/scripts/, and put this code in it:


unset PATH


# ------------- system commands used by this script --------------------


# ------------- file locations -----------------------------------------


# ------------- the script itself --------------------------------------

# make sure we're running as root
if (( `$ID -u` != 0 )); then { $ECHO "Sorry, must be root.  Exiting..."; exit; } fi

#Check our args
if [ -z "$SOURCE_DIR" ]; then
  $ECHO "Please pass a source directory as argument 1!";
  exit 1;

if [ -z "$SNAPSHOT_DIR" ]; then
  $ECHO "Please pass a source directory as argument 1!";
  exit 1;

#Check our DIR's
if [ ! -d $SOURCE_DIR ]; then
  $ECHO "$SOURCE_DIR is not a directory!";
  exit 1;

if [ ! -d $SNAPSHOT_DIR/ ]; then

if (( $? )); then
    $ECHO "snapshot: could not create directory $SNAPSHOT_DIR";

#Account for backup.0
let KEEP=$KEEP-1

for i in `$SEQ $KEEP -1 0`; do
  # Delete the last rotation
  if [ $i == $KEEP ]; then
    $RM -rf $SNAPSHOT_DIR/daily.$i
    # shift the middle snapshots(s) back by one, if they exist
    let NEXT=$i+1
    if [ -d $SNAPSHOT_DIR/daily.$i ] ; then         \
      $MV $SNAPSHOT_DIR/daily.$i $SNAPSHOT_DIR/daily.$NEXT

CMD="$RSYNC -a --delete --delete-excluded "
CMD="$CMD --link-dest=$SNAPSHOT_DIR/daily.1 "

if [ ! -d $SNAPSHOT_DIR/daily.0 ]; then
  $MKDIR -p $SNAPSHOT_DIR/daily.0

eval $CMD

Now, do a ‘chmod 755 /apps/scripts/’ and let’s test it out. Run ‘/apps/scripts/ MySite_wp’. Once completed, have a look in /apps/snapshots/MySite_wp/. You will have a directory named daily.0 that will contain a snapshot of your application. If you run the same command again, the current daily.0 contents will be moved over to daily.1, and a new snapshot will be stored in daily.0. This will complete until you have 7 such daily directories, at which point the oldest will be deleted before the newest is created. By using hard links, only if a file changes will it actually consume space on your hard drive. Step two, complete!

Step Three: Tie It All Together

Now, for the easy part. Let’s tell cron to perform a backup each night. Create the file /etc/cron.daily/, and put this text in there:


WEBAPPS=( MySite_wp )

for WEBAPP in ${WEBAPPS[@]}; do
    /apps/scripts/ $WEBAPP
    /apps/scripts/ /apps/$WEBAPP/ /apps/snapshots/$WEBAPP/

Now, run ‘chmod 755 /etc/cron.daily/’, and you will have a backup of your MySite_wp applicaton! What’s best, is let’s say you add a Drupal application, you name your MySQL database MySite_Drupal, and your document root is a /apps/MySite_Drupal. All you need to do is change line 3 of to look like this:

WEBAPPS=( MySite_wp MySite_Drupal )

and you will get a backup of your Drupal install the following night too!


Heaven forbid, you’ve made a critical mistake, installed a bad plugin, or something else that’s horribly broken your MySite_wp install. No fear! Here’s how to restore it.

mkdir /apps/MySite_wp-broken && mv /apps/MySite_wp/* /apps/MySite_wp-broken/
rsync -avz /apps/snapshots/MySite_wp/daily.0/* /apps/MySite_wp/
gzip -dc /apps/mysqlbackups/archives/MySite_wp.sql.1.gz > /tmp/mysite.sql
mysql -u root -p MySite_wp < /tmp/mysite.sql
rm /tmp/mysite.sql

and viola! Your site is back as it was at the time of the last backup.

Offsite Backup

To ensure safety, you should then backup your /apps/snapshots and your /apps/mysqlbackups directories to someplace offsite. I recommend rsync for this as well. Stay tuned for a post on how to do this!

Linode Review

I recently switched from shared Unix hosting to Linode Xen-based VPS hosting. Follow the jump to read my reviews of both. I had a shared Unix account with for about a year. Aplus used FreeBSD with jails to provide their shared hosting. While that gave me the ability to ssh into the box, I could not get root. It did however, work quite well - the control panel is nice, and you could use about anything you wanted to. I never needed to use their support, their control panel worked great, and I never had any issues with billing. There were two drawbacks, one minor, the other major: 1. The box was firewalled to death. I’m all for firewalls, but I like to be in control of it. Not only were inbound ports blocked (which is a good thing), but all outbound access was blocked as well. This made hard things impossible, and easy things hard. For example, adding a simple RSS widget to your page hosted on Aplus just will not work. 2. The particular box I was on was severely over-sold. I have no idea how many shared accounts there were on the box, but there were times where my simple little wordpress blog was completely unavailable. $12 a month is cheap, but I at least expect to be able to render pages!

After doing a bunch of research, my choice for a new hosting provider was down to Linode and SliceHost. In the end, I settled on Linode because I was reading some grumblings that SliceHost was having some growing pains, and I couldn’t find any negatives to Linode. So, at 10:57pm on July 30th, I started the sign up process for a Linode 540 in their Dallas datacenter. At 11:07pm that night (10 minutes later!) I had full access to my server. Very impressive! By 11pm on July 31st, I had moved my blog from Aplus to Linode without any hitches. First, let me tell you what Linode is and isn’t. - Linode isa provider of Xen-based virtualized hosts. This means you get to pick which distribution you want, and you get your own root account with which you can do what you feel like. - Linode providesa DNS Manager included with all their plans that allows you have full control over any number of domains. I had no idea this existed until I signed up, and it was a great little side benefit. I was able to cancel my DNS service at a registrar that I was paying $15 a year for. - Linode providesyou with a Xen instance with 4 cores of Xeon for CPU, and a configurable amount of RAM, bandwidth, and storage. - Linode providesa out-of-band management tool named lish (LInode SHell) which gives you console level access to your server.  There is also an AJAX web-based console interface available. - Linode providesyou with everything you need to build your own server. You may do with this server what you like, provided it’s for law-abiding activities. You have the ability to create your own partitions, upgrade your kernel, install packages, whatever! - Linode providesyou with more than enough rope with which you can hang yourself! This is a logical extension of the above point. If you have root, you can most certainly do a ‘rm -rf /’ and no one will stop to ask you if you’re sure or not. - Linode is notyour run-of-the-mill webhoster. If you want to run your own LAMP stack, you are more than welcome to do so. However, youare responsible for the setup and maintanence of the entire stack. There’s no cute little control panel button you click to setup a blog. If you don’t know Linux, and don’t want to learn how to do these sort of things, you’re better off with a provider such as

After signing up, you get to pick which data center you want your server to be hosted in.  Here are their current datacenters: - Newark, NJ - Atlanta, GA - Dallas, TX - Fremont, CA

You can view what servers are available in what datacenters here. Here are some of Linode’s support options: - A quick FAQ - A Wiki - A public support forum which employees take part in regularly - An IRC channel - A support ticket system for active customers - There is a phone number posted on their site, but I don’t think it’s intended to be used for support issues.

After just two days of running my own Linode, I must say that I’m thoroughly impressed. Uptime is 100%, and I haven’t needed support for anything at all. My blog runs as it should - and if it didn’t it would be my fault for not setting it up properly. I will update this post in the future with more data as I learn more about the service. Also, if you’d like to give Linode a try and have enjoyed this post, consider visiting their site by clicking on any of the Linode links present in this post. They contain a referral code that will give me $20 credit if you sign up and stay a customer for 30 days.

Using Sun's Java (Jdk) With Eclipse on Ubuntu

Let’s face it, if you’re reading this article, you know what Eclipse is, and what you’re trying to do.  Follow the jump for how to do it. First, install Sun’s Java 6 jdk, and Eclipse: sudo apt-get install eclipse sun-java6-jdk

Now, set up the newly installed jdk as the system default: sudo update-java-alternatives -s java-6-sun

Next, set your default jvm: sudo vim /etc/jvm

and add this line at the top of the file: /usr/lib/jvm/java-6-sun

Now, that should do the trick, but the Eclipse packaged with Ubuntu is packaged to prefer GCJ.  Let’s fix that: sudo vim /etc/eclipse/java_home

and again add this line at the top of the file: /usr/lib/jvm/java-6-sun

Finally, while you’re at it, bump up your Xms here: sudo vim /usr/lib/eclipse/eclipse.ini

Dnsmasq + Dhclient

I needed to be able to use dnsmasq on my laptop so that I could forward corporate hostname requests to our corporate DNS servers, but send all other requests to OpenDNS' servers.  Sometimes at a hotel, you can’t use OpenDNS, so I also wanted to fail back to whatever DNS servers were being sent via DHCP. The trick here is to get dhclient to update a file other than /etc/resolv.conf.  You tell dhclient to update a file named /etc/resolv.conf.dhclient, then point /etc/resolv.conf to use localhost.  Finally, tell dnsmasq to use /etc/resolv.conf.dhclient as its source.  Here’s how I did that on Ubuntu 8.04: First, install dnsmasq:

sudo apt-get install dnsmasq resolvconf

Next, set the following in /etc/dnsmasq.conf: … resolv-file=/etc/resolv.conf.dhclient server=/ …

Then restart dnsmasq: sudo /etc/init.d/dnsmasq restart

Now, configure your local machine to use a hardcoded  DNS server of  I use NetworkManager, so I left click on the NM icon, and select “Manual configuration…”.  Click the DNS tab, then click the unlock button.  Remove any existing servers in “DNS Servers”, then add  Optionally, add any search domains you might want to use. Now, we need to tell dhclient to a) prepend OpenDNS' servers to the nameserver list, and b) write the DNS config to /etc/resolv.conf.dhclient instead of /etc/resolv.conf.  First, edit /etc/dhcp3/dhclient.conf, and add the line: prepend domain-name-servers,;

Now, for the part that I couldn’t find using Google.  Let’s tell dhclient to update a different file:

sudo cat   > /etc/dhcp3/dhclient-enter-hooks.d/dnsmasq <<EOD


make_resolv_conf() {
  if [ -n "$new_domain_name_servers" ]; then
    [ -n "$new_domain_name" ] && echo search $new_domain_name >$CUSTOM_RESOLV_CONF
    for nameserver in $new_domain_name_servers; do
      echo nameserver $nameserver >> $CUSTOM_RESOLV_CONF

Now, set it to be executable: sudo chmod 755 /etc/dhcp3/dhclient-enter-hooks.d/dnsmasq

Now, reboot.  When you reboot, you should have the following setup: 1. When you get a DHCP lease, the new DNS config will be written to /etc/resolv.conf.dhclient 2. This file will first contain the two OpenDNS servers, then whatever the ISP/Router sends as nameservers 3. /etc/resolv.conf will point to localhost and should never change. 4. Any requests for will go to the 10.x nameservers above 5. Any requests for any other domains will first be tried through OpenDNS, then through the ISP’s/Router’s nameservers.

Hope this helps you as much as it helped me!

Per-subnet Routing With Solaris 10 Non-global Zones

I had the chance to finally tinker with Solaris 10 zones the other day. They are impressive - very easy to setup! One of my biggest gripes about Solaris is that they've fallen way behind in the area of advanced IP routing. If you want to do things like policy routing in Solaris, you have to install ipfilter, which is no easy task. There is no alternative to iproute2 in Linux. Read after the jump to find a quick hack to setup proper routing for non-global zones on multiple subnets. Update: If you are using Solaris 10 Update 4 or newer, you may be able to use set ip-type=exclusive in your zone config. This will give you what I've hacked together here. Note, that you must have a dedicated interface for the zone in order to use it, and there are some other limitations, described here. Keep an eye on project Crossbow, which will hopefully make all of this go away. In Solaris 10, you set the default gateway at boot time by using /etc/defaultrouter. You can add multiple default routes by adding multiple lines to that file. However, if you do that, the kernel will simply round-robin the packets between the gateways, which will light up any firewall like a Christmas tree. Imagine the following scenario: HostA is a Solaris 10 box with 4 bge interfaces. HostA's IP address is and is assigned to bge0. The router for the subnet is at HostB is a non-global zone residing on HostA, with an IP address of and you've assigned it to bge1 via zonecfg. The router for the subnet is at Now, non-global zones don't have their own kernel, they "share" with the global zone. IP routing is handled in the kernel, so the routing configuration for the non-global zone needs to be done in the global zone. The first trick here is to get bge1 to come up on bootup, but not assign it an IP. Do this as root on HostA to establish that:

# echo "" > /etc/hostname.bge1

This will plumb and bring up the interface, but it will not be assigned an IP. Now, remember what I said about the kernel round-robin routing packets earlier? It will only do that if both gateways are reachable. So, the trick is to make HostB's gateway unreachable from HostA, and HostA's gateway unreachable from HostB. There's a catch-22 here as well, you can only add a default route if the gateway is currently reachable. So how in the world do we get this to work??? With some nice hackery, of course! First, set HostB's configuration so that it does not boot automatically. Don't worry if you need this functionality, we've got a hack for that too:

root@HostA # zonecfg -z HostB
zonecfg:HostB> set autoboot=false
zonecfg:HostB> verify
zonecfg:HostB> commit
zonecfg:HostB> exit

Now, we are going to create our own init script that will bring up bge1 temporarily with HostB's IP, set the default route, then remove that IP. By using HostB's IP, we are allowed to set the route, but when we remove the interface, HostB's gateway becomes unreachable from HostA. Finally, we boot HostB, which sees only the default route for it's interface. Let's setup that init script:

# cat <<EOD > /etc/init.d/zoneboot

/usr/sbin/ifconfig bge1 addif up
/usr/sbin/route add default
/usr/sbin/ifconfig bge1 removeif
/usr/sbin/zoneadm -z HostB boot

# ln -s /etc/init.d/zoneboot /etc/rc3.d/S99zoneboot

You can of course modify this script to work with more interfaces and zones, but you get the idea. Now, reboot HostA. HostA's routing table looks like so:

# netstat -rn

Routing Table: IPv4
  Destination           Gateway           Flags  Ref     Use     Interface
default              UG       1        119
default              UG       1        112          U        1         35 bge0            U        1          0 bge0               UH       4        113 lo0

HostA has two default gateways, but only one of them is reachable. Bingo! HostB's routing table looks like this:

Routing Table: IPv4
  Destination           Gateway           Flags  Ref     Use     Interface
default               UG      1        112           U       1         27 bge1:1             U       1          0 bge1:1                UH      4        108 lo0:2

Success! Hope you found this helpful!

Forcing NIC Speed and Duplex on Solaris 10

There are two ways to force duplex & speed on a Solaris 10 box - via the driver, and via ndd. First, via the driver:

# cat
<<EOD > /platform/`uname -i`/kernel/drv/bge.conf adv_autoneg_cap=0
adv_1000fdx_cap=0 adv_1000hdx_cap=0 adv_100fdx_cap=1 adv_100hdx_cap=0
adv_10fdx_cap=0 adv_10hdx_cap=0; EOD

Note that this sets all instances of bge to 100Mbit Full Duplex. If you wish to be more selective, you can do this:

# cat < /etc/init.d/net-tune
#!/bin/sh # Force to 100FDX NIC=bge for i in 0 1 2 3; do /usr/sbin/ndd -set
/dev/${NIC}${i} adv_1000fdx_cap 0 /usr/sbin/ndd -set /dev/${NIC}${i}
adv_1000hdx_cap 0 /usr/sbin/ndd -set /dev/${NIC}${i} adv_100fdx_cap 1
/usr/sbin/ndd -set /dev/${NIC}${i} adv_100hdx_cap 0 /usr/sbin/ndd -set
/dev/${NIC}${i} adv_10fdx_cap 0 /usr/sbin/ndd -set /dev/${NIC}${i}
adv_10hdx_cap 0 /usr/sbin/ndd -set /dev/${NIC}${i} adv_autoneg_cap 0 done EOD
# chmod 755 /etc/init.d/net-tune # ln -s /etc/init.d/net-tune /etc/rc2.d

You have to reboot for the kernel config file to take effect, but you can run the net-tune script at any time to make it work. You can change the 0 1 2 3 in the for do loop above to set the instances you need.

Legend Micro

This issue did finally get resolved and Paypal didn’t need to step in. I’m going to remove any editorial remarks, and just leave the factual emails here. If you do have any problems, I would recommend getting Simon involved, he was prompt and professional - Justin I bought what was listed as a “Hauppage PVR-150 MCE PCI Card”, and received something compeletely different. Below is a copy and paste of all my communications with them. On 4/23, I sent my first email to them: Dear legendmicro-wholesale, I just received my tuner card, and it’s not as the auction implied. It is not compatible with with the WinTV-PVR-150 MCE PCI #1042, it’s a completely different card with different inputs, outputs and chipsets. I run MythTV on Linux, and there are no drivers for this card. I would gladly exchange this card for a “true” WinTV PVR 150. If you don’t have one, I will need to get a refund. -techadvise Later, on 4/23, they responded via eBay: We do not advertize this card as being Linux compatible. If you would like to return this card: PLEASE CONTACT OUR CUSTOMER SERVICE please use link below to file an RMA -legendmicro-wholesale Okay, fair enough. I didn’t really go into all the details about how their auction was completely incorrect. So, I did that next. On 4/24, I sent them this via eBay: Dear legendmicro-wholesale, I can contact your customer service, but I don’t think you understand just how incorrect your listing is. Here are the major points: - The title reads “Hauppauge WinTV-PVR-150 MCE PCI Tuner Card”. This card doesn’t have anything at all in common with a Hauppage card. It is a Emuzed Maui I/II, and is described in detail here: The auction states the card has an FM Tuner, it does not. The auction says it has a composite video input, and the card does not. These are just the major points. I need to either have a card that fits the auction description sent to me free of charge, or I can return this card for a refund. I don’t think I should be responsible for paying freight in either direction as I would not have bid on the auction if the listing was correct. Please confirm that I will receive either a replacement or a full refund. Justin -techadvise To which they replied on 4/24: Dear techadvise, Justin, You will need to contact customer service to proceed with the RMA. PLEASE CONTACT OUR CUSTOMER SERVICE please use link below to file an RMA -legendmicro-wholesale So, on 4/28, I send them this via eBay: Dear legendmicro-wholesale, I contacted customer service on April 24th at 4:30, and still haven’t heard back yet. If we don’t have a plan in place by tomorrow at noon, I’m just going to start working with Paypal/Ebay to get my money refunded. Justin -techadvise To which Legend Micro replied on 4/28: Dear techadvise, PLEASE CONTACT OUR CUSTOMER SERVICE please use link below to file an RMA -legendmicro-wholesale Gosh, that looks a lot like their last message. So, I got a little frustrated, and sent them this back via eBay on 4/28: Dear legendmicro-wholesale, IF YOU READ MY PREVIOUS MESSAGE YOU WOULD KNOW THAT I HAVE! Thanks for making my decision easy. Enjoy your negative feedback. -techadvise To which they replied on 4/28: Dear techadvise, RMAs are processed in the order that they are received. Sometimes it can take up to 2 business days to process an RMA. If you would like to talk to someone regarding your RMA, please call customer service 800-935-9305 x3 -legendmicro-wholesale At this point, I opened a case with Paypal. Here’s what I posted to Paypal on 4/28 to initiate a dispute: I bid on and won eBay item #260231153044 a “Hauppauge WinTV-PVR-150 MCE PCI Tuner Card”. What I received was a TV tuner card, but nothing close to the specifications set forth in the auction. The auction title reads “Hauppauge WinTV-PVR-150 MCE PCI Tuner Card”. This card doesn’t have anything at all in common with a Hauppage card. It is a Emuzed Maui I/II which is a cheap knock-off of the Hauppage. The auction states the card has an FM Tuner, it does not. The auction says it has a composite video input, and the card does not. I have sent email to the seller 4 times. Each time, he replies with the same copy & paste answer: — PLEASE CONTACT OUR CUSTOMER SERVICE please use link below to file an RMA — When I go to the above site, the RMA procedure states that I will be liable for S&H, which I don’t believe I should be. I emailed the customer service address listed on his site on 4/24, and have yet to hear back. As I have explained to the seller, I am willing to accept either a full refund of $49 or a true Hauppage PVR-150 MCE PCI card. I will gladly ship the seller’s card back to him at his expense. Metaphorically speaking, I bid on an American sports car, and recieved a British 4 door sedan with the steering wheel on the opposite side. Sure, it’s a car, but it’s unusable to me, and doesn’t even come close to matching the original description. On 4/29, the seller updated the Paypal case: dear customer, we apologize for inconvinience,we never received the RMA request from you, please close the dispute, you will be issued RMA # and pre-paid shipping label and you will be refunded in full as soon as we will get the product back in stock, for any questions, please call our customer service 800-935-9305 ext 3-Kat, thank you Immediately after receiving that message, I filled out the RMA form on their site, and put Kat’s email above in the notes field. I immediately got an autoreply stating that my request had been received. On 4/30, I get this via my personal email account, bypassing eBay and Paypal: Dear customer, we apologize for inconvenience, we never received the RMA request from you, please close the dispute, you will be issued RMA # and pre-paid shipping label and you will be refunded in full as soon as we will get the product back in stock, for any questions, please call our customer service 800-935-9305 ext 3-Kat, thank you Thank You for Your Business Kat (Customer service) 30700 Carter Street STE B Solon, Ohio 44139 440-776-8839 Direct Voice 800-935-9305 Ext. 3 440-498-0706 Fax On 4/30, I replied back to Kat directly: Kat, My apologies, but since the dispute seems to be my only way to get a quick response from your company, I’m going to keep it open until the issue is resolved. I never submitted an RMA request before, I simply emailed with questions that I never received a response to. However, I did submit an RMA form last night, and got an autoreply, but nothing else after that. My request number is 501014. Thanks, Justin On 5/1, I received this update to the Paypal dispute case: please close dispute and call 800-935-9305 ext 3 On 5/1, I update the Paypal case with the recent communications, and set forth an ultimatum: As I stated in my email to you yesterday, I will not close this dispute until my dispute is resolved. It is not. I have filled out your RMA form, and received a request number of 501014. I have not received an RMA number, nor a pre-paid shipping label. Since your priority seems to be getting me to close this dispute without actually resolving the problem, I’m going to mandate that all future communications take place through Paypal for third-party documentation - I will not call you. Once I recieve an RMA number and a prepaid shipping label, I will ship the part back to you. Once my paypal account is refunded, I will close this dispute. UNTIL THAT POINT IN TIME, I WILL NOT CLOSE THIS DISPUTE! Please stop asking me to do so. We have 17 days to get this resolved before I file a claim. I suggest you stop trying to get me to close the dispute and get around to sending me that RMA number and shipping label that you’ve been promising me for 3 days now. Justin After updating the case, Kat emailed me at my personal email account on 5/1: As soon as we will see the dispute closed, you will be emailed RMA # along with prepaid shipping label and we do have the right item in stock for you. Thank You for Your Business Kat (Customer service) 30700 Carter Street STE B Solon, Ohio 44139 440-776-8839 Direct Voice 800-935-9305 Ext. 3 440-498-0706 Fax I updated the case with paypal with this: Paypal, Kat from LegendMicro just emailed my personal email account, disregarding my request to stop communicating “out of band”. Directly quoting her entire email: —BEGIN QUOTE— As soon as we will see the dispute closed, you will be emailed RMA # along with prepaid shipping label and we do have the right item in stock for you. Thank You for Your Business Kat (Customer service) 30700 Carter Street STE B Solon, Ohio 44139 440-776-8839 Direct Voice 800-935-9305 Ext. 3 440-498-0706 Fax —END QUOTE— It is obvious to me that the seller is not concerned with customer service, only with closing this dispute. Probably so that they can string me along further without a deadline hanging over them. It’s my opinion that I’ve done everything I can to facilitate fair commerce between myself and the seller, and that the seller has done nothing to try and resolve the issue. To date, I have still never received an RMA number, nor a shipping label. I give up. They have done nothing that I ask, and really seem to want me to take this “offline”. My only recourse at this point is to turn this over to Paypal as a claim. Paypal, I have complete documentation of all email communications between the seller and myself should you need it. Thanks, Justin I then escalated the dispute to a claim with this comment: While the seller will answer my emails, they will not give me an RMA number or a shipping label. They continue to try and get me to close the dispute without giving me any indications that they will follow through with their statements. Shortly after posting this blog entry, and giving negative feedback on the seller, I finally got an RMA from them. There’s some semi-sensitive information in the email, so I’ll refrain from posting it here. However, two things to note: - The RMA reflects that the card is indeed an Emuzed card, not a Hauppage. Did they know all along? - The RMA includes a refund on my original shipping charge. This is good! However, I didn’t get any notice of a shipping label to send the Emuzed card back to them. So, I sent them an email asking about the freight to them on 5/2: Thank you for the RMA number. Kat in customer service promised me that I would receive a pre-paid shipping label to return the part back to you. What is the status on that label? Justin Also on 5/2, I received a reply from someone (judging from the typing style, either Kat or the seller) to my personal email account: Please Close the dispute and you will receive the shipping label. I immediately replied: The dispute is closed it’s a claim now. You can send me the shipping label, and I’ll stop the claim. Or you can lose the claim, pay me my refund and have to deal with Paypal marking you as a questionable merchant. Your choice. It’s beyond the point of the money now, it’s the principle of the whole thing. You guys didn’t do jack for me until I opened the claim. Hell, I have a good reason to think that you knew you were selling me something different than what I bid on. There’s no way I’m going to give up the only leverage I have in exchange for your “word” that you’ll get me a shipping label. You might like to know that I’m tracking all of our communications via my blog so that Paypal and other potential customers of yours can get a heads up on what kind of shady practices you take part in. - I update it quite regularly. Justin I received an email from Simon on 5/2: Justin, First of all, I’d like to apologize on behalf of Legend Micro for the miscommunication that occurred with this transaction. Second, I’d like to give you this shipping label in hopes of resolving the claim/dispute. Along with that, I’d like for you to consider removing the negative feedback you left for us. I’d also like to explain to you what happened in the misunderstanding: Our warehouse mistakenly sent the wrong card. This is our mistake and you should have been issued a shipping label from the beginning. We do have the Hauppauge card that you originally ordered in stock. We would be more than happy to send you the card that you originally bought in exchange the card that was incorrectly shipped to you. Please let me know if you would like the Hauppauge card or a full refund. You can contact me directly at this email or by calling me at either of the numbers below. Regards, Simon Legend Micro 30700 Carter Street Suite B Solon, Ohio 44139 Phone: 888-368-7573 Direct/International: 440-394-4570 To which I replied: Simon, THANK YOU!!! This is all that I have wanted done since this issue was started 11 days ago. I would love to get the proper card sent out. Let’s do this - I will drop the original card off at the UPS store with the label you have sent me. If you ship out the replacement and supply me with the tracking number, I will close the Paypal claim, and update my feedback on eBay. Let me know if this works for you. Again, thank you for finally stepping up. Justin A few minutes later Simon replied back: Justin, Sure this is not a problem. We can ship out the card as soon as we see that the label we sent you has been activated and the package is in UPS' possession. Please let me know when you are planning on dropping the card off at the UPS store. Regards, Simon I sent him the following email: I will do this over my lunch break in the next couple of hours. Simon and I emailed back and forth a few more times, and they did what they promised. Once their tracking number showed the package was in UPS' hands, I got a shipment notification of the replacement card. On 5/7, I received my replacement which is quite obviously a “true” Hauppage WinTV PCI card.