Sunday, February 20, 2011

Enabling WOL for ubuntu

Once you have the BIOS setup for to receive Wake On Lan/Magic packet you then need to tell Ubuntu to keep the Ethernet controller alive on a halt. Otherwise the magic packet is going to be ignored. To do this

sudo apt-get install ethtool

Now execute the command to set the wake on lan mode to on "g". You may need to tweak the eth0 piece to match the correct Ethernet interface.
sudo ethtool -s eth0 wol g

And confirm the setting with:
sudo ethtool eth0

At this point you can halt the machine and wake it but.. the setting is only temporary so you need to install a boot script in the server to make it permanent. Nothing is worst than shutting down the server while you are remote only to have it never come back on the next activation.
sudo vi /etc/init.d/wakeonlan

Now add the text.
#!/bin/sh
ethtool -s eth0 wol g
exit

Set execute permissions on the script:
sudo chmod a+x /etc/init.d/wakeonlan

Now at this point is is best to confirm the script actually works, unless you like making problems to fix.. So run it. And then install the script for startup:
update-rc.d -f /etc/init.d/wakeonlan defaults

Confirm output the install worked without errors.

Now your right to go. Dont forgot to get the MAC address from an ifconfig and then shutdown with:
sudo halt

Then simply send the magic packet(crafted from the Mac addres) to you local intranets broadcast address and the machine should wake up. If you want it to work from remote, map a random port or your NAT that will recast it to the local broadcast address and your done.

If it doesn't work then there are a range of problem items to check:
  • Confirm bios wake in LAN is on
  • Confirm for older bios's wake signal from pci is on
  • Confirm that the router led is indicating that the wire is connected and the link powered.
  • Confirm the router firewall isnt filtering the wake on LAN, often ports 7 or 9.
  • Confirm the wake on LAN tool is not a BS tool that doesn't work. There are a surprising number of them for how simple the magic packet is. For windows try Wolcmd.exe, ubuntu: wakeonlan, and the dd-wrt routers wol service also works nicely.
  • Confirm that the machine wasn't hard powered off. this tends to kill the sleeping ethernet controller and prevent the wakeup after that point.
Refer: http://ubuntuforums.org/showthread.php?t=234588 http://wiki.xbmc.org/index.php?title=HOW-TO_set_up_Wake-On-Lan_%28Ubuntu%29#The_init.d_script

Thursday, February 17, 2011

Perl generic data structure dumper

Here is a quick function to dump the contents of a generic mass of variables. I use it to debug the mass of random data structures that appear in random perl scripts

sub rec_print
{
    my ($message, $lead) = @_;
    
    if (ref($message) eq 'ARRAY') 
    { 
       # print  ":\n";        
        rec_print($_, $lead . " ")  foreach (@$message);
    }
    elsif (ref($message) eq 'HASH') 
    {
        foreach my $k (keys %$message)
        {
            print  "$lead$k:\n";
            rec_print($message->{$k}, $lead . " ");
        }
    }
    else
    {
        print "$lead$message\n";
    }
}

#example
rec_print({a=>"abc", b=>"bcd"},"");

Wednesday, February 16, 2011

boost, in vista using mingw and cmd.exe

Gezz.. what a pain... Getting boost to build in mingw is a bit of a mess. The docs dont "officially" cover it, but it does work once you patch together all the various missing pieces. Here is how:

Mingw version: 4.5
Boost Version: 1.45
OS: Vista.

First Download the tar.bz version from http://sourceforge.net/projects/boost/files/boost/1.45.0/.
Dont download the build version of bjam it wont work. You need to build it.

Build bjam:
Refer: http://boost.org/doc/libs/1_45_0/doc/html/jam/building.html

Note that I use the directory c:\tools as my install area for all programs that need to avoid the windows UAE etc idiocy.. Transfer the unziped/untared files into the desired location and then build the bjam.exe

In cmd.exe execute:
cd C:\tools\boost_1_45_0\tools\build\v2\engine\src
build.bat mingw
Once built copy C:\tools\boost_1_45_0\tools\build\v2\engine\src\bin.ntx86\bjam.exe into C:\tools\MinGW\bin (makes it easy later, since you likely have it in your %PATH% var already.)

Build the boost libs In cmd.exe execute:
bjam toolset=gcc --build-type=complete stage
Refer: http://www.boost.org/doc/libs/1_45_0/more/getting_started/windows.html#or-build-from-the-command-prompt

Wait copious amounts of time... There seems to be ALOT of warnings simply ignore them they are "harmless"

You can build boost test programs(in cmd or msys) with:
g++ -I"c:\tools\boost_1_45_0" -L"c:\tools\boost_1_45_0\stage\lib" -static boost_lamba_test.cpp -o a.exe
g++ -I"c:\tools\boost_1_45_0" -L"c:\tools\boost_1_45_0\stage\lib" -static boost_regex_test.cpp -lboost_regex-mgw45-1_45 -o b.exe

Lamba test: http://www.boost.org/doc/libs/1_45_0/more/getting_started/windows.html#build-a-simple-program-using-boost
Regex test: http://www.boost.org/doc/libs/1_45_0/more/getting_started/windows.html#link-your-program-to-a-boost-library

Keep in mind the order of the source and libs files is important in mingw
http://www.mingw.org/wiki/Specify_the_libraries_for_the_linker_to_use

Sunday, February 13, 2011

remote server shutdown.

In 2009 I wrote about passwordless shutdown of a ubuntu. At that time my object was remote shutdown and boot up of the server ie from an iphone or zaurus running an ultra-lite web server.

The resulting system would send the magic packet to wakeup the main server, zip the days data, scp the data to the main server and then ssh to the shutdown down user(causing the machine to halt). Now that I have an old iphone 3g I was seriously considering porting my ultra light server to it.

Anyway some how I got off track...again... My ubuntu server didnt cleanly upgrade to 10.10 so am I rebuilding it from scratch. Here is how to setup the auto shutdown user:

First add the shutdown user:
sudo adduser --home /home/shutdown shutdown

Or add the existing user to the shutdown group. (or combo of both)
sudo usermod -a -G shutdown username

Grant him ssh rights with:
sudo vi /etc/ssh/sshd_config

Add the line:
AllowUsers shutdown

And setup his ssh key:
sudo su -l shutdown
mkdir 
chmod 700 .ssh/
touch .ssh/authorized_keys 
chmod 600 .ssh/authorized_keys 
vi .ssh/authorized_keys 

And add the line(with your ssh key and note the forced command "/sbin/halt"):
command="/sbin/halt",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-rsa .... ==

Now by default halt cant be run without sudoing so to fix that edit the sudoers file
sudo visudo
UPDATE: You can can now add an extension file to the sudoers.d directory and not have to modifiy /etc/sudoers directly this way it doesnt break on every system upgrade..
sudo vi /etc/sudoers.d/passwordless_shutdown

Add the lines to grant rights to shutdown(and no one else) for the halt command
%shutdown ALL=NOPASSWD: /sbin/shutdown
%shutdown ALL=NOPASSWD: /sbin/halt

Then halt can be run as (an no password will be required)
sudo halt

If this still isnt sufficient (and it isnt for some scripting applications) The "sudo" part of the command can be removed by chmoding the command halt so that its runnable outside of a root user.
sudo chmod +s /sbin/reboot

Of course this basically allows any user on the system shutdown rights. so be careful with the chmod way.

Git setup in ubuntu 10.10

Here is a quick run down of the commands to setup git in ubuntu server edition 10.10
I user remote logins alot so i dont want the git keys to be the same as the remote login users.. This way the git user can only mess with the repos and cant sudo to anything.

The simplest way to setup a private and secure git repo is to use ssh, avoid packages like gitosis et al, as they complicate the system setup needlessly.

Start of with installing git.
sudo apt-get -y install git-core

Setup a git user with(without sudoer rights);
sudo useradd --home /home/git --shell /bin/sh git
sudo su -l git
mkdir ~/.ssh
chmod 700 ~/.ssh
mkdir ~/repos

Now to setup a repo do the following:
sudo su -l git
cd ~/repos
git init --bare testing.git

Now your remote repo url (and username) is;
ssh://git@server.ip.address/~/repos/testing.git

But it can be checked out locally with:
git clone ~git/repos/testing.git

Check out the local version and confirm it.

For the remote a client is needed. TortoiseSVN was big favorite of mine. So im going for TortoiseGIT as my client. To setup it up you need to install Msysgit then tortiseGIT.
http://code.google.com/p/msysgit/downloads/list
http://code.google.com/p/tortoisegit/downloads/list

When I tried to check out my repo the clone failed on me due to the "PermitRootLogin no" and "PasswordAuthentication no" settings in my sshd_config fix it with
sudo su -l gitadmin
sudo vi /etc/ssh/sshd_config

And add the user "git" to you AllowUsers line and install
AllowUsers git

Setup the remote users ssh key with PuttyGen and then add your ssh users pub key to the git user so that the client can login and pull/push the repo
sudo vi ~git/.ssh/authorized_keys

And then restart ssh and confirm the download of the admin settings:
sudo /etc/init.d/ssh restart

Refer:
http://book.git-scm.com

Saturday, January 29, 2011

Setting up passwordless SSH logins on ubuntu

First setup a clean install of ssh and config it from local and remote
sudo apt-get install openssh-server
 ssh -l username ipaddresss
 ifconfig | grep "inet addr"

sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.factory-defaults
 sudo chmod a-w /etc/ssh/sshd_config.factory-defaults
 sudo vi /etc/ssh/sshd_config

Then add(or change) the lines too read the following (to diable password loging and forwarding and spec limited access)
PasswordAuthentication no
 AllowTcpForwarding no
 X11Forwarding no
 AllowUsers yourRemoteUsername

Then add your key (do it now before restart or you will need a console access)
cat >> .ssh/authorized_keys 

paste in the one line with the rsa public key info and then reboot the machine or restart ssh with.
sudo /etc/init.d/ssh restart

Refer:
https://help.ubuntu.com/community/SSH/OpenSSH/Configuring#disable-password-authentication
https://help.ubuntu.com/community/SSH/OpenSSH/Keys

Thursday, January 27, 2011

Memory Blob Accessors (void*)

Dealing with generic Memory Blobs(The ominous void* or char*) is one thing that most programs know should be avoided. However most of use end up having to work with them. They are essential in homogeneous file and packet reader/writers, where the contents of the data dictate the class and type of next subsection of the data. And in caching and memory pool systems where the data contents and type is unrelated to the management of the blob.

Lucking they are easily handled with templates and reinterpret_cast. Here is some code demonstrating a blob handling class, with a streaming interface and fileIO capabilities. As you can see I got a little ambitious while coding it and so not all of the code is compile tested(ie templates dont compile unless used..) But it will build as is and execute, and I will sooner or latter get back and check the rest of it.

//build with g++
#include <stdint.h>

#include <istream>
#include <iostream>
#include <iomanip>

#include <string> 
#include <cstring>
#include <stdexcept>

using namespace std;

class Blob
{
public:
  //******* CONSTRUCTION ***********//
  
  Blob(uint32_t _size)
  {
    data = new char[_size];
    size = _size;
    memset(data, 0, size);
  }

  //*******  SIZING  ***********//
  uint32_t getSize() const
  { return size; }

  void resize(uint32_t _size)
  {
    uint32_t copySize = std::min(_size,size);
    char* old_data = data;
    data = new char[_size];
    if(_size > size)
       memset(&data[size], 0, _size - size);  //zero new part
    memcpy(data, old_data, copySize);         //copy old
    size = _size;
    delete old_data;
  }
 
  //*******  IMPORT/EXPORT  ***********//

  template<typename T>
  bool importObject(const T& src, 
      uint32_t offset = 0)
  {
    if((offset + sizeof(T)) > size) 
      return false;
    
    memcpy(&data[offset], &src, sizeof(T)); 
    return true;
  }

  template<typename T>
  bool exportObject(T& dst, 
      uint32_t offset = 0)
  {
    if((offset + sizeof(T)) > size) 
      return false;

    T* value = reinterpret_cast<T*>(&data[offset]);
    dst = *value;
    return true;
  }

  template<typename T, typename P>
  bool importObjectGetter(const T& src, 
     const P& (T::*get)() const, 
     uint32_t offset = 0)
  {
    if((offset + sizeof(P)) > size) 
      return false;
    
    const P& value = (src.*get)();
    memcpy(&data[offset], &value, sizeof(P)); 
    return true;
  }

  template<typename T, typename P>
  bool exportObjectSetter(T& dst, 
     bool (T::*set)(P*), 
     uint32_t offset = 0)
  {
    if((offset + sizeof(P)) > size) 
      return false;

    P* value = reinterpret_cast<P*>(&data[offset]);
    (dst.*set)(value);
    return true;
  }

  template<typename T>
  bool importPointer(const T* src, 
       uint32_t len, 
       uint32_t offset = 0)
  {
    if((offset + len) > size) 
      return false;
    
    memcpy(&data[offset], src, len); 
    return true;
  }

  template<typename T>
  bool exportPointer(T* dst, 
       uint32_t len, 
       uint32_t offset = 0)
  {
    if((offset + len) > size) 
      return false;

    memcpy(dst, &data[offset], len); 
    return true;
  }

  bool importZeroTermed(const string src, 
   uint32_t offset = 0)
  {
    uint32_t len = src.length();
    if((offset + len) > size) 
      return false;
    
    memcpy(&data[offset], src.c_str(), len); 
    return true;
  }

  bool exportZeroTermed(string& dst, 
   uint32_t offset = 0)
  {
    uint32_t len = strlen(&data[offset]);
    if((offset + len) > size) 
      return false;

    dst = &data[offset]; 
    return true;
  }

  //*********  DIRECT ACCESS  ***********//

  template<typename T>
  T* accessAsObject(uint32_t offset = 0)
  {
    if((offset + sizeof(T)) > size) 
      throw runtime_error("Out of Range");

    return reinterpret_cast<T*>(&data[offset]);
  }

  //*********  DUMPING  ***********//

  void print(ostream& out)
  {
    const int spaceStep = 4;
    const int lineStep  = 16;
    int totOffset=0;
    int subOffset=0;

    out << "Size(in hex): " << hex << size << endl;
    while(totOffset < size)
      {
 // the label..
 out << hex << setfill('0') << setw(2*sizeof(uint32_t)) 
     << totOffset << ": ";

 // the hex..
 int subOffset=0;
 while(subOffset < lineStep)
   {
     int offset = totOffset + subOffset; 
     if(offset <  size)
       {
  uint16_t number = (0xff & data[offset]);
  out << hex << setfill('0') << setw(2) 
      << number;
       }
     else
       out << "  ";
     subOffset++;
     if((subOffset % spaceStep) == 0)
       out << " ";
   }

 out << " : ";
 //the text
 subOffset=0;
 while(subOffset < lineStep)
   {
     int offset = totOffset + subOffset; 
     if(offset < size)
       {
  if(
     (data[offset] >= 33 ) && 
     (data[offset] <= 126 )
     )
    out << data[offset];
  else
    out << " ";
       }
     else
       out << " ";
     subOffset++;
   }
     
 out << endl;
 totOffset += lineStep;
      }
    out << dec;
  }

  //*********** FILE IO *************//
  void writeToFile(iostream& file)
  { file.write(data, size);  }

  void readFromFile(iostream& file)
  { file.read(data, size); }

  void writeSizedToFile(iostream& file)
  {
    file.write(reinterpret_cast<char*>(&size), sizeof(uint32_t));
    file.write(data, size);  
  }

  void readSizedFromFile(iostream& file)
  { 
    file.read(reinterpret_cast<char*>(&size), sizeof(uint32_t));
    resize(size);
    file.read(data, size); 
  }

private:
  char*   data;
  uint32_t size;
};

ostream& operator<<(ostream& out, Blob& val)
{
    val.print(out);
    return out;
}

class BlobStream
{
public:
  BlobStream(uint32_t _size, bool _autoScale=true, uint32_t _autoScaleFactor=4) :
    blob(_size),
    offset(0),
    autoScaleEnabled(_autoScale),
    autoScaleFactor(_autoScaleFactor)
  {}

  //*********  ACCESSORS  ***********//

  uint32_t getOffset()
  { return offset; }

  Blob& getBlob()
  { return blob; }

  //*********  SIZERS  ***********//

  void resetOffset()
  { offset = 0; }

  void finaliseSize()
  { 
    blob.resize(offset); 
    autoScaleEnabled = false;
  }

  void autoScaleUp(uint32_t min = 0)
  {
    if( !autoScaleEnabled)
      throw runtime_error("Buffer Size locked!");

    uint32_t size = blob.getSize();
    if(size == 0) size = 1;
    blob.resize(std::max(autoScaleFactor*size, min));
  }
  //*********  STREAMERS  ***********//
  
  template<typename T>
  BlobStream& operator<<(T& src)
  {
    while( !blob.importObject(src, offset) )
      autoScaleUp(sizeof(T));
    offset += sizeof(T);
    return *this;
  }

  BlobStream& operator<<(string& src)
  {
    while( !blob.importZeroTermed(src, offset) )
      autoScaleUp(src.length());
    offset += src.length();
    return *this;
  }

  BlobStream& operator<<(char* src)
  {
    while( !blob.importZeroTermed(src, offset) )
      autoScaleUp(strlen(src));
    offset += strlen(src);
    return *this;
  }

  template<typename T>
  BlobStream& operator>>(T& src)
  {
    if( !blob.exportObject(src, offset) )
      throw runtime_error("Lack of Buffer Data");
    offset += sizeof(T);
    return *this;
  }

  BlobStream& operator>>(string& src)
  {
    if( !blob.exportZeroTermed(src, offset) )
      throw runtime_error("Lack of Buffer Data OR no termination");
    offset += src.length();
    return *this;
  }

private:
  bool     autoScaleEnabled;
  uint32_t autoScaleFactor;

  Blob blob;
  uint32_t offset;
};

//Test
struct A
{
  char a1;
  int a2;
};

struct B
{
  char b1[10];
  float b2;
};

int main()
{
  BlobStream bs(0);
  A a;
  B b;
  
  a.a1 = '#';
  a.a2 = 10;

  memcpy(b.b1, "here it is", 10); 
  b.b2 = 0.2;
  
  bs << a << b << " -- and then some";

  cout << "Before Finalisation" << endl;
  bs.getBlob().print(cout);
  bs.finaliseSize();
  bs.resetOffset();
  cout << endl << "After Finalisation" << endl;
  bs.getBlob().print(cout);

  A c;
  B d;
  string e;

  bs >> c >> d >> e;
  
  cout << endl
       << "Retrived Data:" << endl
       << " " << c.a1 << endl
       << " " << c.a2 << endl
       << " " << d.b1 << endl
       << " " << d.b2 << endl
       << " " << e    << endl;    
}

The result looks like this:
Before Finalisation
Size(in hex): 80
00000000: 231e1a66 0a000000 68657265 20697420  : #  f    here it
00000010: 69732200 cdcc4c3e 202d2d20 616e6420  : is"   L> -- and
00000020: 7468656e 20736f6d 65000000 00000000  : then some
00000030: 00000000 00000000 00000000 00000000  :
00000040: 00000000 00000000 00000000 00000000  :
00000050: 00000000 00000000 00000000 00000000  :
00000060: 00000000 00000000 00000000 00000000  :
00000070: 00000000 00000000 00000000 00000000  :

After Finalisation
Size(in hex): 2a
00000000: 231e1a66 0a000000 68657265 20697420  : #  f    here it
00000010: 69732200 cdcc4c3e 202d2d20 616e6420  : is"   L> -- and
00000020: 7468656e 20736f6d 6500               : then some

Retrived Data:
 #
 10
 here it is"
 0.2
  -- and then some