// Netlink.cpp

#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <string>
#include <vector>
#include <asm/types.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/mount.h>
#include <sys/time.h>
#include <scsi/scsi_ioctl.h>
#include <scsi/scsi.h>
#include <scsi/sg.h>

#define NETLINK_KOBJECT_UEVENT	15	/* Kernel messages to userspace */

struct sDevice
{
  std::string strName;
  bool bActive;
  bool bMedia;
  int fd;
};

std::vector<struct sDevice> vDevices;

int main(int argc, char** argv)
{
    char buffer[1024];
    struct sDevice sDev;
    std::vector<struct sDevice>::iterator it;

    for (char c = 'a'; c <= 'h'; ++c) {
        sDev.strName = "/dev/sd";
	sDev.strName += c;
        sDev.bActive = false;
	sDev.bMedia  = false;
        sDev.fd = -1;
        vDevices.push_back(sDev);
    }

    // Open netlink socket
    int fd;
    fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
    if (fd < 0) {
        printf ("Cannot create netlink socket\n");
        return -1;
    }

    // Bind netlink socket
    struct sockaddr_nl addr;
    memset(&addr, 0, sizeof(addr));
    addr.nl_family = AF_NETLINK;
    addr.nl_pid = getpid();
    addr.nl_groups = 1;
    if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
        perror("Cannot bind netlink socket\n");
        return -1;
    }
  
    // Listen netlink socket
    fd_set fds;
    struct timeval tv;
    for (;;) {
        FD_ZERO (&fds);
        FD_SET (fd, &fds);
	tv.tv_sec = 0;
	tv.tv_usec = 100000;
        while ((select(FD_SETSIZE, &fds, NULL, NULL, &tv)) > 0) {
            int status = read(fd, buffer, sizeof(buffer)-1);
            if (status > 0) {
	        buffer[status] = 0; // null terminate

		std::string sMessage;
		sMessage = buffer;

		if ((sMessage.substr(0, 4) == "add@") && (sMessage.size() == 14)) {
		  for (it = vDevices.begin(); it != vDevices.end(); ++it) {
		      // Add device
		      if (sMessage.substr(11, 3) == (*it).strName.substr(5, 3)) { 
			  printf ("%s added\n", (*it).strName.c_str());
			  (*it).bActive = true;
			  (*it).bMedia = false;
			  printf ("opening\n");;
			  (*it).fd = open((*it).strName.c_str(), O_RDONLY | O_NONBLOCK);
			  printf ("opened %d\n", (*it).fd);
			}
		    }
		}
		else if ((sMessage.substr(0, 7) == "remove@") && (sMessage.size() == 17)) {
		  for (it = vDevices.begin(); it != vDevices.end(); ++it) {
		      // Remove device
		      if (sMessage.substr(14, 3) == (*it).strName.substr(5, 3)) { 
			  printf ("%s removed\n", (*it).strName.c_str());
			  (*it).bActive = false;
			  (*it).bMedia = false;
			  printf ("closing %d\n", (*it).fd);
			  close ((*it).fd);
			  printf ("closed\n");
			}
		    }
	        }
	    }
	}
    }
}

