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 :

sudo ./autoshut "poweroff" 10.0.0.1

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

gcc -o autoshut autoshut.c

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 :

0,10,20,30,40,50 1,2,3,4,5,6,7 * * * root /home/tom/autoshut/autoshut "poweroff" 10.0.0.1

Why do all that ? Energy consumption…

#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;
}

Leave a Reply

Your email address will not be published. Required fields are marked *

Time limit is exhausted. Please reload the CAPTCHA.