Home server : auto-shutdown if no other computers are running

I wanted to shutdown my linux home media server if there is no running computer on my network. So I wrote this little programs which reads all known ips from DHCP configuration and lease files and send a ping to them. If the ping respond, one PC of my LAN is up…

To re-start the computer in the morning, I use the BIOS RTC alarm (the thing you have by pressing F1 or ESC on reboot). You could also add a script/a program on each of your computers to send the magic packet to your home server to wake it by lan (see “wake on lan” on google).

This script can take any command. But if you want to do shutdown like proposed in the title, you can use :

[code]sudo ./autoshut “poweroff” 10.0.0.1[/code]

Where 10.0.0.1 is your local IP adress. To compile the program, simply use (after saving the code as “autoshut.c”) : [code]gcc -o autoshut autoshut.c[/code]

In my case, I wanted to launch the command only after midnight, so I used cron. Cron will launch that command every 5 minutes from midnight to eight o’clock. So if I stay up late, my server won’t shutdown if my own computer is not down too. That’s the whole purpose.

The line in my crontab :

[code]0,10,20,30,40,50 1,2,3,4,5,6,7 * * * root /home/tom/autoshut/autoshut “poweroff” 10.0.0.1[/code]

Why do all that ? Energy consumption…

[code]#include <stdio.h>
#include <stdlib.h>
#include <regex.h>
#include <string.h>

#define LEASE_FILE “/var/lib/dhcp/dhcpd.leases”
#define DHCP_CONFIG_FILE “/etc/dhcp/dhcpd.conf”

int in_array(char** ar, char* str) {
int i = 0;
while (ar[i] != NULL) {
if (strcmp(ar[i],str) == 0) return 1;
i++;
}
return 0;
}

char* extractIP (char* filename, char** list, int* listNum) {
FILE *pfile;

pfile = fopen(filename, “rb”);

if(pfile == NULL){
printf(“Sorry, can’t open %s\n”, filename);
return ‘\0’;
}
regex_t reg;
int err = regcomp (&reg, “(10\\.[0-1]\\.0\\.([1-9]|[0-9]{2,3}))”, REG_EXTENDED);
if (err != 0)
{
printf(“ERREUR\n”);
return ‘\0’;
}
char ligne[255];

while(!feof(pfile)) {
fgets(ligne, 254 ,pfile);
int match;
size_t nmatch = 0;
regmatch_t *pmatch = NULL;

nmatch = reg.re_nsub;
pmatch = malloc (sizeof (*pmatch) * nmatch);
match = regexec (&reg, ligne, nmatch, pmatch, 0);
if (match == 0)
{
char *ip = NULL;
int start = pmatch->rm_so;
int end = pmatch->rm_eo;
size_t size = end – start;

char* str = malloc(sizeof(char) * 15);
strncpy (str, &ligne[start], size);
str[size] = ‘\0’;

if (!in_array(list, str)) {
list[*listNum] = str;
printf(“%s\n”, str);
(*listNum)++;
}

}

}

fclose(pfile);
regfree(&reg);
}

int ping(char* address) {

char cmd[30] = “ping -W 1 -q -c 1 “;
strcat(cmd,address);
int ret=system(cmd);
printf(“\nResultat : %d\n\n”,ret);
return !ret;
}
/*
TODO : maybe an option?
int checkCableStatus(const char* interface) {
/sys/class/net/eth0/carrier
}*/

int main(int argc, char** argv) {

if (argc <= 2) {
printf(“Usage : %s Command Local-IP [Local-IP-2]\n\tCommand : a command to execute if ping does not work\n\tLocal-IP : Ip to ignore\n\tLocal-IP-2 : Optional second ip to ignore”,argv[0]);
return -1;
}
int listNum = 0;
char** list = malloc(sizeof(char*) * 255);
extractIP(DHCP_CONFIG_FILE, list, &listNum);
extractIP(LEASE_FILE, list, &listNum);
int i = 0;
while (list[i] != NULL) {
if (strcmp(list[i],argv[2])!=0 && (argc==3 ||strcmp(list[i],argv[3])!=0)) {
if (ping (list[i])) {
printf(“%s responded. Command aborted !\n”,list[i]);
return EXIT_SUCCESS;
}
}
i++;
}
system(argv[1]);
return EXIT_SUCCESS;
}[/code]

Manual network configuration under ubuntu

This procedure is only with cable, not for wifi

First check that your interface is up with the command “sudo ifconfig” :

lo
If like in this screenshot you do not see an interface named “ethXXX“, you have to start the interface manually.
 
To found which of eth0, eth1, … your network card is, you can type “dmesg | grep eth

dmesg
We see here that the card “Intel Pro/1000” takes the “eth0” interface name. But it’s later renamed to “eth1“.
 
So our interface here is eth1, to bring it up, simply run “sudo ifconfig eth1 up”.
eth1up

You may not have an IP Adress automatically like in this screenshot. If it’s the case, simply type “sudo dhclient eth1” to get one with DHCP.
 
If it doesn’t work, try to directly ping an IP address like google’s dns server 8.8.8.8 with the command “ping 8.8.8.8“. If it works, you probably have a nameserver problem. Simply add the line “nameserver 8.8.8.8” in /etc/resolv.conf