typedef unsigned short int sa_family_t;
//Linux includes
#define _LINUX_TIME_H
#define _GNU_SOURCE
#include <sys/types.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/connector.h>
#include <linux/cn_proc.h>
#include <linux/netlink.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h> 
#include <sys/resource.h>
#include <unistd.h>

//Theses magics come from connector.txt, I will maybe check includes if it's not already in
#define NETLINK_ADD_MEMBERSHIP 1
//#define NETLINK_DROP_MEMBERSHIP 0

#define SOL_NETLINK 270

static inline int ioprio_set(int whichint whoint ioprio)
{
        return syscall(__NR_ioprio_setwhichwhoioprio);
}

static inline int ioprio_get(int whichint who)
{
        return syscall(__NR_ioprio_getwhichwho);
}

char *get_cmd(int pid) {
        char *file;
        asprintf(&file"/proc/%d/cmdline"pid);
        int fd;
        fd=open(fileO_RDONLY);
        char *buffer=malloc(4096); //Is there a MACRO to know the max size of cmdline ?
        read(fdbuffer4096);
        char *ret=strdup(buffer);//The separator is \0 so strdup will only copy the first part
        free(buffer);
        return ret;
}

void show_event(struct proc_event *ev) {
        //This function displays the action of the struct proc_event in argument
        switch(ev->what) {
                case PROC_EVENT_NONE:
                        return;
                        break;
                case PROC_EVENT_FORK:
                        break;
                case PROC_EVENT_EXEC:
                        //We only care about exec
                        if(strcmp(get_cmd(ev->event_data.exec.process_pid), "mplayer")) {
                                setpriority(PRIO_PROCESSev->event_data.exec.process_pid, -20);
                                ioprio_set(1,ev->event_data.exec.process_pid,0|1<<13);
                        }
                        break;
                case PROC_EVENT_UID:
                case PROC_EVENT_GID:
                        printf("UID/GID\n");
                        break;
                case PROC_EVENT_EXIT:
                        printf("exit()\n");
                        break;
        }


}

int main(int argcchar **argvchar **envp) {
        //All this code is only to open a NetLink socket...
        //Isn't it easy?
        int s,on;
        struct sockaddr_nl l_local;

        s = socket(PF_NETLINKSOCK_DGRAMNETLINK_CONNECTOR);
        if(!s) {
                perror("Couldn't open socket for NETLINK_CONNECTOR");
                exit(1);
        }

        l_local.nl_family=AF_NETLINK;
        l_local.nl_groups=0x123456;
        l_local.nl_pid = 0;

        if (bind(s, (struct sockaddr *)&l_localsizeof(struct sockaddr_nl)) == -1) {
                perror("bind");
                close(s);
                return -1;
        }

        //On linux > 2.6.14 wee need this to write on a netlink multicast according to connector.txt
        on=l_local.nl_groups;
        setsockopt(sSOL_NETLINKNETLINK_ADD_MEMBERSHIP, &onsizeof(on));

        struct cn_msg message;
        //Fullfil the ID of the kernel side
        message.id.idx=CN_IDX_PROC;
        message.id.val=CN_VAL_PROC;
        message.seq=0;
        message.ack=15000;
        message.len=sizeof(enum proc_cn_mcast_op);
        message.flags=0;
        //message.data=PROC_CN_MCAST_LISTEN;
        *((enum proc_cn_mcast_op*)(message.data))=PROC_CN_MCAST_LISTEN;
        send(s, &messagesizeof(message) + sizeof(enum proc_cn_mcast_op), 0);

        struct cn_msg *buffer=malloc(sizeof(struct cn_msg)+sizeof(struct proc_event));
        int buflen;
        //In this program we only get one event, to demonstrate the use of cn we don't need more.
        buflen=recv(sbuffersizeof(buffer), 0);
        if (buflen<0) {
                return -1;
        }
        //let's show the result.
        struct proc_event *event=(struct proc_event*)buffer->data;
        show_event(event);
        return 0;
}