source: ogServer-Git/sources/ogAdmServer.c @ f4e7832

Last change on this file since f4e7832 was f4e7832, checked in by OpenGnSys Support Team <soporte-og@…>, 4 years ago

#971 add str_toupper()

Add new utils.c file and replace old StrToUpper?().

  • Property mode set to 100644
File size: 157.3 KB
Line 
1// *******************************************************************************************************
2// Servicio: ogAdmServer
3// Autor: José Manuel Alonso (E.T.S.I.I.) Universidad de Sevilla
4// Fecha Creación: Marzo-2010
5// Fecha Última modificación: Marzo-2010
6// Nombre del fichero: ogAdmServer.cpp
7// Descripción :Este fichero implementa el servicio de administración general del sistema
8// *******************************************************************************************************
9#include "ogAdmServer.h"
10#include "ogAdmLib.c"
11#include "dbi.h"
12#include "utils.h"
13#include "list.h"
14#include "schedule.h"
15#include <ev.h>
16#include <syslog.h>
17#include <sys/ioctl.h>
18#include <ifaddrs.h>
19#include <sys/types.h>
20#include <sys/stat.h>
21#include <fcntl.h>
22#include <jansson.h>
23#include <time.h>
24
25static char usuario[LONPRM]; // Usuario de acceso a la base de datos
26static char pasguor[LONPRM]; // Password del usuario
27static char datasource[LONPRM]; // Dirección IP del gestor de base de datos
28static char catalog[LONPRM]; // Nombre de la base de datos
29static char interface[LONPRM]; // Interface name
30static char auth_token[LONPRM]; // API token
31
32static struct og_dbi_config dbi_config = {
33        .user           = usuario,
34        .passwd         = pasguor,
35        .host           = datasource,
36        .database       = catalog,
37};
38
39//________________________________________________________________________________________________________
40//      Función: tomaConfiguracion
41//
42//      Descripción:
43//              Lee el fichero de configuración del servicio
44//      Parámetros:
45//              filecfg : Ruta completa al fichero de configuración
46//      Devuelve:
47//              true: Si el proceso es correcto
48//              false: En caso de ocurrir algún error
49//________________________________________________________________________________________________________
50static bool tomaConfiguracion(const char *filecfg)
51{
52        char buf[1024], *line;
53        char *key, *value;
54        FILE *fcfg;
55
56        if (filecfg == NULL || strlen(filecfg) == 0) {
57                syslog(LOG_ERR, "No configuration file has been specified\n");
58                return false;
59        }
60
61        fcfg = fopen(filecfg, "rt");
62        if (fcfg == NULL) {
63                syslog(LOG_ERR, "Cannot open configuration file `%s'\n",
64                       filecfg);
65                return false;
66        }
67
68        servidoradm[0] = '\0'; //inicializar variables globales
69
70        line = fgets(buf, sizeof(buf), fcfg);
71        while (line != NULL) {
72                const char *delim = "=";
73
74                line[strlen(line) - 1] = '\0';
75
76                key = strtok(line, delim);
77                value = strtok(NULL, delim);
78
79                if (!strcmp(str_toupper(key), "SERVIDORADM"))
80                        snprintf(servidoradm, sizeof(servidoradm), "%s", value);
81                else if (!strcmp(str_toupper(key), "PUERTO"))
82                        snprintf(puerto, sizeof(puerto), "%s", value);
83                else if (!strcmp(str_toupper(key), "USUARIO"))
84                        snprintf(usuario, sizeof(usuario), "%s", value);
85                else if (!strcmp(str_toupper(key), "PASSWORD"))
86                        snprintf(pasguor, sizeof(pasguor), "%s", value);
87                else if (!strcmp(str_toupper(key), "DATASOURCE"))
88                        snprintf(datasource, sizeof(datasource), "%s", value);
89                else if (!strcmp(str_toupper(key), "CATALOG"))
90                        snprintf(catalog, sizeof(catalog), "%s", value);
91                else if (!strcmp(str_toupper(key), "INTERFACE"))
92                        snprintf(interface, sizeof(interface), "%s", value);
93                else if (!strcmp(str_toupper(key), "APITOKEN"))
94                        snprintf(auth_token, sizeof(auth_token), "%s", value);
95
96                line = fgets(buf, sizeof(buf), fcfg);
97        }
98
99        fclose(fcfg);
100
101        if (!servidoradm[0]) {
102                syslog(LOG_ERR, "Missing SERVIDORADM in configuration file\n");
103                return false;
104        }
105        if (!puerto[0]) {
106                syslog(LOG_ERR, "Missing PUERTO in configuration file\n");
107                return false;
108        }
109        if (!usuario[0]) {
110                syslog(LOG_ERR, "Missing USUARIO in configuration file\n");
111                return false;
112        }
113        if (!pasguor[0]) {
114                syslog(LOG_ERR, "Missing PASSWORD in configuration file\n");
115                return false;
116        }
117        if (!datasource[0]) {
118                syslog(LOG_ERR, "Missing DATASOURCE in configuration file\n");
119                return false;
120        }
121        if (!catalog[0]) {
122                syslog(LOG_ERR, "Missing CATALOG in configuration file\n");
123                return false;
124        }
125        if (!interface[0])
126                syslog(LOG_ERR, "Missing INTERFACE in configuration file\n");
127
128        return true;
129}
130
131enum og_client_state {
132        OG_CLIENT_RECEIVING_HEADER      = 0,
133        OG_CLIENT_RECEIVING_PAYLOAD,
134        OG_CLIENT_PROCESSING_REQUEST,
135};
136
137#define OG_MSG_REQUEST_MAXLEN   65536
138#define OG_CMD_MAXLEN           64
139
140/* Shut down connection if there is no complete message after 10 seconds. */
141#define OG_CLIENT_TIMEOUT       10
142
143/* Agent client operation might take longer, shut down after 30 seconds. */
144#define OG_AGENT_CLIENT_TIMEOUT 30
145
146enum og_cmd_type {
147        OG_CMD_UNSPEC,
148        OG_CMD_WOL,
149        OG_CMD_PROBE,
150        OG_CMD_SHELL_RUN,
151        OG_CMD_SESSION,
152        OG_CMD_POWEROFF,
153        OG_CMD_REFRESH,
154        OG_CMD_REBOOT,
155        OG_CMD_STOP,
156        OG_CMD_HARDWARE,
157        OG_CMD_SOFTWARE,
158        OG_CMD_IMAGE_CREATE,
159        OG_CMD_IMAGE_RESTORE,
160        OG_CMD_SETUP,
161        OG_CMD_RUN_SCHEDULE,
162        OG_CMD_MAX
163};
164
165static LIST_HEAD(client_list);
166
167enum og_client_status {
168        OG_CLIENT_STATUS_OGLIVE,
169        OG_CLIENT_STATUS_BUSY,
170};
171
172struct og_client {
173        struct list_head        list;
174        struct ev_io            io;
175        struct ev_timer         timer;
176        struct sockaddr_in      addr;
177        enum og_client_state    state;
178        char                    buf[OG_MSG_REQUEST_MAXLEN];
179        unsigned int            buf_len;
180        unsigned int            msg_len;
181        int                     keepalive_idx;
182        bool                    rest;
183        bool                    agent;
184        int                     content_length;
185        char                    auth_token[64];
186        enum og_client_status   status;
187        enum og_cmd_type        last_cmd;
188        unsigned int            last_cmd_id;
189        bool                    autorun;
190};
191
192static inline int og_client_socket(const struct og_client *cli)
193{
194        return cli->io.fd;
195}
196
197static inline const char *og_client_status(const struct og_client *cli)
198{
199        if (cli->last_cmd != OG_CMD_UNSPEC)
200                return "BSY";
201
202        switch (cli->status) {
203        case OG_CLIENT_STATUS_BUSY:
204                return "BSY";
205        case OG_CLIENT_STATUS_OGLIVE:
206                return "OPG";
207        default:
208                return "OFF";
209        }
210}
211
212// ________________________________________________________________________________________________________
213// Función: clienteDisponible
214//
215//      Descripción:
216//              Comprueba la disponibilidad del cliente para recibir comandos interactivos
217//      Parametros:
218//              - ip : La ip del cliente a buscar
219//              - idx: (Salida)  Indice que ocupa el cliente, de estar ya registrado
220//      Devuelve:
221//              true: Si el cliente está disponible
222//              false: En caso contrario
223// ________________________________________________________________________________________________________
224bool clienteDisponible(char *ip, int* idx)
225{
226        int estado;
227
228        if (clienteExistente(ip, idx)) {
229                estado = strcmp(tbsockets[*idx].estado, CLIENTE_OCUPADO); // Cliente ocupado
230                if (estado == 0)
231                        return false;
232
233                estado = strcmp(tbsockets[*idx].estado, CLIENTE_APAGADO); // Cliente apagado
234                if (estado == 0)
235                        return false;
236
237                estado = strcmp(tbsockets[*idx].estado, CLIENTE_INICIANDO); // Cliente en proceso de inclusión
238                if (estado == 0)
239                        return false;
240
241                return true; // En caso contrario el cliente está disponible
242        }
243        return false; // Cliente no está registrado en el sistema
244}
245// ________________________________________________________________________________________________________
246// Función: clienteExistente
247//
248//      Descripción:
249//              Comprueba si el cliente está registrado en la tabla de socket del sistema
250//      Parametros:
251//              - ip : La ip del cliente a buscar
252//              - idx:(Salida)  Indice que ocupa el cliente, de estar ya registrado
253//      Devuelve:
254//              true: Si el cliente está registrado
255//              false: En caso contrario
256// ________________________________________________________________________________________________________
257bool clienteExistente(char *ip, int* idx)
258{
259        int i;
260        for (i = 0; i < MAXIMOS_CLIENTES; i++) {
261                if (contieneIP(ip, tbsockets[i].ip)) { // Si existe la IP en la cadena
262                        *idx = i;
263                        return true;
264                }
265        }
266        return false;
267}
268// ________________________________________________________________________________________________________
269// Función: actualizaConfiguracion
270//
271//      Descripción:
272//              Esta función actualiza la base de datos con la configuracion de particiones de un cliente
273//      Parámetros:
274//              - db: Objeto base de datos (ya operativo)
275//              - tbl: Objeto tabla
276//              - cfg: cadena con una Configuración
277//              - ido: Identificador del ordenador cliente
278//      Devuelve:
279//              true: Si el proceso es correcto
280//              false: En caso de ocurrir algún error
281//      Especificaciones:
282//              Los parametros de la configuración son:
283//                      par= Número de partición
284//                      cpt= Codigo o tipo de partición
285//                      sfi= Sistema de ficheros que está implementado en la partición
286//                      soi= Nombre del sistema de ficheros instalado en la partición
287//                      tam= Tamaño de la partición
288// ________________________________________________________________________________________________________
289bool actualizaConfiguracion(struct og_dbi *dbi, char *cfg, int ido)
290{
291        int lon, p, c,i, dato, swu, idsoi, idsfi,k;
292        char *ptrPar[MAXPAR], *ptrCfg[7], *ptrDual[2], tbPar[LONSTD];
293        char *ser, *disk, *par, *cpt, *sfi, *soi, *tam, *uso; // Parametros de configuración.
294        dbi_result result, result_update;
295        const char *msglog;
296
297        lon = 0;
298        p = splitCadena(ptrPar, cfg, '\n');
299        for (i = 0; i < p; i++) {
300                c = splitCadena(ptrCfg, ptrPar[i], '\t');
301
302                // Si la 1ª línea solo incluye el número de serie del equipo; actualizar BD.
303                if (i == 0 && c == 1) {
304                        splitCadena(ptrDual, ptrCfg[0], '=');
305                        ser = ptrDual[1];
306                        if (strlen(ser) > 0) {
307                                // Solo actualizar si número de serie no existía.
308                                result = dbi_conn_queryf(dbi->conn,
309                                                "UPDATE ordenadores SET numserie='%s'"
310                                                " WHERE idordenador=%d AND numserie IS NULL",
311                                                ser, ido);
312                                if (!result) {
313                                        dbi_conn_error(dbi->conn, &msglog);
314                                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
315                                               __func__, __LINE__, msglog);
316                                        return false;
317                                }
318                                dbi_result_free(result);
319                        }
320                        continue;
321                }
322
323                // Distribución de particionado.
324                disk = par = cpt = sfi = soi = tam = uso = NULL;
325
326                splitCadena(ptrDual, ptrCfg[0], '=');
327                disk = ptrDual[1]; // Número de disco
328
329                splitCadena(ptrDual, ptrCfg[1], '=');
330                par = ptrDual[1]; // Número de partición
331
332                k=splitCadena(ptrDual, ptrCfg[2], '=');
333                if(k==2){
334                        cpt = ptrDual[1]; // Código de partición
335                }else{
336                        cpt = (char*)"0";
337                }
338
339                k=splitCadena(ptrDual, ptrCfg[3], '=');
340                if(k==2){
341                        sfi = ptrDual[1]; // Sistema de ficheros
342                        /* Comprueba existencia del s0xistema de ficheros instalado */
343                        idsfi = checkDato(dbi, sfi, "sistemasficheros", "descripcion","idsistemafichero");
344                }
345                else
346                        idsfi=0;
347
348                k=splitCadena(ptrDual, ptrCfg[4], '=');
349                if(k==2){ // Sistema operativo detecdtado
350                        soi = ptrDual[1]; // Nombre del S.O. instalado
351                        /* Comprueba existencia del sistema operativo instalado */
352                        idsoi = checkDato(dbi, soi, "nombresos", "nombreso", "idnombreso");
353                }
354                else
355                        idsoi=0;
356
357                splitCadena(ptrDual, ptrCfg[5], '=');
358                tam = ptrDual[1]; // Tamaño de la partición
359
360                splitCadena(ptrDual, ptrCfg[6], '=');
361                uso = ptrDual[1]; // Porcentaje de uso del S.F.
362
363                lon += sprintf(tbPar + lon, "(%s, %s),", disk, par);
364
365                result = dbi_conn_queryf(dbi->conn,
366                                "SELECT numdisk, numpar, tamano, uso, idsistemafichero, idnombreso"
367                                "  FROM ordenadores_particiones"
368                                " WHERE idordenador=%d AND numdisk=%s AND numpar=%s",
369                                ido, disk, par);
370                if (!result) {
371                        dbi_conn_error(dbi->conn, &msglog);
372                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
373                               __func__, __LINE__, msglog);
374                        return false;
375                }
376                if (!dbi_result_next_row(result)) {
377                        result_update = dbi_conn_queryf(dbi->conn,
378                                        "INSERT INTO ordenadores_particiones(idordenador,numdisk,numpar,codpar,tamano,uso,idsistemafichero,idnombreso,idimagen)"
379                                        " VALUES(%d,%s,%s,0x%s,%s,%s,%d,%d,0)",
380                                        ido, disk, par, cpt, tam, uso, idsfi, idsoi);
381                        if (!result_update) {
382                                dbi_conn_error(dbi->conn, &msglog);
383                                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
384                                       __func__, __LINE__, msglog);
385                                return false;
386                        }
387                        dbi_result_free(result_update);
388
389                } else { // Existe el registro
390                        swu = true; // Se supone que algún dato ha cambiado
391
392                        dato = dbi_result_get_uint(result, "tamano");
393                        if (atoi(tam) == dato) {// Parámetro tamaño igual al almacenado
394                                dato = dbi_result_get_uint(result, "idsistemafichero");
395                                if (idsfi == dato) {// Parámetro sistema de fichero igual al almacenado
396                                        dato = dbi_result_get_uint(result, "idnombreso");
397                                        if (idsoi == dato) {// Parámetro sistema de fichero distinto al almacenado
398                                                swu = false; // Todos los parámetros de la partición son iguales, no se actualiza
399                                        }
400                                }
401                        }
402                        if (swu) { // Hay que actualizar los parámetros de la partición
403                                result_update = dbi_conn_queryf(dbi->conn,
404                                        "UPDATE ordenadores_particiones SET "
405                                        " codpar=0x%s,"
406                                        " tamano=%s,"
407                                        " uso=%s,"
408                                        " idsistemafichero=%d,"
409                                        " idnombreso=%d,"
410                                        " idimagen=0,"
411                                        " idperfilsoft=0,"
412                                        " fechadespliegue=NULL"
413                                        " WHERE idordenador=%d AND numdisk=%s AND numpar=%s",
414                                        cpt, tam, uso, idsfi, idsoi, ido, disk, par);
415                        } else {  // Actualizar porcentaje de uso.
416                                result_update = dbi_conn_queryf(dbi->conn,
417                                        "UPDATE ordenadores_particiones SET "
418                                        " codpar=0x%s,"
419                                        " uso=%s"
420                                        " WHERE idordenador=%d AND numdisk=%s AND numpar=%s",
421                                        cpt, uso, ido, disk, par);
422                        }
423                        if (!result_update) {
424                                dbi_conn_error(dbi->conn, &msglog);
425                                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
426                                       __func__, __LINE__, msglog);
427                                return false;
428                        }
429
430                        dbi_result_free(result_update);
431                }
432                dbi_result_free(result);
433        }
434        lon += sprintf(tbPar + lon, "(0,0)");
435        // Eliminar particiones almacenadas que ya no existen
436        result_update = dbi_conn_queryf(dbi->conn,
437                "DELETE FROM ordenadores_particiones WHERE idordenador=%d AND (numdisk, numpar) NOT IN (%s)",
438                        ido, tbPar);
439        if (!result_update) {
440                dbi_conn_error(dbi->conn, &msglog);
441                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
442                       __func__, __LINE__, msglog);
443                return false;
444        }
445        dbi_result_free(result_update);
446
447        return true;
448}
449// ________________________________________________________________________________________________________
450// Función: checkDato
451//
452//      Descripción:
453//               Esta función comprueba si existe un dato en una tabla y si no es así lo incluye. devuelve en
454//              cualquier caso el identificador del registro existenet o del insertado
455//      Parámetros:
456//              - db: Objeto base de datos (ya operativo)
457//              - tbl: Objeto tabla
458//              - dato: Dato
459//              - tabla: Nombre de la tabla
460//              - nomdato: Nombre del dato en la tabla
461//              - nomidentificador: Nombre del identificador en la tabla
462//      Devuelve:
463//              El identificador del registro existente o el del insertado
464//
465//      Especificaciones:
466//              En caso de producirse algún error se devuelve el valor 0
467// ________________________________________________________________________________________________________
468
469int checkDato(struct og_dbi *dbi, char *dato, const char *tabla,
470                     const char *nomdato, const char *nomidentificador)
471{
472        const char *msglog;
473        int identificador;
474        dbi_result result;
475
476        if (strlen(dato) == 0)
477                return (0); // EL dato no tiene valor
478        result = dbi_conn_queryf(dbi->conn,
479                        "SELECT %s FROM %s WHERE %s ='%s'", nomidentificador,
480                        tabla, nomdato, dato);
481
482        // Ejecuta consulta
483        if (!result) {
484                dbi_conn_error(dbi->conn, &msglog);
485                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
486                       __func__, __LINE__, msglog);
487                return (0);
488        }
489        if (!dbi_result_next_row(result)) { //  Software NO existente
490                dbi_result_free(result);
491
492                result = dbi_conn_queryf(dbi->conn,
493                                "INSERT INTO %s (%s) VALUES('%s')", tabla, nomdato, dato);
494                if (!result) {
495                        dbi_conn_error(dbi->conn, &msglog);
496                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
497                               __func__, __LINE__, msglog);
498                        return (0);
499                }
500                // Recupera el identificador del software
501                identificador = dbi_conn_sequence_last(dbi->conn, NULL);
502        } else {
503                identificador = dbi_result_get_uint(result, nomidentificador);
504        }
505        dbi_result_free(result);
506
507        return (identificador);
508}
509
510struct og_task {
511        uint32_t        task_id;
512        uint32_t        procedure_id;
513        uint32_t        command_id;
514        uint32_t        center_id;
515        uint32_t        schedule_id;
516        uint32_t        type_scope;
517        uint32_t        scope;
518        const char      *filtered_scope;
519        const char      *params;
520};
521
522static TRAMA *og_msg_alloc(char *data, unsigned int len);
523static void og_msg_free(TRAMA *ptrTrama);
524
525static bool og_send_cmd(char *ips_array[], int ips_array_len,
526                        const char *state, TRAMA *ptrTrama)
527{
528        int i, idx;
529
530        for (i = 0; i < ips_array_len; i++) {
531                if (clienteDisponible(ips_array[i], &idx)) { // Si el cliente puede recibir comandos
532                        int sock = tbsockets[idx].cli ? tbsockets[idx].cli->io.fd : -1;
533
534                        strcpy(tbsockets[idx].estado, state); // Actualiza el estado del cliente
535                        if (sock >= 0 && !mandaTrama(&sock, ptrTrama)) {
536                                syslog(LOG_ERR, "failed to send response to %s:%s\n",
537                                       ips_array[i], strerror(errno));
538                        }
539                }
540        }
541        return true;
542}
543
544// ________________________________________________________________________________________________________
545// Función: Levanta
546//
547//      Descripción:
548//              Enciende ordenadores a través de la red cuyas macs se pasan como parámetro
549//      Parámetros:
550//              - iph: Cadena de direcciones ip separadas por ";"
551//              - mac: Cadena de direcciones mac separadas por ";"
552//              - mar: Método de arranque (1=Broadcast, 2=Unicast)
553//      Devuelve:
554//              true: Si el proceso es correcto
555//              false: En caso de ocurrir algún error
556// ________________________________________________________________________________________________________
557
558bool Levanta(char *ptrIP[], char *ptrMacs[], int lon, char *mar)
559{
560        unsigned int on = 1;
561        struct sockaddr_in local;
562        int i, res;
563        int s;
564
565        /* Creación de socket para envío de magig packet */
566        s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
567        if (s < 0) {
568                syslog(LOG_ERR, "cannot create socket for magic packet\n");
569                return false;
570        }
571        res = setsockopt(s, SOL_SOCKET, SO_BROADCAST, (unsigned int *) &on,
572                         sizeof(on));
573        if (res < 0) {
574                syslog(LOG_ERR, "cannot set broadcast socket\n");
575                return false;
576        }
577        memset(&local, 0, sizeof(local));
578        local.sin_family = AF_INET;
579        local.sin_port = htons(PUERTO_WAKEUP);
580        local.sin_addr.s_addr = htonl(INADDR_ANY);
581
582        for (i = 0; i < lon; i++) {
583                if (!WakeUp(s, ptrIP[i], ptrMacs[i], mar)) {
584                        syslog(LOG_ERR, "problem sending magic packet\n");
585                        close(s);
586                        return false;
587                }
588        }
589        close(s);
590        return true;
591}
592
593#define OG_WOL_SEQUENCE         6
594#define OG_WOL_MACADDR_LEN      6
595#define OG_WOL_REPEAT           16
596
597struct wol_msg {
598        char secuencia_FF[OG_WOL_SEQUENCE];
599        char macbin[OG_WOL_REPEAT][OG_WOL_MACADDR_LEN];
600};
601
602static bool wake_up_broadcast(int sd, struct sockaddr_in *client,
603                              const struct wol_msg *msg)
604{
605        struct sockaddr_in *broadcast_addr;
606        struct ifaddrs *ifaddr, *ifa;
607        int ret;
608
609        if (getifaddrs(&ifaddr) < 0) {
610                syslog(LOG_ERR, "cannot get list of addresses\n");
611                return false;
612        }
613
614        client->sin_addr.s_addr = htonl(INADDR_BROADCAST);
615
616        for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
617                if (ifa->ifa_addr == NULL ||
618                    ifa->ifa_addr->sa_family != AF_INET ||
619                    strcmp(ifa->ifa_name, interface) != 0)
620                        continue;
621
622                broadcast_addr =
623                        (struct sockaddr_in *)ifa->ifa_ifu.ifu_broadaddr;
624                client->sin_addr.s_addr = broadcast_addr->sin_addr.s_addr;
625                break;
626        }
627        freeifaddrs(ifaddr);
628
629        ret = sendto(sd, msg, sizeof(*msg), 0,
630                     (struct sockaddr *)client, sizeof(*client));
631        if (ret < 0) {
632                syslog(LOG_ERR, "failed to send broadcast wol\n");
633                return false;
634        }
635
636        return true;
637}
638
639static bool wake_up_unicast(int sd, struct sockaddr_in *client,
640                            const struct wol_msg *msg,
641                            const struct in_addr *addr)
642{
643        int ret;
644
645        client->sin_addr.s_addr = addr->s_addr;
646
647        ret = sendto(sd, msg, sizeof(*msg), 0,
648                     (struct sockaddr *)client, sizeof(*client));
649        if (ret < 0) {
650                syslog(LOG_ERR, "failed to send unicast wol\n");
651                return false;
652        }
653
654        return true;
655}
656
657enum wol_delivery_type {
658        OG_WOL_BROADCAST = 1,
659        OG_WOL_UNICAST = 2
660};
661
662//_____________________________________________________________________________________________________________
663// Función: WakeUp
664//
665//       Descripción:
666//              Enciende el ordenador cuya MAC se pasa como parámetro
667//      Parámetros:
668//              - s : Socket para enviar trama magic packet
669//              - iph : Cadena con la dirección ip
670//              - mac : Cadena con la dirección mac en formato XXXXXXXXXXXX
671//              - mar: Método de arranque (1=Broadcast, 2=Unicast)
672//      Devuelve:
673//              true: Si el proceso es correcto
674//              false: En caso de ocurrir algún error
675//_____________________________________________________________________________________________________________
676//
677bool WakeUp(int s, char* iph, char *mac, char *mar)
678{
679        unsigned int macaddr[OG_WOL_MACADDR_LEN];
680        char HDaddress_bin[OG_WOL_MACADDR_LEN];
681        struct sockaddr_in WakeUpCliente;
682        struct wol_msg Trama_WakeUp;
683        struct in_addr addr;
684        bool ret;
685        int i;
686
687        for (i = 0; i < 6; i++) // Primera secuencia de la trama Wake Up (0xFFFFFFFFFFFF)
688                Trama_WakeUp.secuencia_FF[i] = 0xFF;
689
690        sscanf(mac, "%02x%02x%02x%02x%02x%02x",
691               &macaddr[0], &macaddr[1], &macaddr[2],
692               &macaddr[3], &macaddr[4], &macaddr[5]);
693
694        for (i = 0; i < 6; i++)
695                HDaddress_bin[i] = (uint8_t)macaddr[i];
696
697        for (i = 0; i < 16; i++) // Segunda secuencia de la trama Wake Up , repetir 16 veces su la MAC
698                memcpy(&Trama_WakeUp.macbin[i][0], &HDaddress_bin, 6);
699
700        /* Creación de socket del cliente que recibe la trama magic packet */
701        WakeUpCliente.sin_family = AF_INET;
702        WakeUpCliente.sin_port = htons((short) PUERTO_WAKEUP);
703
704        switch (atoi(mar)) {
705        case OG_WOL_BROADCAST:
706                ret = wake_up_broadcast(s, &WakeUpCliente, &Trama_WakeUp);
707                break;
708        case OG_WOL_UNICAST:
709                if (inet_aton(iph, &addr) < 0) {
710                        syslog(LOG_ERR, "bad IP address for unicast wol\n");
711                        ret = false;
712                        break;
713                }
714                ret = wake_up_unicast(s, &WakeUpCliente, &Trama_WakeUp, &addr);
715                break;
716        default:
717                syslog(LOG_ERR, "unknown wol type\n");
718                ret = false;
719                break;
720        }
721        return ret;
722}
723
724// ________________________________________________________________________________________________________
725// Función: actualizaCreacionImagen
726//
727//      Descripción:
728//              Esta función actualiza la base de datos con el resultado de la creación de una imagen
729//      Parámetros:
730//              - db: Objeto base de datos (ya operativo)
731//              - tbl: Objeto tabla
732//              - idi: Identificador de la imagen
733//              - dsk: Disco de donde se creó
734//              - par: Partición de donde se creó
735//              - cpt: Código de partición
736//              - ipr: Ip del repositorio
737//              - ido: Identificador del ordenador modelo
738//      Devuelve:
739//              true: Si el proceso es correcto
740//              false: En caso de ocurrir algún error
741// ________________________________________________________________________________________________________
742bool actualizaCreacionImagen(struct og_dbi *dbi, char *idi, char *dsk,
743                             char *par, char *cpt, char *ipr, char *ido)
744{
745        const char *msglog;
746        dbi_result result;
747        int idr,ifs;
748
749        /* Toma identificador del repositorio correspondiente al ordenador modelo */
750        result = dbi_conn_queryf(dbi->conn,
751                        "SELECT repositorios.idrepositorio"
752                        "  FROM repositorios"
753                        "  LEFT JOIN ordenadores USING (idrepositorio)"
754                        " WHERE repositorios.ip='%s' AND ordenadores.idordenador=%s", ipr, ido);
755
756        if (!result) {
757                dbi_conn_error(dbi->conn, &msglog);
758                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
759                       __func__, __LINE__, msglog);
760                return false;
761        }
762        if (!dbi_result_next_row(result)) {
763                syslog(LOG_ERR,
764                       "repository does not exist in database (%s:%d)\n",
765                       __func__, __LINE__);
766                dbi_result_free(result);
767                return false;
768        }
769        idr = dbi_result_get_uint(result, "idrepositorio");
770        dbi_result_free(result);
771
772        /* Toma identificador del perfilsoftware */
773        result = dbi_conn_queryf(dbi->conn,
774                        "SELECT idperfilsoft"
775                        "  FROM ordenadores_particiones"
776                        " WHERE idordenador=%s AND numdisk=%s AND numpar=%s", ido, dsk, par);
777
778        if (!result) {
779                dbi_conn_error(dbi->conn, &msglog);
780                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
781                       __func__, __LINE__, msglog);
782                return false;
783        }
784        if (!dbi_result_next_row(result)) {
785                syslog(LOG_ERR,
786                       "software profile does not exist in database (%s:%d)\n",
787                       __func__, __LINE__);
788                dbi_result_free(result);
789                return false;
790        }
791        ifs = dbi_result_get_uint(result, "idperfilsoft");
792        dbi_result_free(result);
793
794        /* Actualizar los datos de la imagen */
795        result = dbi_conn_queryf(dbi->conn,
796                "UPDATE imagenes"
797                "   SET idordenador=%s, numdisk=%s, numpar=%s, codpar=%s,"
798                "       idperfilsoft=%d, idrepositorio=%d,"
799                "       fechacreacion=NOW(), revision=revision+1"
800                " WHERE idimagen=%s", ido, dsk, par, cpt, ifs, idr, idi);
801
802        if (!result) {
803                dbi_conn_error(dbi->conn, &msglog);
804                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
805                       __func__, __LINE__, msglog);
806                return false;
807        }
808        dbi_result_free(result);
809
810        /* Actualizar los datos en el cliente */
811        result = dbi_conn_queryf(dbi->conn,
812                "UPDATE ordenadores_particiones"
813                "   SET idimagen=%s, revision=(SELECT revision FROM imagenes WHERE idimagen=%s),"
814                "       fechadespliegue=NOW()"
815                " WHERE idordenador=%s AND numdisk=%s AND numpar=%s",
816                idi, idi, ido, dsk, par);
817        if (!result) {
818                dbi_conn_error(dbi->conn, &msglog);
819                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
820                       __func__, __LINE__, msglog);
821                return false;
822        }
823        dbi_result_free(result);
824
825        return true;
826}
827
828// ________________________________________________________________________________________________________
829// Función: actualizaRestauracionImagen
830//
831//      Descripción:
832//              Esta función actualiza la base de datos con el resultado de la restauración de una imagen
833//      Parámetros:
834//              - db: Objeto base de datos (ya operativo)
835//              - tbl: Objeto tabla
836//              - idi: Identificador de la imagen
837//              - dsk: Disco de donde se restauró
838//              - par: Partición de donde se restauró
839//              - ido: Identificador del cliente donde se restauró
840//              - ifs: Identificador del perfil software contenido      en la imagen
841//      Devuelve:
842//              true: Si el proceso es correcto
843//              false: En caso de ocurrir algún error
844// ________________________________________________________________________________________________________
845bool actualizaRestauracionImagen(struct og_dbi *dbi, char *idi,
846                                 char *dsk, char *par, char *ido, char *ifs)
847{
848        const char *msglog;
849        dbi_result result;
850
851        /* Actualizar los datos de la imagen */
852        result = dbi_conn_queryf(dbi->conn,
853                        "UPDATE ordenadores_particiones"
854                        "   SET idimagen=%s, idperfilsoft=%s, fechadespliegue=NOW(),"
855                        "       revision=(SELECT revision FROM imagenes WHERE idimagen=%s),"
856                        "       idnombreso=IFNULL((SELECT idnombreso FROM perfilessoft WHERE idperfilsoft=%s),0)"
857                        " WHERE idordenador=%s AND numdisk=%s AND numpar=%s", idi, ifs, idi, ifs, ido, dsk, par);
858
859        if (!result) {
860                dbi_conn_error(dbi->conn, &msglog);
861                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
862                       __func__, __LINE__, msglog);
863                return false;
864        }
865        dbi_result_free(result);
866
867        return true;
868}
869// ________________________________________________________________________________________________________
870// Función: actualizaHardware
871//
872//              Descripción:
873//                      Actualiza la base de datos con la configuracion hardware del cliente
874//              Parámetros:
875//                      - db: Objeto base de datos (ya operativo)
876//                      - tbl: Objeto tabla
877//                      - hrd: cadena con el inventario hardware
878//                      - ido: Identificador del ordenador
879//                      - npc: Nombre del ordenador
880//                      - idc: Identificador del centro o Unidad organizativa
881// ________________________________________________________________________________________________________
882//
883bool actualizaHardware(struct og_dbi *dbi, char *hrd, char *ido, char *npc,
884                       char *idc)
885{
886        const char *msglog;
887        int idtipohardware, idperfilhard;
888        int lon, i, j, aux;
889        bool retval;
890        char *whard;
891        int tbidhardware[MAXHARDWARE];
892        char *tbHardware[MAXHARDWARE],*dualHardware[2], strInt[LONINT], *idhardwares;
893        dbi_result result;
894
895        /* Toma Centro (Unidad Organizativa) */
896        result = dbi_conn_queryf(dbi->conn,
897                                 "SELECT idperfilhard FROM ordenadores WHERE idordenador=%s",
898                                 ido);
899        if (!result) {
900                dbi_conn_error(dbi->conn, &msglog);
901                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
902                       __func__, __LINE__, msglog);
903                return false;
904        }
905        if (!dbi_result_next_row(result)) {
906                syslog(LOG_ERR, "client does not exist in database (%s:%d)\n",
907                       __func__, __LINE__);
908                dbi_result_free(result);
909                return false;
910        }
911        idperfilhard = dbi_result_get_uint(result, "idperfilhard");
912        dbi_result_free(result);
913
914        whard=escaparCadena(hrd); // Codificar comillas simples
915        if(!whard)
916                return false;
917        /* Recorre componentes hardware*/
918        lon = splitCadena(tbHardware, whard, '\n');
919        if (lon > MAXHARDWARE)
920                lon = MAXHARDWARE; // Limita el número de componentes hardware
921        /*
922         for (i=0;i<lon;i++){
923         sprintf(msglog,"Linea de inventario: %s",tbHardware[i]);
924         RegistraLog(msglog,false);
925         }
926         */
927        for (i = 0; i < lon; i++) {
928                splitCadena(dualHardware, rTrim(tbHardware[i]), '=');
929                //sprintf(msglog,"nemonico: %s",dualHardware[0]);
930                //RegistraLog(msglog,false);
931                //sprintf(msglog,"valor: %s",dualHardware[1]);
932                //RegistraLog(msglog,false);
933                result = dbi_conn_queryf(dbi->conn,
934                                         "SELECT idtipohardware,descripcion FROM tipohardwares WHERE nemonico='%s'",
935                                         dualHardware[0]);
936                if (!result) {
937                        dbi_conn_error(dbi->conn, &msglog);
938                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
939                               __func__, __LINE__, msglog);
940                        return false;
941                }
942                if (!dbi_result_next_row(result)) { //  Tipo de Hardware NO existente
943                        dbi_result_free(result);
944                        return false;
945                } else { //  Tipo de Hardware Existe
946                        idtipohardware = dbi_result_get_uint(result, "idtipohardware");
947                        dbi_result_free(result);
948
949                        result = dbi_conn_queryf(dbi->conn,
950                                                 "SELECT idhardware FROM hardwares WHERE idtipohardware=%d AND descripcion='%s'",
951                                                 idtipohardware, dualHardware[1]);
952
953                        if (!result) {
954                                dbi_conn_error(dbi->conn, &msglog);
955                                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
956                                       __func__, __LINE__, msglog);
957                                return false;
958                        }
959
960                        if (!dbi_result_next_row(result)) { //  Hardware NO existente
961                                dbi_result_free(result);
962                                result = dbi_conn_queryf(dbi->conn,
963                                                        "INSERT hardwares (idtipohardware,descripcion,idcentro,grupoid) "
964                                                        " VALUES(%d,'%s',%s,0)", idtipohardware,
965                                                dualHardware[1], idc);
966                                if (!result) {
967                                        dbi_conn_error(dbi->conn, &msglog);
968                                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
969                                               __func__, __LINE__, msglog);
970                                        return false;
971                                }
972
973                                // Recupera el identificador del hardware
974                                tbidhardware[i] = dbi_conn_sequence_last(dbi->conn, NULL);
975                        } else {
976                                tbidhardware[i] = dbi_result_get_uint(result, "idhardware");
977                        }
978                        dbi_result_free(result);
979                }
980        }
981        // Ordena tabla de identificadores para cosultar si existe un pefil con esas especificaciones
982
983        for (i = 0; i < lon - 1; i++) {
984                for (j = i + 1; j < lon; j++) {
985                        if (tbidhardware[i] > tbidhardware[j]) {
986                                aux = tbidhardware[i];
987                                tbidhardware[i] = tbidhardware[j];
988                                tbidhardware[j] = aux;
989                        }
990                }
991        }
992        /* Crea cadena de identificadores de componentes hardware separados por coma */
993        sprintf(strInt, "%d", tbidhardware[lon - 1]); // Pasa a cadena el último identificador que es de mayor longitud
994        aux = strlen(strInt); // Calcula longitud de cadena para reservar espacio a todos los perfiles
995        idhardwares = calloc(1, sizeof(aux) * lon + lon);
996        if (idhardwares == NULL) {
997                syslog(LOG_ERR, "%s:%d OOM\n", __FILE__, __LINE__);
998                return false;
999        }
1000        aux = sprintf(idhardwares, "%d", tbidhardware[0]);
1001        for (i = 1; i < lon; i++)
1002                aux += sprintf(idhardwares + aux, ",%d", tbidhardware[i]);
1003
1004        if (!cuestionPerfilHardware(dbi, idc, ido, idperfilhard, idhardwares,
1005                        npc, tbidhardware, lon)) {
1006                syslog(LOG_ERR, "Problem updating client hardware\n");
1007                retval=false;
1008        } else {
1009                retval=true;
1010        }
1011        free(whard);
1012        free(idhardwares);
1013
1014        return (retval);
1015}
1016// ________________________________________________________________________________________________________
1017// Función: cuestionPerfilHardware
1018//
1019//              Descripción:
1020//                      Comprueba existencia de perfil hardware y actualización de éste para el ordenador
1021//              Parámetros:
1022//                      - db: Objeto base de datos (ya operativo)
1023//                      - tbl: Objeto tabla
1024//                      - idc: Identificador de la Unidad organizativa donde se encuentra el cliente
1025//                      - ido: Identificador del ordenador
1026//                      - tbidhardware: Identificador del tipo de hardware
1027//                      - con: Número de componentes detectados para configurar un el perfil hardware
1028//                      - npc: Nombre del cliente
1029// ________________________________________________________________________________________________________
1030bool cuestionPerfilHardware(struct og_dbi *dbi, char *idc, char *ido,
1031                int idperfilhardware, char *idhardwares, char *npc, int *tbidhardware,
1032                int lon)
1033{
1034        const char *msglog;
1035        dbi_result result;
1036        int i;
1037        int nwidperfilhard;
1038
1039        // Busca perfil hard del ordenador que contenga todos los componentes hardware encontrados
1040        result = dbi_conn_queryf(dbi->conn,
1041                "SELECT idperfilhard FROM"
1042                " (SELECT perfileshard_hardwares.idperfilhard as idperfilhard,"
1043                "       group_concat(cast(perfileshard_hardwares.idhardware AS char( 11) )"
1044                "       ORDER BY perfileshard_hardwares.idhardware SEPARATOR ',' ) AS idhardwares"
1045                " FROM  perfileshard_hardwares"
1046                " GROUP BY perfileshard_hardwares.idperfilhard) AS temp"
1047                " WHERE idhardwares LIKE '%s'", idhardwares);
1048
1049        if (!result) {
1050                dbi_conn_error(dbi->conn, &msglog);
1051                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1052                       __func__, __LINE__, msglog);
1053                return false;
1054        }
1055        if (!dbi_result_next_row(result)) {
1056                // No existe un perfil hardware con esos componentes de componentes hardware, lo crea
1057                dbi_result_free(result);
1058                result = dbi_conn_queryf(dbi->conn,
1059                                "INSERT perfileshard  (descripcion,idcentro,grupoid)"
1060                                " VALUES('Perfil hardware (%s) ',%s,0)", npc, idc);
1061                if (!result) {
1062                        dbi_conn_error(dbi->conn, &msglog);
1063                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1064                               __func__, __LINE__, msglog);
1065                        return false;
1066                }
1067                dbi_result_free(result);
1068
1069                // Recupera el identificador del nuevo perfil hardware
1070                nwidperfilhard = dbi_conn_sequence_last(dbi->conn, NULL);
1071
1072                // Crea la relación entre perfiles y componenetes hardware
1073                for (i = 0; i < lon; i++) {
1074                        result = dbi_conn_queryf(dbi->conn,
1075                                        "INSERT perfileshard_hardwares  (idperfilhard,idhardware)"
1076                                                " VALUES(%d,%d)", nwidperfilhard, tbidhardware[i]);
1077                        if (!result) {
1078                                dbi_conn_error(dbi->conn, &msglog);
1079                                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1080                                       __func__, __LINE__, msglog);
1081                                return false;
1082                        }
1083                        dbi_result_free(result);
1084                }
1085        } else { // Existe un perfil con todos esos componentes
1086                nwidperfilhard = dbi_result_get_uint(result, "idperfilhard");
1087                dbi_result_free(result);
1088        }
1089        if (idperfilhardware != nwidperfilhard) { // No coinciden los perfiles
1090                // Actualiza el identificador del perfil hardware del ordenador
1091                result = dbi_conn_queryf(dbi->conn,
1092                        "UPDATE ordenadores SET idperfilhard=%d"
1093                        " WHERE idordenador=%s", nwidperfilhard, ido);
1094                if (!result) {
1095                        dbi_conn_error(dbi->conn, &msglog);
1096                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1097                               __func__, __LINE__, msglog);
1098                        return false;
1099                }
1100                dbi_result_free(result);
1101        }
1102        /* Eliminar Relación de hardwares con Perfiles hardware que quedan húerfanos */
1103        result = dbi_conn_queryf(dbi->conn,
1104                "DELETE FROM perfileshard_hardwares WHERE idperfilhard IN "
1105                " (SELECT idperfilhard FROM perfileshard WHERE idperfilhard NOT IN"
1106                " (SELECT DISTINCT idperfilhard from ordenadores))");
1107        if (!result) {
1108                dbi_conn_error(dbi->conn, &msglog);
1109                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1110                       __func__, __LINE__, msglog);
1111                return false;
1112        }
1113        dbi_result_free(result);
1114
1115        /* Eliminar Perfiles hardware que quedan húerfanos */
1116        result = dbi_conn_queryf(dbi->conn,
1117                        "DELETE FROM perfileshard WHERE idperfilhard NOT IN"
1118                        " (SELECT DISTINCT idperfilhard FROM ordenadores)");
1119        if (!result) {
1120                dbi_conn_error(dbi->conn, &msglog);
1121                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1122                       __func__, __LINE__, msglog);
1123                return false;
1124        }
1125        dbi_result_free(result);
1126
1127        /* Eliminar Relación de hardwares con Perfiles hardware que quedan húerfanos */
1128        result = dbi_conn_queryf(dbi->conn,
1129                        "DELETE FROM perfileshard_hardwares WHERE idperfilhard NOT IN"
1130                        " (SELECT idperfilhard FROM perfileshard)");
1131        if (!result) {
1132                dbi_conn_error(dbi->conn, &msglog);
1133                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1134                       __func__, __LINE__, msglog);
1135                return false;
1136        }
1137        dbi_result_free(result);
1138
1139        return true;
1140}
1141// ________________________________________________________________________________________________________
1142// Función: actualizaSoftware
1143//
1144//      Descripción:
1145//              Actualiza la base de datos con la configuración software del cliente
1146//      Parámetros:
1147//              - db: Objeto base de datos (ya operativo)
1148//              - tbl: Objeto tabla
1149//              - sft: cadena con el inventario software
1150//              - par: Número de la partición
1151//              - ido: Identificador del ordenador del cliente en la tabla
1152//              - npc: Nombre del ordenador
1153//              - idc: Identificador del centro o Unidad organizativa
1154//      Devuelve:
1155//              true: Si el proceso es correcto
1156//              false: En caso de ocurrir algún error
1157//
1158//      Versión 1.1.0: Se incluye el sistema operativo. Autora: Irina Gómez - ETSII Universidad Sevilla
1159// ________________________________________________________________________________________________________
1160bool actualizaSoftware(struct og_dbi *dbi, char *sft, char *par,char *ido,
1161                       char *npc, char *idc)
1162{
1163        int i, j, lon, aux, idperfilsoft, idnombreso;
1164        bool retval;
1165        char *wsft;
1166        int tbidsoftware[MAXSOFTWARE];
1167        char *tbSoftware[MAXSOFTWARE], strInt[LONINT], *idsoftwares;
1168        const char *msglog;
1169        dbi_result result;
1170
1171        /* Toma Centro (Unidad Organizativa) y perfil software */
1172        result = dbi_conn_queryf(dbi->conn,
1173                "SELECT idperfilsoft,numpar"
1174                " FROM ordenadores_particiones"
1175                " WHERE idordenador=%s", ido);
1176        if (!result) {
1177                dbi_conn_error(dbi->conn, &msglog);
1178                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1179                       __func__, __LINE__, msglog);
1180                return false;
1181        }
1182        idperfilsoft = 0; // Por defecto se supone que el ordenador no tiene aún detectado el perfil software
1183        while (dbi_result_next_row(result)) {
1184                aux = dbi_result_get_uint(result, "numpar");
1185                if (aux == atoi(par)) { // Se encuentra la partición
1186                        idperfilsoft = dbi_result_get_uint(result, "idperfilsoft");
1187                        break;
1188                }
1189        }
1190        dbi_result_free(result);
1191        wsft=escaparCadena(sft); // Codificar comillas simples
1192        if(!wsft)
1193                return false;
1194
1195        /* Recorre componentes software*/
1196        lon = splitCadena(tbSoftware, wsft, '\n');
1197
1198        if (lon == 0)
1199                return true; // No hay lineas que procesar
1200        if (lon > MAXSOFTWARE)
1201                lon = MAXSOFTWARE; // Limita el número de componentes software
1202
1203        idnombreso = 0;
1204        for (i = 0; i < lon; i++) {
1205                // Primera línea es el sistema operativo: se obtiene identificador
1206                if (i == 0) {
1207                        idnombreso = checkDato(dbi, rTrim(tbSoftware[i]), "nombresos", "nombreso", "idnombreso");
1208                        continue;
1209                }
1210
1211                result = dbi_conn_queryf(dbi->conn,
1212                                "SELECT idsoftware FROM softwares WHERE descripcion ='%s'",
1213                                rTrim(tbSoftware[i]));
1214                if (!result) {
1215                        dbi_conn_error(dbi->conn, &msglog);
1216                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1217                               __func__, __LINE__, msglog);
1218                        return false;
1219                }
1220
1221                if (!dbi_result_next_row(result)) {
1222                        dbi_result_free(result);
1223                        result = dbi_conn_queryf(dbi->conn,
1224                                                "INSERT INTO softwares (idtiposoftware,descripcion,idcentro,grupoid)"
1225                                                " VALUES(2,'%s',%s,0)", tbSoftware[i], idc);
1226                        if (!result) { // Error al insertar
1227                                dbi_conn_error(dbi->conn, &msglog);
1228                                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1229                                       __func__, __LINE__, msglog);
1230                                return false;
1231                        }
1232
1233                        // Recupera el identificador del software
1234                        tbidsoftware[i] = dbi_conn_sequence_last(dbi->conn, NULL);
1235                } else {
1236                        tbidsoftware[i] = dbi_result_get_uint(result, "idsoftware");
1237                }
1238                dbi_result_free(result);
1239        }
1240
1241        // Ordena tabla de identificadores para cosultar si existe un pefil con esas especificaciones
1242
1243        for (i = 0; i < lon - 1; i++) {
1244                for (j = i + 1; j < lon; j++) {
1245                        if (tbidsoftware[i] > tbidsoftware[j]) {
1246                                aux = tbidsoftware[i];
1247                                tbidsoftware[i] = tbidsoftware[j];
1248                                tbidsoftware[j] = aux;
1249                        }
1250                }
1251        }
1252        /* Crea cadena de identificadores de componentes software separados por coma */
1253        sprintf(strInt, "%d", tbidsoftware[lon - 1]); // Pasa a cadena el último identificador que es de mayor longitud
1254        aux = strlen(strInt); // Calcula longitud de cadena para reservar espacio a todos los perfiles
1255        idsoftwares = calloc(1, (sizeof(aux)+1) * lon + lon);
1256        if (idsoftwares == NULL) {
1257                syslog(LOG_ERR, "%s:%d OOM\n", __FILE__, __LINE__);
1258                return false;
1259        }
1260        aux = sprintf(idsoftwares, "%d", tbidsoftware[0]);
1261        for (i = 1; i < lon; i++)
1262                aux += sprintf(idsoftwares + aux, ",%d", tbidsoftware[i]);
1263
1264        // Comprueba existencia de perfil software y actualización de éste para el ordenador
1265        if (!cuestionPerfilSoftware(dbi, idc, ido, idperfilsoft, idnombreso, idsoftwares,
1266                        npc, par, tbidsoftware, lon)) {
1267                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1268                       __func__, __LINE__, msglog);
1269                retval=false;
1270        } else {
1271                retval=true;
1272        }
1273        free(wsft);
1274        free(idsoftwares);
1275
1276        return retval;
1277}
1278// ________________________________________________________________________________________________________
1279// Función: CuestionPerfilSoftware
1280//
1281//      Parámetros:
1282//              - db: Objeto base de datos (ya operativo)
1283//              - tbl: Objeto tabla
1284//              - idcentro: Identificador del centro en la tabla
1285//              - ido: Identificador del ordenador del cliente en la tabla
1286//              - idnombreso: Identificador del sistema operativo
1287//              - idsoftwares: Cadena con los identificadores de componentes software separados por comas
1288//              - npc: Nombre del ordenador del cliente
1289//              - particion: Número de la partición
1290//              - tbidsoftware: Array con los identificadores de componentes software
1291//              - lon: Número de componentes
1292//      Devuelve:
1293//              true: Si el proceso es correcto
1294//              false: En caso de ocurrir algún error
1295//
1296//      Versión 1.1.0: Se incluye el sistema operativo. Autora: Irina Gómez - ETSII Universidad Sevilla
1297//_________________________________________________________________________________________________________
1298bool cuestionPerfilSoftware(struct og_dbi *dbi, char *idc, char *ido,
1299                            int idperfilsoftware, int idnombreso,
1300                            char *idsoftwares, char *npc, char *par,
1301                            int *tbidsoftware, int lon)
1302{
1303        int i, nwidperfilsoft;
1304        const char *msglog;
1305        dbi_result result;
1306
1307        // Busca perfil soft del ordenador que contenga todos los componentes software encontrados
1308        result = dbi_conn_queryf(dbi->conn,
1309                "SELECT idperfilsoft FROM"
1310                " (SELECT perfilessoft_softwares.idperfilsoft as idperfilsoft,"
1311                "       group_concat(cast(perfilessoft_softwares.idsoftware AS char( 11) )"
1312                "       ORDER BY perfilessoft_softwares.idsoftware SEPARATOR ',' ) AS idsoftwares"
1313                " FROM  perfilessoft_softwares"
1314                " GROUP BY perfilessoft_softwares.idperfilsoft) AS temp"
1315                " WHERE idsoftwares LIKE '%s'", idsoftwares);
1316
1317        if (!result) {
1318                dbi_conn_error(dbi->conn, &msglog);
1319                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1320                       __func__, __LINE__, msglog);
1321                return false;
1322        }
1323        if (!dbi_result_next_row(result)) { // No existe un perfil software con esos componentes de componentes software, lo crea
1324                dbi_result_free(result);
1325                result = dbi_conn_queryf(dbi->conn,
1326                                "INSERT perfilessoft  (descripcion, idcentro, grupoid, idnombreso)"
1327                                " VALUES('Perfil Software (%s, Part:%s) ',%s,0,%i)", npc, par, idc,idnombreso);
1328                if (!result) {
1329                        dbi_conn_error(dbi->conn, &msglog);
1330                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1331                               __func__, __LINE__, msglog);
1332                        return false;
1333                }
1334
1335                dbi_result_free(result);
1336                // Recupera el identificador del nuevo perfil software
1337                nwidperfilsoft = dbi_conn_sequence_last(dbi->conn, NULL);
1338
1339                // Crea la relación entre perfiles y componenetes software
1340                for (i = 0; i < lon; i++) {
1341                        result = dbi_conn_queryf(dbi->conn,
1342                                                "INSERT perfilessoft_softwares (idperfilsoft,idsoftware)"
1343                                                " VALUES(%d,%d)", nwidperfilsoft, tbidsoftware[i]);
1344                        if (!result) {
1345                                dbi_conn_error(dbi->conn, &msglog);
1346                                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1347                                       __func__, __LINE__, msglog);
1348                                return false;
1349                        }
1350                        dbi_result_free(result);
1351                }
1352        } else { // Existe un perfil con todos esos componentes
1353                nwidperfilsoft = dbi_result_get_uint(result, "idperfilsoft");
1354                dbi_result_free(result);
1355        }
1356
1357        if (idperfilsoftware != nwidperfilsoft) { // No coinciden los perfiles
1358                // Actualiza el identificador del perfil software del ordenador
1359                result = dbi_conn_queryf(dbi->conn,
1360                                "UPDATE ordenadores_particiones SET idperfilsoft=%d,idimagen=0"
1361                                " WHERE idordenador=%s AND numpar=%s", nwidperfilsoft, ido, par);
1362                if (!result) { // Error al insertar
1363                        dbi_conn_error(dbi->conn, &msglog);
1364                        syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1365                               __func__, __LINE__, msglog);
1366                        return false;
1367                }
1368                dbi_result_free(result);
1369        }
1370
1371        /* DEPURACIÓN DE PERFILES SOFTWARE */
1372
1373         /* Eliminar Relación de softwares con Perfiles software que quedan húerfanos */
1374        result = dbi_conn_queryf(dbi->conn,
1375                "DELETE FROM perfilessoft_softwares WHERE idperfilsoft IN "\
1376                " (SELECT idperfilsoft FROM perfilessoft WHERE idperfilsoft NOT IN"\
1377                " (SELECT DISTINCT idperfilsoft from ordenadores_particiones) AND idperfilsoft NOT IN"\
1378                " (SELECT DISTINCT idperfilsoft from imagenes))");
1379        if (!result) {
1380                dbi_conn_error(dbi->conn, &msglog);
1381                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1382                       __func__, __LINE__, msglog);
1383                return false;
1384        }
1385        dbi_result_free(result),
1386        /* Eliminar Perfiles software que quedan húerfanos */
1387        result = dbi_conn_queryf(dbi->conn,
1388                "DELETE FROM perfilessoft WHERE idperfilsoft NOT IN"
1389                " (SELECT DISTINCT idperfilsoft from ordenadores_particiones)"\
1390                " AND  idperfilsoft NOT IN"\
1391                " (SELECT DISTINCT idperfilsoft from imagenes)");
1392        if (!result) {
1393                dbi_conn_error(dbi->conn, &msglog);
1394                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1395                       __func__, __LINE__, msglog);
1396                return false;
1397        }
1398        dbi_result_free(result),
1399
1400        /* Eliminar Relación de softwares con Perfiles software que quedan húerfanos */
1401        result = dbi_conn_queryf(dbi->conn,
1402                        "DELETE FROM perfilessoft_softwares WHERE idperfilsoft NOT IN"
1403                        " (SELECT idperfilsoft from perfilessoft)");
1404        if (!result) {
1405                dbi_conn_error(dbi->conn, &msglog);
1406                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
1407                       __func__, __LINE__, msglog);
1408                return false;
1409        }
1410        dbi_result_free(result);
1411
1412        return true;
1413}
1414
1415static void og_client_release(struct ev_loop *loop, struct og_client *cli)
1416{
1417        if (cli->keepalive_idx >= 0) {
1418                syslog(LOG_DEBUG, "closing keepalive connection for %s:%hu in slot %d\n",
1419                       inet_ntoa(cli->addr.sin_addr),
1420                       ntohs(cli->addr.sin_port), cli->keepalive_idx);
1421                tbsockets[cli->keepalive_idx].cli = NULL;
1422        }
1423
1424        list_del(&cli->list);
1425        ev_io_stop(loop, &cli->io);
1426        close(cli->io.fd);
1427        free(cli);
1428}
1429
1430static void og_client_keepalive(struct ev_loop *loop, struct og_client *cli)
1431{
1432        struct og_client *old_cli;
1433
1434        old_cli = tbsockets[cli->keepalive_idx].cli;
1435        if (old_cli && old_cli != cli) {
1436                syslog(LOG_DEBUG, "closing old keepalive connection for %s:%hu\n",
1437                       inet_ntoa(old_cli->addr.sin_addr),
1438                       ntohs(old_cli->addr.sin_port));
1439
1440                og_client_release(loop, old_cli);
1441        }
1442        tbsockets[cli->keepalive_idx].cli = cli;
1443}
1444
1445static void og_client_reset_state(struct og_client *cli)
1446{
1447        cli->state = OG_CLIENT_RECEIVING_HEADER;
1448        cli->buf_len = 0;
1449}
1450
1451static TRAMA *og_msg_alloc(char *data, unsigned int len)
1452{
1453        TRAMA *ptrTrama;
1454
1455        ptrTrama = calloc(1, sizeof(TRAMA));
1456        if (!ptrTrama) {
1457                syslog(LOG_ERR, "OOM\n");
1458                return NULL;
1459        }
1460
1461        initParametros(ptrTrama, len);
1462        memcpy(ptrTrama, "@JMMLCAMDJ_MCDJ", LONGITUD_CABECERATRAMA);
1463        memcpy(ptrTrama->parametros, data, len);
1464        ptrTrama->lonprm = len;
1465
1466        return ptrTrama;
1467}
1468
1469static void og_msg_free(TRAMA *ptrTrama)
1470{
1471        free(ptrTrama->parametros);
1472        free(ptrTrama);
1473}
1474
1475#define OG_CLIENTS_MAX  4096
1476#define OG_PARTITION_MAX 4
1477
1478struct og_partition {
1479        const char      *disk;
1480        const char      *number;
1481        const char      *code;
1482        const char      *size;
1483        const char      *filesystem;
1484        const char      *format;
1485        const char      *os;
1486        const char      *used_size;
1487};
1488
1489struct og_sync_params {
1490        const char      *sync;
1491        const char      *diff;
1492        const char      *remove;
1493        const char      *compress;
1494        const char      *cleanup;
1495        const char      *cache;
1496        const char      *cleanup_cache;
1497        const char      *remove_dst;
1498        const char      *diff_id;
1499        const char      *diff_name;
1500        const char      *path;
1501        const char      *method;
1502};
1503
1504struct og_msg_params {
1505        const char      *ips_array[OG_CLIENTS_MAX];
1506        const char      *mac_array[OG_CLIENTS_MAX];
1507        unsigned int    ips_array_len;
1508        const char      *wol_type;
1509        char            run_cmd[4096];
1510        const char      *disk;
1511        const char      *partition;
1512        const char      *repository;
1513        const char      *name;
1514        const char      *id;
1515        const char      *code;
1516        const char      *type;
1517        const char      *profile;
1518        const char      *cache;
1519        const char      *cache_size;
1520        bool            echo;
1521        struct og_partition     partition_setup[OG_PARTITION_MAX];
1522        struct og_sync_params sync_setup;
1523        struct og_schedule_time time;
1524        const char      *task_id;
1525        uint64_t        flags;
1526};
1527
1528#define OG_COMPUTER_NAME_MAXLEN 100
1529
1530struct og_computer {
1531        unsigned int    id;
1532        unsigned int    center;
1533        unsigned int    room;
1534        char            name[OG_COMPUTER_NAME_MAXLEN + 1];
1535        unsigned int    procedure_id;
1536};
1537
1538#define OG_REST_PARAM_ADDR                      (1UL << 0)
1539#define OG_REST_PARAM_MAC                       (1UL << 1)
1540#define OG_REST_PARAM_WOL_TYPE                  (1UL << 2)
1541#define OG_REST_PARAM_RUN_CMD                   (1UL << 3)
1542#define OG_REST_PARAM_DISK                      (1UL << 4)
1543#define OG_REST_PARAM_PARTITION                 (1UL << 5)
1544#define OG_REST_PARAM_REPO                      (1UL << 6)
1545#define OG_REST_PARAM_NAME                      (1UL << 7)
1546#define OG_REST_PARAM_ID                        (1UL << 8)
1547#define OG_REST_PARAM_CODE                      (1UL << 9)
1548#define OG_REST_PARAM_TYPE                      (1UL << 10)
1549#define OG_REST_PARAM_PROFILE                   (1UL << 11)
1550#define OG_REST_PARAM_CACHE                     (1UL << 12)
1551#define OG_REST_PARAM_CACHE_SIZE                (1UL << 13)
1552#define OG_REST_PARAM_PART_0                    (1UL << 14)
1553#define OG_REST_PARAM_PART_1                    (1UL << 15)
1554#define OG_REST_PARAM_PART_2                    (1UL << 16)
1555#define OG_REST_PARAM_PART_3                    (1UL << 17)
1556#define OG_REST_PARAM_SYNC_SYNC                 (1UL << 18)
1557#define OG_REST_PARAM_SYNC_DIFF                 (1UL << 19)
1558#define OG_REST_PARAM_SYNC_REMOVE               (1UL << 20)
1559#define OG_REST_PARAM_SYNC_COMPRESS             (1UL << 21)
1560#define OG_REST_PARAM_SYNC_CLEANUP              (1UL << 22)
1561#define OG_REST_PARAM_SYNC_CACHE                (1UL << 23)
1562#define OG_REST_PARAM_SYNC_CLEANUP_CACHE        (1UL << 24)
1563#define OG_REST_PARAM_SYNC_REMOVE_DST           (1UL << 25)
1564#define OG_REST_PARAM_SYNC_DIFF_ID              (1UL << 26)
1565#define OG_REST_PARAM_SYNC_DIFF_NAME            (1UL << 27)
1566#define OG_REST_PARAM_SYNC_PATH                 (1UL << 28)
1567#define OG_REST_PARAM_SYNC_METHOD               (1UL << 29)
1568#define OG_REST_PARAM_ECHO                      (1UL << 30)
1569#define OG_REST_PARAM_TASK                      (1UL << 31)
1570#define OG_REST_PARAM_TIME_YEARS                (1UL << 32)
1571#define OG_REST_PARAM_TIME_MONTHS               (1UL << 33)
1572#define OG_REST_PARAM_TIME_WEEKS                (1UL << 34)
1573#define OG_REST_PARAM_TIME_WEEK_DAYS            (1UL << 35)
1574#define OG_REST_PARAM_TIME_DAYS                 (1UL << 36)
1575#define OG_REST_PARAM_TIME_HOURS                (1UL << 37)
1576#define OG_REST_PARAM_TIME_AM_PM                (1UL << 38)
1577#define OG_REST_PARAM_TIME_MINUTES              (1UL << 39)
1578
1579enum og_rest_method {
1580        OG_METHOD_GET   = 0,
1581        OG_METHOD_POST,
1582        OG_METHOD_NO_HTTP
1583};
1584
1585static struct og_client *og_client_find(const char *ip)
1586{
1587        struct og_client *client;
1588        struct in_addr addr;
1589        int res;
1590
1591        res = inet_aton(ip, &addr);
1592        if (!res) {
1593                syslog(LOG_ERR, "Invalid IP string: %s\n", ip);
1594                return NULL;
1595        }
1596
1597        list_for_each_entry(client, &client_list, list) {
1598                if (client->addr.sin_addr.s_addr == addr.s_addr && client->agent) {
1599                        return client;
1600                }
1601        }
1602
1603        return NULL;
1604}
1605
1606static bool og_msg_params_validate(const struct og_msg_params *params,
1607                                   const uint64_t flags)
1608{
1609        return (params->flags & flags) == flags;
1610}
1611
1612static int og_json_parse_clients(json_t *element, struct og_msg_params *params)
1613{
1614        unsigned int i;
1615        json_t *k;
1616
1617        if (json_typeof(element) != JSON_ARRAY)
1618                return -1;
1619
1620        for (i = 0; i < json_array_size(element); i++) {
1621                k = json_array_get(element, i);
1622                if (json_typeof(k) != JSON_STRING)
1623                        return -1;
1624
1625                params->ips_array[params->ips_array_len++] =
1626                        json_string_value(k);
1627
1628                params->flags |= OG_REST_PARAM_ADDR;
1629        }
1630
1631        return 0;
1632}
1633
1634static int og_json_parse_string(json_t *element, const char **str)
1635{
1636        if (json_typeof(element) != JSON_STRING)
1637                return -1;
1638
1639        *str = json_string_value(element);
1640        return 0;
1641}
1642
1643static int og_json_parse_uint(json_t *element, uint32_t *integer)
1644{
1645        if (json_typeof(element) != JSON_INTEGER)
1646                return -1;
1647
1648        *integer = json_integer_value(element);
1649        return 0;
1650}
1651
1652static int og_json_parse_bool(json_t *element, bool *value)
1653{
1654        if (json_typeof(element) == JSON_TRUE)
1655                *value = true;
1656        else if (json_typeof(element) == JSON_FALSE)
1657                *value = false;
1658        else
1659                return -1;
1660
1661        return 0;
1662}
1663
1664static int og_json_parse_sync_params(json_t *element,
1665                                     struct og_msg_params *params)
1666{
1667        const char *key;
1668        json_t *value;
1669        int err = 0;
1670
1671        json_object_foreach(element, key, value) {
1672                if (!strcmp(key, "sync")) {
1673                        err = og_json_parse_string(value, &params->sync_setup.sync);
1674                        params->flags |= OG_REST_PARAM_SYNC_SYNC;
1675                } else if (!strcmp(key, "diff")) {
1676                        err = og_json_parse_string(value, &params->sync_setup.diff);
1677                        params->flags |= OG_REST_PARAM_SYNC_DIFF;
1678                } else if (!strcmp(key, "remove")) {
1679                        err = og_json_parse_string(value, &params->sync_setup.remove);
1680                        params->flags |= OG_REST_PARAM_SYNC_REMOVE;
1681                } else if (!strcmp(key, "compress")) {
1682                        err = og_json_parse_string(value, &params->sync_setup.compress);
1683                        params->flags |= OG_REST_PARAM_SYNC_COMPRESS;
1684                } else if (!strcmp(key, "cleanup")) {
1685                        err = og_json_parse_string(value, &params->sync_setup.cleanup);
1686                        params->flags |= OG_REST_PARAM_SYNC_CLEANUP;
1687                } else if (!strcmp(key, "cache")) {
1688                        err = og_json_parse_string(value, &params->sync_setup.cache);
1689                        params->flags |= OG_REST_PARAM_SYNC_CACHE;
1690                } else if (!strcmp(key, "cleanup_cache")) {
1691                        err = og_json_parse_string(value, &params->sync_setup.cleanup_cache);
1692                        params->flags |= OG_REST_PARAM_SYNC_CLEANUP_CACHE;
1693                } else if (!strcmp(key, "remove_dst")) {
1694                        err = og_json_parse_string(value, &params->sync_setup.remove_dst);
1695                        params->flags |= OG_REST_PARAM_SYNC_REMOVE_DST;
1696                } else if (!strcmp(key, "diff_id")) {
1697                        err = og_json_parse_string(value, &params->sync_setup.diff_id);
1698                        params->flags |= OG_REST_PARAM_SYNC_DIFF_ID;
1699                } else if (!strcmp(key, "diff_name")) {
1700                        err = og_json_parse_string(value, &params->sync_setup.diff_name);
1701                        params->flags |= OG_REST_PARAM_SYNC_DIFF_NAME;
1702                } else if (!strcmp(key, "path")) {
1703                        err = og_json_parse_string(value, &params->sync_setup.path);
1704                        params->flags |= OG_REST_PARAM_SYNC_PATH;
1705                } else if (!strcmp(key, "method")) {
1706                        err = og_json_parse_string(value, &params->sync_setup.method);
1707                        params->flags |= OG_REST_PARAM_SYNC_METHOD;
1708                }
1709
1710                if (err != 0)
1711                        return err;
1712        }
1713        return err;
1714}
1715
1716#define OG_PARAM_PART_NUMBER                    (1UL << 0)
1717#define OG_PARAM_PART_CODE                      (1UL << 1)
1718#define OG_PARAM_PART_FILESYSTEM                (1UL << 2)
1719#define OG_PARAM_PART_SIZE                      (1UL << 3)
1720#define OG_PARAM_PART_FORMAT                    (1UL << 4)
1721#define OG_PARAM_PART_DISK                      (1UL << 5)
1722#define OG_PARAM_PART_OS                        (1UL << 6)
1723#define OG_PARAM_PART_USED_SIZE                 (1UL << 7)
1724
1725static int og_json_parse_partition(json_t *element,
1726                                   struct og_partition *part,
1727                                   uint64_t required_flags)
1728{
1729        uint64_t flags = 0UL;
1730        const char *key;
1731        json_t *value;
1732        int err = 0;
1733
1734        json_object_foreach(element, key, value) {
1735                if (!strcmp(key, "partition")) {
1736                        err = og_json_parse_string(value, &part->number);
1737                        flags |= OG_PARAM_PART_NUMBER;
1738                } else if (!strcmp(key, "code")) {
1739                        err = og_json_parse_string(value, &part->code);
1740                        flags |= OG_PARAM_PART_CODE;
1741                } else if (!strcmp(key, "filesystem")) {
1742                        err = og_json_parse_string(value, &part->filesystem);
1743                        flags |= OG_PARAM_PART_FILESYSTEM;
1744                } else if (!strcmp(key, "size")) {
1745                        err = og_json_parse_string(value, &part->size);
1746                        flags |= OG_PARAM_PART_SIZE;
1747                } else if (!strcmp(key, "format")) {
1748                        err = og_json_parse_string(value, &part->format);
1749                        flags |= OG_PARAM_PART_FORMAT;
1750                } else if (!strcmp(key, "disk")) {
1751                        err = og_json_parse_string(value, &part->disk);
1752                        flags |= OG_PARAM_PART_DISK;
1753                } else if (!strcmp(key, "os")) {
1754                        err = og_json_parse_string(value, &part->os);
1755                        flags |= OG_PARAM_PART_OS;
1756                } else if (!strcmp(key, "used_size")) {
1757                        err = og_json_parse_string(value, &part->used_size);
1758                        flags |= OG_PARAM_PART_USED_SIZE;
1759                }
1760
1761                if (err < 0)
1762                        return err;
1763        }
1764
1765        if (flags != required_flags)
1766                return -1;
1767
1768        return err;
1769}
1770
1771static int og_json_parse_partition_setup(json_t *element,
1772                                         struct og_msg_params *params)
1773{
1774        unsigned int i;
1775        json_t *k;
1776
1777        if (json_typeof(element) != JSON_ARRAY)
1778                return -1;
1779
1780        for (i = 0; i < json_array_size(element) && i < OG_PARTITION_MAX; ++i) {
1781                k = json_array_get(element, i);
1782
1783                if (json_typeof(k) != JSON_OBJECT)
1784                        return -1;
1785
1786                if (og_json_parse_partition(k, &params->partition_setup[i],
1787                                            OG_PARAM_PART_NUMBER |
1788                                            OG_PARAM_PART_CODE |
1789                                            OG_PARAM_PART_FILESYSTEM |
1790                                            OG_PARAM_PART_SIZE |
1791                                            OG_PARAM_PART_FORMAT) < 0)
1792                        return -1;
1793
1794                params->flags |= (OG_REST_PARAM_PART_0 << i);
1795        }
1796        return 0;
1797}
1798
1799static int og_json_parse_time_params(json_t *element,
1800                                     struct og_msg_params *params)
1801{
1802        const char *key;
1803        json_t *value;
1804        int err = 0;
1805
1806        json_object_foreach(element, key, value) {
1807                if (!strcmp(key, "years")) {
1808                        err = og_json_parse_uint(value, &params->time.years);
1809                        params->flags |= OG_REST_PARAM_TIME_YEARS;
1810                } else if (!strcmp(key, "months")) {
1811                        err = og_json_parse_uint(value, &params->time.months);
1812                        params->flags |= OG_REST_PARAM_TIME_MONTHS;
1813                } else if (!strcmp(key, "weeks")) {
1814                        err = og_json_parse_uint(value, &params->time.weeks);
1815                        params->flags |= OG_REST_PARAM_TIME_WEEKS;
1816                } else if (!strcmp(key, "week_days")) {
1817                        err = og_json_parse_uint(value, &params->time.week_days);
1818                        params->flags |= OG_REST_PARAM_TIME_WEEK_DAYS;
1819                } else if (!strcmp(key, "days")) {
1820                        err = og_json_parse_uint(value, &params->time.days);
1821                        params->flags |= OG_REST_PARAM_TIME_DAYS;
1822                } else if (!strcmp(key, "hours")) {
1823                        err = og_json_parse_uint(value, &params->time.hours);
1824                        params->flags |= OG_REST_PARAM_TIME_HOURS;
1825                } else if (!strcmp(key, "am_pm")) {
1826                        err = og_json_parse_uint(value, &params->time.am_pm);
1827                        params->flags |= OG_REST_PARAM_TIME_AM_PM;
1828                } else if (!strcmp(key, "minutes")) {
1829                        err = og_json_parse_uint(value, &params->time.minutes);
1830                        params->flags |= OG_REST_PARAM_TIME_MINUTES;
1831                }
1832                if (err != 0)
1833                        return err;
1834        }
1835
1836        return err;
1837}
1838
1839static const char *og_cmd_to_uri[OG_CMD_MAX] = {
1840        [OG_CMD_WOL]            = "wol",
1841        [OG_CMD_PROBE]          = "probe",
1842        [OG_CMD_SHELL_RUN]      = "shell/run",
1843        [OG_CMD_SESSION]        = "session",
1844        [OG_CMD_POWEROFF]       = "poweroff",
1845        [OG_CMD_REFRESH]        = "refresh",
1846        [OG_CMD_REBOOT]         = "reboot",
1847        [OG_CMD_STOP]           = "stop",
1848        [OG_CMD_HARDWARE]       = "hardware",
1849        [OG_CMD_SOFTWARE]       = "software",
1850        [OG_CMD_IMAGE_CREATE]   = "image/create",
1851        [OG_CMD_IMAGE_RESTORE]  = "image/restore",
1852        [OG_CMD_SETUP]          = "setup",
1853        [OG_CMD_RUN_SCHEDULE]   = "run/schedule",
1854};
1855
1856static bool og_client_is_busy(const struct og_client *cli,
1857                              enum og_cmd_type type)
1858{
1859        switch (type) {
1860        case OG_CMD_REBOOT:
1861        case OG_CMD_POWEROFF:
1862        case OG_CMD_STOP:
1863                break;
1864        default:
1865                if (cli->last_cmd != OG_CMD_UNSPEC)
1866                        return true;
1867                break;
1868        }
1869
1870        return false;
1871}
1872
1873static int og_send_request(enum og_rest_method method, enum og_cmd_type type,
1874                           const struct og_msg_params *params,
1875                           const json_t *data)
1876{
1877        const char *content_type = "Content-Type: application/json";
1878        char content [OG_MSG_REQUEST_MAXLEN - 700] = {};
1879        char buf[OG_MSG_REQUEST_MAXLEN] = {};
1880        unsigned int content_length;
1881        char method_str[5] = {};
1882        struct og_client *cli;
1883        const char *uri;
1884        unsigned int i;
1885        int client_sd;
1886
1887        if (method == OG_METHOD_GET)
1888                snprintf(method_str, 5, "GET");
1889        else if (method == OG_METHOD_POST)
1890                snprintf(method_str, 5, "POST");
1891        else
1892                return -1;
1893
1894        if (!data)
1895                content_length = 0;
1896        else
1897                content_length = json_dumpb(data, content,
1898                                            OG_MSG_REQUEST_MAXLEN - 700,
1899                                            JSON_COMPACT);
1900
1901        uri = og_cmd_to_uri[type];
1902        snprintf(buf, OG_MSG_REQUEST_MAXLEN,
1903                 "%s /%s HTTP/1.1\r\nContent-Length: %d\r\n%s\r\n\r\n%s",
1904                 method_str, uri, content_length, content_type, content);
1905
1906        for (i = 0; i < params->ips_array_len; i++) {
1907                cli = og_client_find(params->ips_array[i]);
1908                if (!cli)
1909                        continue;
1910
1911                if (og_client_is_busy(cli, type))
1912                        continue;
1913
1914                client_sd = cli->io.fd;
1915                if (client_sd < 0) {
1916                        syslog(LOG_INFO, "Client %s not conected\n",
1917                               params->ips_array[i]);
1918                        continue;
1919                }
1920
1921                if (send(client_sd, buf, strlen(buf), 0) < 0)
1922                        continue;
1923
1924                cli->last_cmd = type;
1925        }
1926
1927        return 0;
1928}
1929
1930static int og_cmd_post_clients(json_t *element, struct og_msg_params *params)
1931{
1932        const char *key;
1933        json_t *value;
1934        int err = 0;
1935
1936        if (json_typeof(element) != JSON_OBJECT)
1937                return -1;
1938
1939        json_object_foreach(element, key, value) {
1940                if (!strcmp(key, "clients"))
1941                        err = og_json_parse_clients(value, params);
1942
1943                if (err < 0)
1944                        break;
1945        }
1946
1947        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
1948                return -1;
1949
1950        return og_send_request(OG_METHOD_POST, OG_CMD_PROBE, params, NULL);
1951}
1952
1953struct og_buffer {
1954        char    *data;
1955        int     len;
1956};
1957
1958static int og_json_dump_clients(const char *buffer, size_t size, void *data)
1959{
1960        struct og_buffer *og_buffer = (struct og_buffer *)data;
1961
1962        memcpy(og_buffer->data + og_buffer->len, buffer, size);
1963        og_buffer->len += size;
1964
1965        return 0;
1966}
1967
1968static int og_cmd_get_clients(json_t *element, struct og_msg_params *params,
1969                              char *buffer_reply)
1970{
1971        json_t *root, *array, *addr, *state, *object;
1972        struct og_client *client;
1973        struct og_buffer og_buffer = {
1974                .data   = buffer_reply,
1975        };
1976
1977        array = json_array();
1978        if (!array)
1979                return -1;
1980
1981        list_for_each_entry(client, &client_list, list) {
1982                if (!client->agent)
1983                        continue;
1984
1985                object = json_object();
1986                if (!object) {
1987                        json_decref(array);
1988                        return -1;
1989                }
1990                addr = json_string(inet_ntoa(client->addr.sin_addr));
1991                if (!addr) {
1992                        json_decref(object);
1993                        json_decref(array);
1994                        return -1;
1995                }
1996                json_object_set_new(object, "addr", addr);
1997                state = json_string(og_client_status(client));
1998                if (!state) {
1999                        json_decref(object);
2000                        json_decref(array);
2001                        return -1;
2002                }
2003                json_object_set_new(object, "state", state);
2004                json_array_append_new(array, object);
2005        }
2006        root = json_pack("{s:o}", "clients", array);
2007        if (!root) {
2008                json_decref(array);
2009                return -1;
2010        }
2011
2012        json_dump_callback(root, og_json_dump_clients, &og_buffer, 0);
2013        json_decref(root);
2014
2015        return 0;
2016}
2017
2018static int og_json_parse_target(json_t *element, struct og_msg_params *params)
2019{
2020        const char *key;
2021        json_t *value;
2022
2023        if (json_typeof(element) != JSON_OBJECT) {
2024                return -1;
2025        }
2026
2027        json_object_foreach(element, key, value) {
2028                if (!strcmp(key, "addr")) {
2029                        if (json_typeof(value) != JSON_STRING)
2030                                return -1;
2031
2032                        params->ips_array[params->ips_array_len] =
2033                                json_string_value(value);
2034
2035                        params->flags |= OG_REST_PARAM_ADDR;
2036                } else if (!strcmp(key, "mac")) {
2037                        if (json_typeof(value) != JSON_STRING)
2038                                return -1;
2039
2040                        params->mac_array[params->ips_array_len] =
2041                                json_string_value(value);
2042
2043                        params->flags |= OG_REST_PARAM_MAC;
2044                }
2045        }
2046
2047        return 0;
2048}
2049
2050static int og_json_parse_targets(json_t *element, struct og_msg_params *params)
2051{
2052        unsigned int i;
2053        json_t *k;
2054        int err;
2055
2056        if (json_typeof(element) != JSON_ARRAY)
2057                return -1;
2058
2059        for (i = 0; i < json_array_size(element); i++) {
2060                k = json_array_get(element, i);
2061
2062                if (json_typeof(k) != JSON_OBJECT)
2063                        return -1;
2064
2065                err = og_json_parse_target(k, params);
2066                if (err < 0)
2067                        return err;
2068
2069                params->ips_array_len++;
2070        }
2071        return 0;
2072}
2073
2074static int og_json_parse_type(json_t *element, struct og_msg_params *params)
2075{
2076        const char *type;
2077
2078        if (json_typeof(element) != JSON_STRING)
2079                return -1;
2080
2081        params->wol_type = json_string_value(element);
2082
2083        type = json_string_value(element);
2084        if (!strcmp(type, "unicast"))
2085                params->wol_type = "2";
2086        else if (!strcmp(type, "broadcast"))
2087                params->wol_type = "1";
2088
2089        params->flags |= OG_REST_PARAM_WOL_TYPE;
2090
2091        return 0;
2092}
2093
2094static int og_cmd_wol(json_t *element, struct og_msg_params *params)
2095{
2096        const char *key;
2097        json_t *value;
2098        int err = 0;
2099
2100        if (json_typeof(element) != JSON_OBJECT)
2101                return -1;
2102
2103        json_object_foreach(element, key, value) {
2104                if (!strcmp(key, "clients")) {
2105                        err = og_json_parse_targets(value, params);
2106                } else if (!strcmp(key, "type")) {
2107                        err = og_json_parse_type(value, params);
2108                }
2109
2110                if (err < 0)
2111                        break;
2112        }
2113
2114        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
2115                                            OG_REST_PARAM_MAC |
2116                                            OG_REST_PARAM_WOL_TYPE))
2117                return -1;
2118
2119        if (!Levanta((char **)params->ips_array, (char **)params->mac_array,
2120                     params->ips_array_len, (char *)params->wol_type))
2121                return -1;
2122
2123        return 0;
2124}
2125
2126static int og_json_parse_run(json_t *element, struct og_msg_params *params)
2127{
2128        if (json_typeof(element) != JSON_STRING)
2129                return -1;
2130
2131        snprintf(params->run_cmd, sizeof(params->run_cmd), "%s",
2132                 json_string_value(element));
2133
2134        params->flags |= OG_REST_PARAM_RUN_CMD;
2135
2136        return 0;
2137}
2138
2139static int og_cmd_run_post(json_t *element, struct og_msg_params *params)
2140{
2141        json_t *value, *clients;
2142        const char *key;
2143        unsigned int i;
2144        int err = 0;
2145
2146        if (json_typeof(element) != JSON_OBJECT)
2147                return -1;
2148
2149        json_object_foreach(element, key, value) {
2150                if (!strcmp(key, "clients"))
2151                        err = og_json_parse_clients(value, params);
2152                else if (!strcmp(key, "run"))
2153                        err = og_json_parse_run(value, params);
2154                else if (!strcmp(key, "echo")) {
2155                        err = og_json_parse_bool(value, &params->echo);
2156                        params->flags |= OG_REST_PARAM_ECHO;
2157                }
2158
2159                if (err < 0)
2160                        break;
2161        }
2162
2163        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
2164                                            OG_REST_PARAM_RUN_CMD |
2165                                            OG_REST_PARAM_ECHO))
2166                return -1;
2167
2168        clients = json_copy(element);
2169        json_object_del(clients, "clients");
2170
2171        err = og_send_request(OG_METHOD_POST, OG_CMD_SHELL_RUN, params, clients);
2172        if (err < 0)
2173                return err;
2174
2175        for (i = 0; i < params->ips_array_len; i++) {
2176                char filename[4096];
2177                FILE *f;
2178
2179                sprintf(filename, "/tmp/_Seconsola_%s", params->ips_array[i]);
2180                f = fopen(filename, "wt");
2181                fclose(f);
2182        }
2183
2184        return 0;
2185}
2186
2187static int og_cmd_run_get(json_t *element, struct og_msg_params *params,
2188                          char *buffer_reply)
2189{
2190        struct og_buffer og_buffer = {
2191                .data   = buffer_reply,
2192        };
2193        json_t *root, *value, *array;
2194        const char *key;
2195        unsigned int i;
2196        int err = 0;
2197
2198        if (json_typeof(element) != JSON_OBJECT)
2199                return -1;
2200
2201        json_object_foreach(element, key, value) {
2202                if (!strcmp(key, "clients"))
2203                        err = og_json_parse_clients(value, params);
2204
2205                if (err < 0)
2206                        return err;
2207        }
2208
2209        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
2210                return -1;
2211
2212        array = json_array();
2213        if (!array)
2214                return -1;
2215
2216        for (i = 0; i < params->ips_array_len; i++) {
2217                json_t *object, *output, *addr;
2218                char data[4096] = {};
2219                char filename[4096];
2220                int fd, numbytes;
2221
2222                sprintf(filename, "/tmp/_Seconsola_%s", params->ips_array[i]);
2223
2224                fd = open(filename, O_RDONLY);
2225                if (!fd)
2226                        return -1;
2227
2228                numbytes = read(fd, data, sizeof(data));
2229                if (numbytes < 0) {
2230                        close(fd);
2231                        return -1;
2232                }
2233                data[sizeof(data) - 1] = '\0';
2234                close(fd);
2235
2236                object = json_object();
2237                if (!object) {
2238                        json_decref(array);
2239                        return -1;
2240                }
2241                addr = json_string(params->ips_array[i]);
2242                if (!addr) {
2243                        json_decref(object);
2244                        json_decref(array);
2245                        return -1;
2246                }
2247                json_object_set_new(object, "addr", addr);
2248
2249                output = json_string(data);
2250                if (!output) {
2251                        json_decref(object);
2252                        json_decref(array);
2253                        return -1;
2254                }
2255                json_object_set_new(object, "output", output);
2256
2257                json_array_append_new(array, object);
2258        }
2259
2260        root = json_pack("{s:o}", "clients", array);
2261        if (!root)
2262                return -1;
2263
2264        json_dump_callback(root, og_json_dump_clients, &og_buffer, 0);
2265        json_decref(root);
2266
2267        return 0;
2268}
2269
2270static int og_cmd_session(json_t *element, struct og_msg_params *params)
2271{
2272        json_t *clients, *value;
2273        const char *key;
2274        int err = 0;
2275
2276        if (json_typeof(element) != JSON_OBJECT)
2277                return -1;
2278
2279        json_object_foreach(element, key, value) {
2280                if (!strcmp(key, "clients")) {
2281                        err = og_json_parse_clients(value, params);
2282                } else if (!strcmp(key, "disk")) {
2283                        err = og_json_parse_string(value, &params->disk);
2284                        params->flags |= OG_REST_PARAM_DISK;
2285                } else if (!strcmp(key, "partition")) {
2286                        err = og_json_parse_string(value, &params->partition);
2287                        params->flags |= OG_REST_PARAM_PARTITION;
2288                }
2289
2290                if (err < 0)
2291                        return err;
2292        }
2293
2294        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
2295                                            OG_REST_PARAM_DISK |
2296                                            OG_REST_PARAM_PARTITION))
2297                return -1;
2298
2299        clients = json_copy(element);
2300        json_object_del(clients, "clients");
2301
2302        return og_send_request(OG_METHOD_POST, OG_CMD_SESSION, params, clients);
2303}
2304
2305static int og_cmd_poweroff(json_t *element, struct og_msg_params *params)
2306{
2307        const char *key;
2308        json_t *value;
2309        int err = 0;
2310
2311        if (json_typeof(element) != JSON_OBJECT)
2312                return -1;
2313
2314        json_object_foreach(element, key, value) {
2315                if (!strcmp(key, "clients"))
2316                        err = og_json_parse_clients(value, params);
2317
2318                if (err < 0)
2319                        break;
2320        }
2321
2322        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
2323                return -1;
2324
2325        return og_send_request(OG_METHOD_POST, OG_CMD_POWEROFF, params, NULL);
2326}
2327
2328static int og_cmd_refresh(json_t *element, struct og_msg_params *params)
2329{
2330        const char *key;
2331        json_t *value;
2332        int err = 0;
2333
2334        if (json_typeof(element) != JSON_OBJECT)
2335                return -1;
2336
2337        json_object_foreach(element, key, value) {
2338                if (!strcmp(key, "clients"))
2339                        err = og_json_parse_clients(value, params);
2340
2341                if (err < 0)
2342                        break;
2343        }
2344
2345        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
2346                return -1;
2347
2348        return og_send_request(OG_METHOD_GET, OG_CMD_REFRESH, params, NULL);
2349}
2350
2351static int og_cmd_reboot(json_t *element, struct og_msg_params *params)
2352{
2353        const char *key;
2354        json_t *value;
2355        int err = 0;
2356
2357        if (json_typeof(element) != JSON_OBJECT)
2358                return -1;
2359
2360        json_object_foreach(element, key, value) {
2361                if (!strcmp(key, "clients"))
2362                        err = og_json_parse_clients(value, params);
2363
2364                if (err < 0)
2365                        break;
2366        }
2367
2368        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
2369                return -1;
2370
2371        return og_send_request(OG_METHOD_POST, OG_CMD_REBOOT, params, NULL);
2372}
2373
2374static int og_cmd_stop(json_t *element, struct og_msg_params *params)
2375{
2376        const char *key;
2377        json_t *value;
2378        int err = 0;
2379
2380        if (json_typeof(element) != JSON_OBJECT)
2381                return -1;
2382
2383        json_object_foreach(element, key, value) {
2384                if (!strcmp(key, "clients"))
2385                        err = og_json_parse_clients(value, params);
2386
2387                if (err < 0)
2388                        break;
2389        }
2390
2391        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
2392                return -1;
2393
2394        return og_send_request(OG_METHOD_POST, OG_CMD_STOP, params, NULL);
2395}
2396
2397static int og_cmd_hardware(json_t *element, struct og_msg_params *params)
2398{
2399        const char *key;
2400        json_t *value;
2401        int err = 0;
2402
2403        if (json_typeof(element) != JSON_OBJECT)
2404                return -1;
2405
2406        json_object_foreach(element, key, value) {
2407                if (!strcmp(key, "clients"))
2408                        err = og_json_parse_clients(value, params);
2409
2410                if (err < 0)
2411                        break;
2412        }
2413
2414        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
2415                return -1;
2416
2417        return og_send_request(OG_METHOD_GET, OG_CMD_HARDWARE, params, NULL);
2418}
2419
2420static int og_cmd_software(json_t *element, struct og_msg_params *params)
2421{
2422        json_t *clients, *value;
2423        const char *key;
2424        int err = 0;
2425
2426        if (json_typeof(element) != JSON_OBJECT)
2427                return -1;
2428
2429        json_object_foreach(element, key, value) {
2430                if (!strcmp(key, "clients"))
2431                        err = og_json_parse_clients(value, params);
2432                else if (!strcmp(key, "disk")) {
2433                        err = og_json_parse_string(value, &params->disk);
2434                        params->flags |= OG_REST_PARAM_DISK;
2435                }
2436                else if (!strcmp(key, "partition")) {
2437                        err = og_json_parse_string(value, &params->partition);
2438                        params->flags |= OG_REST_PARAM_PARTITION;
2439                }
2440
2441                if (err < 0)
2442                        break;
2443        }
2444
2445        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
2446                                            OG_REST_PARAM_DISK |
2447                                            OG_REST_PARAM_PARTITION))
2448                return -1;
2449
2450        clients = json_copy(element);
2451        json_object_del(clients, "clients");
2452
2453        return og_send_request(OG_METHOD_POST, OG_CMD_SOFTWARE, params, clients);
2454}
2455
2456static int og_cmd_create_image(json_t *element, struct og_msg_params *params)
2457{
2458        json_t *value, *clients;
2459        const char *key;
2460        int err = 0;
2461
2462        if (json_typeof(element) != JSON_OBJECT)
2463                return -1;
2464
2465        json_object_foreach(element, key, value) {
2466                if (!strcmp(key, "disk")) {
2467                        err = og_json_parse_string(value, &params->disk);
2468                        params->flags |= OG_REST_PARAM_DISK;
2469                } else if (!strcmp(key, "partition")) {
2470                        err = og_json_parse_string(value, &params->partition);
2471                        params->flags |= OG_REST_PARAM_PARTITION;
2472                } else if (!strcmp(key, "name")) {
2473                        err = og_json_parse_string(value, &params->name);
2474                        params->flags |= OG_REST_PARAM_NAME;
2475                } else if (!strcmp(key, "repository")) {
2476                        err = og_json_parse_string(value, &params->repository);
2477                        params->flags |= OG_REST_PARAM_REPO;
2478                } else if (!strcmp(key, "clients")) {
2479                        err = og_json_parse_clients(value, params);
2480                } else if (!strcmp(key, "id")) {
2481                        err = og_json_parse_string(value, &params->id);
2482                        params->flags |= OG_REST_PARAM_ID;
2483                } else if (!strcmp(key, "code")) {
2484                        err = og_json_parse_string(value, &params->code);
2485                        params->flags |= OG_REST_PARAM_CODE;
2486                }
2487
2488                if (err < 0)
2489                        break;
2490        }
2491
2492        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
2493                                            OG_REST_PARAM_DISK |
2494                                            OG_REST_PARAM_PARTITION |
2495                                            OG_REST_PARAM_CODE |
2496                                            OG_REST_PARAM_ID |
2497                                            OG_REST_PARAM_NAME |
2498                                            OG_REST_PARAM_REPO))
2499                return -1;
2500
2501        clients = json_copy(element);
2502        json_object_del(clients, "clients");
2503
2504        return og_send_request(OG_METHOD_POST, OG_CMD_IMAGE_CREATE, params,
2505                               clients);
2506}
2507
2508static int og_cmd_restore_image(json_t *element, struct og_msg_params *params)
2509{
2510        json_t *clients, *value;
2511        const char *key;
2512        int err = 0;
2513
2514        if (json_typeof(element) != JSON_OBJECT)
2515                return -1;
2516
2517        json_object_foreach(element, key, value) {
2518                if (!strcmp(key, "disk")) {
2519                        err = og_json_parse_string(value, &params->disk);
2520                        params->flags |= OG_REST_PARAM_DISK;
2521                } else if (!strcmp(key, "partition")) {
2522                        err = og_json_parse_string(value, &params->partition);
2523                        params->flags |= OG_REST_PARAM_PARTITION;
2524                } else if (!strcmp(key, "name")) {
2525                        err = og_json_parse_string(value, &params->name);
2526                        params->flags |= OG_REST_PARAM_NAME;
2527                } else if (!strcmp(key, "repository")) {
2528                        err = og_json_parse_string(value, &params->repository);
2529                        params->flags |= OG_REST_PARAM_REPO;
2530                } else if (!strcmp(key, "clients")) {
2531                        err = og_json_parse_clients(value, params);
2532                } else if (!strcmp(key, "type")) {
2533                        err = og_json_parse_string(value, &params->type);
2534                        params->flags |= OG_REST_PARAM_TYPE;
2535                } else if (!strcmp(key, "profile")) {
2536                        err = og_json_parse_string(value, &params->profile);
2537                        params->flags |= OG_REST_PARAM_PROFILE;
2538                } else if (!strcmp(key, "id")) {
2539                        err = og_json_parse_string(value, &params->id);
2540                        params->flags |= OG_REST_PARAM_ID;
2541                }
2542
2543                if (err < 0)
2544                        break;
2545        }
2546
2547        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
2548                                            OG_REST_PARAM_DISK |
2549                                            OG_REST_PARAM_PARTITION |
2550                                            OG_REST_PARAM_NAME |
2551                                            OG_REST_PARAM_REPO |
2552                                            OG_REST_PARAM_TYPE |
2553                                            OG_REST_PARAM_PROFILE |
2554                                            OG_REST_PARAM_ID))
2555                return -1;
2556
2557        clients = json_copy(element);
2558        json_object_del(clients, "clients");
2559
2560        return og_send_request(OG_METHOD_POST, OG_CMD_IMAGE_RESTORE, params,
2561                               clients);
2562}
2563
2564static int og_cmd_setup(json_t *element, struct og_msg_params *params)
2565{
2566        json_t *value, *clients;
2567        const char *key;
2568        int err = 0;
2569
2570        if (json_typeof(element) != JSON_OBJECT)
2571                return -1;
2572
2573        json_object_foreach(element, key, value) {
2574                if (!strcmp(key, "clients")) {
2575                        err = og_json_parse_clients(value, params);
2576                } else if (!strcmp(key, "disk")) {
2577                        err = og_json_parse_string(value, &params->disk);
2578                        params->flags |= OG_REST_PARAM_DISK;
2579                } else if (!strcmp(key, "cache")) {
2580                        err = og_json_parse_string(value, &params->cache);
2581                        params->flags |= OG_REST_PARAM_CACHE;
2582                } else if (!strcmp(key, "cache_size")) {
2583                        err = og_json_parse_string(value, &params->cache_size);
2584                        params->flags |= OG_REST_PARAM_CACHE_SIZE;
2585                } else if (!strcmp(key, "partition_setup")) {
2586                        err = og_json_parse_partition_setup(value, params);
2587                }
2588
2589                if (err < 0)
2590                        break;
2591        }
2592
2593        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
2594                                            OG_REST_PARAM_DISK |
2595                                            OG_REST_PARAM_CACHE |
2596                                            OG_REST_PARAM_CACHE_SIZE |
2597                                            OG_REST_PARAM_PART_0 |
2598                                            OG_REST_PARAM_PART_1 |
2599                                            OG_REST_PARAM_PART_2 |
2600                                            OG_REST_PARAM_PART_3))
2601                return -1;
2602
2603        clients = json_copy(element);
2604        json_object_del(clients, "clients");
2605
2606        return og_send_request(OG_METHOD_POST, OG_CMD_SETUP, params, clients);
2607}
2608
2609static int og_cmd_run_schedule(json_t *element, struct og_msg_params *params)
2610{
2611        const char *key;
2612        json_t *value;
2613        int err = 0;
2614
2615        json_object_foreach(element, key, value) {
2616                if (!strcmp(key, "clients"))
2617                        err = og_json_parse_clients(value, params);
2618
2619                if (err < 0)
2620                        break;
2621        }
2622
2623        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR))
2624                return -1;
2625
2626        return og_send_request(OG_METHOD_GET, OG_CMD_RUN_SCHEDULE, params,
2627                               NULL);
2628}
2629
2630static int og_cmd_create_basic_image(json_t *element, struct og_msg_params *params)
2631{
2632        char buf[4096] = {};
2633        int err = 0, len;
2634        const char *key;
2635        json_t *value;
2636        TRAMA *msg;
2637
2638        if (json_typeof(element) != JSON_OBJECT)
2639                return -1;
2640
2641        json_object_foreach(element, key, value) {
2642                if (!strcmp(key, "clients")) {
2643                        err = og_json_parse_clients(value, params);
2644                } else if (!strcmp(key, "disk")) {
2645                        err = og_json_parse_string(value, &params->disk);
2646                        params->flags |= OG_REST_PARAM_DISK;
2647                } else if (!strcmp(key, "partition")) {
2648                        err = og_json_parse_string(value, &params->partition);
2649                        params->flags |= OG_REST_PARAM_PARTITION;
2650                } else if (!strcmp(key, "code")) {
2651                        err = og_json_parse_string(value, &params->code);
2652                        params->flags |= OG_REST_PARAM_CODE;
2653                } else if (!strcmp(key, "id")) {
2654                        err = og_json_parse_string(value, &params->id);
2655                        params->flags |= OG_REST_PARAM_ID;
2656                } else if (!strcmp(key, "name")) {
2657                        err = og_json_parse_string(value, &params->name);
2658                        params->flags |= OG_REST_PARAM_NAME;
2659                } else if (!strcmp(key, "repository")) {
2660                        err = og_json_parse_string(value, &params->repository);
2661                        params->flags |= OG_REST_PARAM_REPO;
2662                } else if (!strcmp(key, "sync_params")) {
2663                        err = og_json_parse_sync_params(value, params);
2664                }
2665
2666                if (err < 0)
2667                        break;
2668        }
2669
2670        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
2671                                            OG_REST_PARAM_DISK |
2672                                            OG_REST_PARAM_PARTITION |
2673                                            OG_REST_PARAM_CODE |
2674                                            OG_REST_PARAM_ID |
2675                                            OG_REST_PARAM_NAME |
2676                                            OG_REST_PARAM_REPO |
2677                                            OG_REST_PARAM_SYNC_SYNC |
2678                                            OG_REST_PARAM_SYNC_DIFF |
2679                                            OG_REST_PARAM_SYNC_REMOVE |
2680                                            OG_REST_PARAM_SYNC_COMPRESS |
2681                                            OG_REST_PARAM_SYNC_CLEANUP |
2682                                            OG_REST_PARAM_SYNC_CACHE |
2683                                            OG_REST_PARAM_SYNC_CLEANUP_CACHE |
2684                                            OG_REST_PARAM_SYNC_REMOVE_DST))
2685                return -1;
2686
2687        len = snprintf(buf, sizeof(buf),
2688                       "nfn=CrearImagenBasica\rdsk=%s\rpar=%s\rcpt=%s\ridi=%s\r"
2689                       "nci=%s\ripr=%s\rrti=\rmsy=%s\rwhl=%s\reli=%s\rcmp=%s\rbpi=%s\r"
2690                       "cpc=%s\rbpc=%s\rnba=%s\r",
2691                       params->disk, params->partition, params->code, params->id,
2692                       params->name, params->repository, params->sync_setup.sync,
2693                       params->sync_setup.diff, params->sync_setup.remove,
2694                       params->sync_setup.compress, params->sync_setup.cleanup,
2695                       params->sync_setup.cache, params->sync_setup.cleanup_cache,
2696                       params->sync_setup.remove_dst);
2697
2698        msg = og_msg_alloc(buf, len);
2699        if (!msg)
2700                return -1;
2701
2702        og_send_cmd((char **)params->ips_array, params->ips_array_len,
2703                    CLIENTE_OCUPADO, msg);
2704
2705        og_msg_free(msg);
2706
2707        return 0;
2708}
2709
2710static int og_cmd_create_incremental_image(json_t *element, struct og_msg_params *params)
2711{
2712        char buf[4096] = {};
2713        int err = 0, len;
2714        const char *key;
2715        json_t *value;
2716        TRAMA *msg;
2717
2718        if (json_typeof(element) != JSON_OBJECT)
2719                return -1;
2720
2721        json_object_foreach(element, key, value) {
2722                if (!strcmp(key, "clients"))
2723                        err = og_json_parse_clients(value, params);
2724                else if (!strcmp(key, "disk")) {
2725                        err = og_json_parse_string(value, &params->disk);
2726                        params->flags |= OG_REST_PARAM_DISK;
2727                } else if (!strcmp(key, "partition")) {
2728                        err = og_json_parse_string(value, &params->partition);
2729                        params->flags |= OG_REST_PARAM_PARTITION;
2730                } else if (!strcmp(key, "id")) {
2731                        err = og_json_parse_string(value, &params->id);
2732                        params->flags |= OG_REST_PARAM_ID;
2733                } else if (!strcmp(key, "name")) {
2734                        err = og_json_parse_string(value, &params->name);
2735                        params->flags |= OG_REST_PARAM_NAME;
2736                } else if (!strcmp(key, "repository")) {
2737                        err = og_json_parse_string(value, &params->repository);
2738                        params->flags |= OG_REST_PARAM_REPO;
2739                } else if (!strcmp(key, "sync_params")) {
2740                        err = og_json_parse_sync_params(value, params);
2741                }
2742
2743                if (err < 0)
2744                        break;
2745        }
2746
2747        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
2748                                            OG_REST_PARAM_DISK |
2749                                            OG_REST_PARAM_PARTITION |
2750                                            OG_REST_PARAM_ID |
2751                                            OG_REST_PARAM_NAME |
2752                                            OG_REST_PARAM_REPO |
2753                                            OG_REST_PARAM_SYNC_SYNC |
2754                                            OG_REST_PARAM_SYNC_PATH |
2755                                            OG_REST_PARAM_SYNC_DIFF |
2756                                            OG_REST_PARAM_SYNC_DIFF_ID |
2757                                            OG_REST_PARAM_SYNC_DIFF_NAME |
2758                                            OG_REST_PARAM_SYNC_REMOVE |
2759                                            OG_REST_PARAM_SYNC_COMPRESS |
2760                                            OG_REST_PARAM_SYNC_CLEANUP |
2761                                            OG_REST_PARAM_SYNC_CACHE |
2762                                            OG_REST_PARAM_SYNC_CLEANUP_CACHE |
2763                                            OG_REST_PARAM_SYNC_REMOVE_DST))
2764                return -1;
2765
2766        len = snprintf(buf, sizeof(buf),
2767                       "nfn=CrearSoftIncremental\rdsk=%s\rpar=%s\ridi=%s\rnci=%s\r"
2768                       "rti=%s\ripr=%s\ridf=%s\rncf=%s\rmsy=%s\rwhl=%s\reli=%s\rcmp=%s\r"
2769                       "bpi=%s\rcpc=%s\rbpc=%s\rnba=%s\r",
2770                       params->disk, params->partition, params->id, params->name,
2771                       params->sync_setup.path, params->repository, params->sync_setup.diff_id,
2772                       params->sync_setup.diff_name, params->sync_setup.sync,
2773                       params->sync_setup.diff, params->sync_setup.remove_dst,
2774                       params->sync_setup.compress, params->sync_setup.cleanup,
2775                       params->sync_setup.cache, params->sync_setup.cleanup_cache,
2776                       params->sync_setup.remove_dst);
2777
2778        msg = og_msg_alloc(buf, len);
2779        if (!msg)
2780                return -1;
2781
2782        og_send_cmd((char **)params->ips_array, params->ips_array_len,
2783                    CLIENTE_OCUPADO, msg);
2784
2785        og_msg_free(msg);
2786
2787        return 0;
2788}
2789
2790static int og_cmd_restore_basic_image(json_t *element, struct og_msg_params *params)
2791{
2792        char buf[4096] = {};
2793        int err = 0, len;
2794        const char *key;
2795        json_t *value;
2796        TRAMA *msg;
2797
2798        if (json_typeof(element) != JSON_OBJECT)
2799                return -1;
2800
2801        json_object_foreach(element, key, value) {
2802                if (!strcmp(key, "clients")) {
2803                        err = og_json_parse_clients(value, params);
2804                } else if (!strcmp(key, "disk")) {
2805                        err = og_json_parse_string(value, &params->disk);
2806                        params->flags |= OG_REST_PARAM_DISK;
2807                } else if (!strcmp(key, "partition")) {
2808                        err = og_json_parse_string(value, &params->partition);
2809                        params->flags |= OG_REST_PARAM_PARTITION;
2810                } else if (!strcmp(key, "id")) {
2811                        err = og_json_parse_string(value, &params->id);
2812                        params->flags |= OG_REST_PARAM_ID;
2813                } else if (!strcmp(key, "name")) {
2814                        err = og_json_parse_string(value, &params->name);
2815                        params->flags |= OG_REST_PARAM_NAME;
2816                } else if (!strcmp(key, "repository")) {
2817                        err = og_json_parse_string(value, &params->repository);
2818                        params->flags |= OG_REST_PARAM_REPO;
2819                } else if (!strcmp(key, "profile")) {
2820                        err = og_json_parse_string(value, &params->profile);
2821                        params->flags |= OG_REST_PARAM_PROFILE;
2822                } else if (!strcmp(key, "type")) {
2823                        err = og_json_parse_string(value, &params->type);
2824                        params->flags |= OG_REST_PARAM_TYPE;
2825                } else if (!strcmp(key, "sync_params")) {
2826                        err = og_json_parse_sync_params(value, params);
2827                }
2828
2829                if (err < 0)
2830                        break;
2831        }
2832
2833        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
2834                                            OG_REST_PARAM_DISK |
2835                                            OG_REST_PARAM_PARTITION |
2836                                            OG_REST_PARAM_ID |
2837                                            OG_REST_PARAM_NAME |
2838                                            OG_REST_PARAM_REPO |
2839                                            OG_REST_PARAM_PROFILE |
2840                                            OG_REST_PARAM_TYPE |
2841                                            OG_REST_PARAM_SYNC_PATH |
2842                                            OG_REST_PARAM_SYNC_METHOD |
2843                                            OG_REST_PARAM_SYNC_SYNC |
2844                                            OG_REST_PARAM_SYNC_DIFF |
2845                                            OG_REST_PARAM_SYNC_REMOVE |
2846                                            OG_REST_PARAM_SYNC_COMPRESS |
2847                                            OG_REST_PARAM_SYNC_CLEANUP |
2848                                            OG_REST_PARAM_SYNC_CACHE |
2849                                            OG_REST_PARAM_SYNC_CLEANUP_CACHE |
2850                                            OG_REST_PARAM_SYNC_REMOVE_DST))
2851                return -1;
2852
2853        len = snprintf(buf, sizeof(buf),
2854                       "nfn=RestaurarImagenBasica\rdsk=%s\rpar=%s\ridi=%s\rnci=%s\r"
2855                           "ipr=%s\rifs=%s\rrti=%s\rmet=%s\rmsy=%s\rtpt=%s\rwhl=%s\r"
2856                           "eli=%s\rcmp=%s\rbpi=%s\rcpc=%s\rbpc=%s\rnba=%s\r",
2857                       params->disk, params->partition, params->id, params->name,
2858                           params->repository, params->profile, params->sync_setup.path,
2859                           params->sync_setup.method, params->sync_setup.sync, params->type,
2860                           params->sync_setup.diff, params->sync_setup.remove,
2861                       params->sync_setup.compress, params->sync_setup.cleanup,
2862                       params->sync_setup.cache, params->sync_setup.cleanup_cache,
2863                       params->sync_setup.remove_dst);
2864
2865        msg = og_msg_alloc(buf, len);
2866        if (!msg)
2867                return -1;
2868
2869        og_send_cmd((char **)params->ips_array, params->ips_array_len,
2870                    CLIENTE_OCUPADO, msg);
2871
2872        og_msg_free(msg);
2873
2874        return 0;
2875}
2876
2877static int og_cmd_restore_incremental_image(json_t *element, struct og_msg_params *params)
2878{
2879        char buf[4096] = {};
2880        int err = 0, len;
2881        const char *key;
2882        json_t *value;
2883        TRAMA *msg;
2884
2885        if (json_typeof(element) != JSON_OBJECT)
2886                return -1;
2887
2888        json_object_foreach(element, key, value) {
2889                if (!strcmp(key, "clients")) {
2890                        err = og_json_parse_clients(value, params);
2891                } else if (!strcmp(key, "disk")) {
2892                        err = og_json_parse_string(value, &params->disk);
2893                        params->flags |= OG_REST_PARAM_DISK;
2894                } else if (!strcmp(key, "partition")) {
2895                        err = og_json_parse_string(value, &params->partition);
2896                        params->flags |= OG_REST_PARAM_PARTITION;
2897                } else if (!strcmp(key, "id")) {
2898                        err = og_json_parse_string(value, &params->id);
2899                        params->flags |= OG_REST_PARAM_ID;
2900                } else if (!strcmp(key, "name")) {
2901                        err = og_json_parse_string(value, &params->name);
2902                        params->flags |= OG_REST_PARAM_NAME;
2903                } else if (!strcmp(key, "repository")) {
2904                        err = og_json_parse_string(value, &params->repository);
2905                        params->flags |= OG_REST_PARAM_REPO;
2906                } else if (!strcmp(key, "profile")) {
2907                        err = og_json_parse_string(value, &params->profile);
2908                        params->flags |= OG_REST_PARAM_PROFILE;
2909                } else if (!strcmp(key, "type")) {
2910                        err = og_json_parse_string(value, &params->type);
2911                        params->flags |= OG_REST_PARAM_TYPE;
2912                } else if (!strcmp(key, "sync_params")) {
2913                        err = og_json_parse_sync_params(value, params);
2914                }
2915
2916                if (err < 0)
2917                        break;
2918        }
2919
2920        if (!og_msg_params_validate(params, OG_REST_PARAM_ADDR |
2921                                            OG_REST_PARAM_DISK |
2922                                            OG_REST_PARAM_PARTITION |
2923                                            OG_REST_PARAM_ID |
2924                                            OG_REST_PARAM_NAME |
2925                                            OG_REST_PARAM_REPO |
2926                                            OG_REST_PARAM_PROFILE |
2927                                            OG_REST_PARAM_TYPE |
2928                                            OG_REST_PARAM_SYNC_DIFF_ID |
2929                                            OG_REST_PARAM_SYNC_DIFF_NAME |
2930                                            OG_REST_PARAM_SYNC_PATH |
2931                                            OG_REST_PARAM_SYNC_METHOD |
2932                                            OG_REST_PARAM_SYNC_SYNC |
2933                                            OG_REST_PARAM_SYNC_DIFF |
2934                                            OG_REST_PARAM_SYNC_REMOVE |
2935                                            OG_REST_PARAM_SYNC_COMPRESS |
2936                                            OG_REST_PARAM_SYNC_CLEANUP |
2937                                            OG_REST_PARAM_SYNC_CACHE |
2938                                            OG_REST_PARAM_SYNC_CLEANUP_CACHE |
2939                                            OG_REST_PARAM_SYNC_REMOVE_DST))
2940                return -1;
2941
2942        len = snprintf(buf, sizeof(buf),
2943                       "nfn=RestaurarSoftIncremental\rdsk=%s\rpar=%s\ridi=%s\rnci=%s\r"
2944                           "ipr=%s\rifs=%s\ridf=%s\rncf=%s\rrti=%s\rmet=%s\rmsy=%s\r"
2945                           "tpt=%s\rwhl=%s\reli=%s\rcmp=%s\rbpi=%s\rcpc=%s\rbpc=%s\r"
2946                           "nba=%s\r",
2947                       params->disk, params->partition, params->id, params->name,
2948                           params->repository, params->profile, params->sync_setup.diff_id,
2949                           params->sync_setup.diff_name, params->sync_setup.path,
2950                           params->sync_setup.method, params->sync_setup.sync, params->type,
2951                           params->sync_setup.diff, params->sync_setup.remove,
2952                       params->sync_setup.compress, params->sync_setup.cleanup,
2953                       params->sync_setup.cache, params->sync_setup.cleanup_cache,
2954                       params->sync_setup.remove_dst);
2955
2956        msg = og_msg_alloc(buf, len);
2957        if (!msg)
2958                return -1;
2959
2960        og_send_cmd((char **)params->ips_array, params->ips_array_len,
2961                    CLIENTE_OCUPADO, msg);
2962
2963        og_msg_free(msg);
2964
2965        return 0;
2966}
2967
2968struct og_cmd {
2969        uint32_t                id;
2970        struct list_head        list;
2971        uint32_t                client_id;
2972        const char              *ip;
2973        const char              *mac;
2974        enum og_cmd_type        type;
2975        enum og_rest_method     method;
2976        struct og_msg_params    params;
2977        json_t                  *json;
2978};
2979
2980static LIST_HEAD(cmd_list);
2981
2982static const struct og_cmd *og_cmd_find(const char *client_ip)
2983{
2984        struct og_cmd *cmd, *next;
2985
2986        list_for_each_entry_safe(cmd, next, &cmd_list, list) {
2987                if (strcmp(cmd->ip, client_ip))
2988                        continue;
2989
2990                list_del(&cmd->list);
2991                return cmd;
2992        }
2993
2994        return NULL;
2995}
2996
2997static void og_cmd_free(const struct og_cmd *cmd)
2998{
2999        struct og_msg_params *params = (struct og_msg_params *)&cmd->params;
3000        int i;
3001
3002        for (i = 0; i < params->ips_array_len; i++) {
3003                free((void *)params->ips_array[i]);
3004                free((void *)params->mac_array[i]);
3005        }
3006        free((void *)params->wol_type);
3007
3008        if (cmd->json)
3009                json_decref(cmd->json);
3010
3011        free((void *)cmd->ip);
3012        free((void *)cmd->mac);
3013        free((void *)cmd);
3014}
3015
3016static void og_cmd_init(struct og_cmd *cmd, enum og_rest_method method,
3017                        enum og_cmd_type type, json_t *root)
3018{
3019        cmd->type = type;
3020        cmd->method = method;
3021        cmd->params.ips_array[0] = strdup(cmd->ip);
3022        cmd->params.ips_array_len = 1;
3023        cmd->json = root;
3024}
3025
3026static int og_cmd_legacy_wol(const char *input, struct og_cmd *cmd)
3027{
3028        char wol_type[2] = {};
3029
3030        if (sscanf(input, "mar=%s", wol_type) != 1) {
3031                syslog(LOG_ERR, "malformed database legacy input\n");
3032                return -1;
3033        }
3034
3035        og_cmd_init(cmd, OG_METHOD_NO_HTTP, OG_CMD_WOL, NULL);
3036        cmd->params.mac_array[0] = strdup(cmd->mac);
3037        cmd->params.wol_type = strdup(wol_type);
3038
3039        return 0;
3040}
3041
3042static int og_cmd_legacy_shell_run(const char *input, struct og_cmd *cmd)
3043{
3044        json_t *root, *script, *echo;
3045
3046        script = json_string(input + 4);
3047        echo = json_boolean(false);
3048
3049        root = json_object();
3050        if (!root)
3051                return -1;
3052        json_object_set_new(root, "run", script);
3053        json_object_set_new(root, "echo", echo);
3054
3055        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_SHELL_RUN, root);
3056
3057        return 0;
3058}
3059
3060#define OG_DB_SMALLINT_MAXLEN   6
3061
3062static int og_cmd_legacy_session(const char *input, struct og_cmd *cmd)
3063{
3064        char part_str[OG_DB_SMALLINT_MAXLEN + 1];
3065        char disk_str[OG_DB_SMALLINT_MAXLEN + 1];
3066        json_t *root, *disk, *partition;
3067
3068        if (sscanf(input, "dsk=%s\rpar=%s\r", disk_str, part_str) != 2)
3069                return -1;
3070        partition = json_string(part_str);
3071        disk = json_string(disk_str);
3072
3073        root = json_object();
3074        if (!root)
3075                return -1;
3076        json_object_set_new(root, "partition", partition);
3077        json_object_set_new(root, "disk", disk);
3078
3079        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_SESSION, root);
3080
3081        return 0;
3082}
3083
3084static int og_cmd_legacy_poweroff(const char *input, struct og_cmd *cmd)
3085{
3086        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_POWEROFF, NULL);
3087
3088        return 0;
3089}
3090
3091static int og_cmd_legacy_refresh(const char *input, struct og_cmd *cmd)
3092{
3093        og_cmd_init(cmd, OG_METHOD_GET, OG_CMD_REFRESH, NULL);
3094
3095        return 0;
3096}
3097
3098static int og_cmd_legacy_reboot(const char *input, struct og_cmd *cmd)
3099{
3100        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_REBOOT, NULL);
3101
3102        return 0;
3103}
3104
3105static int og_cmd_legacy_stop(const char *input, struct og_cmd *cmd)
3106{
3107        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_STOP, NULL);
3108
3109        return 0;
3110}
3111
3112static int og_cmd_legacy_hardware(const char *input, struct og_cmd *cmd)
3113{
3114        og_cmd_init(cmd, OG_METHOD_GET, OG_CMD_HARDWARE, NULL);
3115
3116        return 0;
3117}
3118
3119static int og_cmd_legacy_software(const char *input, struct og_cmd *cmd)
3120{
3121        og_cmd_init(cmd, OG_METHOD_GET, OG_CMD_SOFTWARE, NULL);
3122
3123        return 0;
3124}
3125
3126#define OG_DB_IMAGE_NAME_MAXLEN 50
3127#define OG_DB_FILESYSTEM_MAXLEN 16
3128#define OG_DB_INT8_MAXLEN       8
3129#define OG_DB_INT_MAXLEN        11
3130#define OG_DB_IP_MAXLEN         15
3131
3132struct og_image_legacy {
3133        char software_id[OG_DB_INT_MAXLEN + 1];
3134        char image_id[OG_DB_INT_MAXLEN + 1];
3135        char name[OG_DB_IMAGE_NAME_MAXLEN + 1];
3136        char repo[OG_DB_IP_MAXLEN + 1];
3137        char part[OG_DB_SMALLINT_MAXLEN + 1];
3138        char disk[OG_DB_SMALLINT_MAXLEN + 1];
3139        char code[OG_DB_INT8_MAXLEN + 1];
3140};
3141
3142struct og_legacy_partition {
3143        char partition[OG_DB_SMALLINT_MAXLEN + 1];
3144        char code[OG_DB_INT8_MAXLEN + 1];
3145        char size[OG_DB_INT_MAXLEN + 1];
3146        char filesystem[OG_DB_FILESYSTEM_MAXLEN + 1];
3147        char format[2]; /* Format is a boolean 0 or 1 => length is 2 */
3148};
3149
3150static int og_cmd_legacy_image_create(const char *input, struct og_cmd *cmd)
3151{
3152        json_t *root, *disk, *partition, *code, *image_id, *name, *repo;
3153        struct og_image_legacy img = {};
3154
3155        if (sscanf(input, "dsk=%s\rpar=%s\rcpt=%s\ridi=%s\rnci=%s\ripr=%s\r",
3156                   img.disk, img.part, img.code, img.image_id, img.name,
3157                   img.repo) != 6)
3158                return -1;
3159        image_id = json_string(img.image_id);
3160        partition = json_string(img.part);
3161        code = json_string(img.code);
3162        name = json_string(img.name);
3163        repo = json_string(img.repo);
3164        disk = json_string(img.disk);
3165
3166        root = json_object();
3167        if (!root)
3168                return -1;
3169        json_object_set_new(root, "partition", partition);
3170        json_object_set_new(root, "repository", repo);
3171        json_object_set_new(root, "id", image_id);
3172        json_object_set_new(root, "code", code);
3173        json_object_set_new(root, "name", name);
3174        json_object_set_new(root, "disk", disk);
3175
3176        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_IMAGE_CREATE, root);
3177
3178        return 0;
3179}
3180
3181#define OG_DB_RESTORE_TYPE_MAXLEN       64
3182
3183static int og_cmd_legacy_image_restore(const char *input, struct og_cmd *cmd)
3184{
3185        json_t *root, *disk, *partition, *image_id, *name, *repo;
3186        char restore_type_str[OG_DB_RESTORE_TYPE_MAXLEN + 1] = {};
3187        char software_id_str[OG_DB_INT_MAXLEN + 1] = {};
3188        json_t *software_id, *restore_type;
3189        struct og_image_legacy img = {};
3190
3191        if (sscanf(input,
3192                   "dsk=%s\rpar=%s\ridi=%s\rnci=%s\ripr=%s\rifs=%s\rptc=%s\r",
3193                   img.disk, img.part, img.image_id, img.name, img.repo,
3194                   software_id_str, restore_type_str) != 7)
3195                return -1;
3196
3197        restore_type = json_string(restore_type_str);
3198        software_id = json_string(software_id_str);
3199        image_id = json_string(img.image_id);
3200        partition = json_string(img.part);
3201        name = json_string(img.name);
3202        repo = json_string(img.repo);
3203        disk = json_string(img.disk);
3204
3205        root = json_object();
3206        if (!root)
3207                return -1;
3208        json_object_set_new(root, "profile", software_id);
3209        json_object_set_new(root, "partition", partition);
3210        json_object_set_new(root, "type", restore_type);
3211        json_object_set_new(root, "repository", repo);
3212        json_object_set_new(root, "id", image_id);
3213        json_object_set_new(root, "name", name);
3214        json_object_set_new(root, "disk", disk);
3215
3216        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_IMAGE_RESTORE, root);
3217
3218        return 0;
3219}
3220
3221static int og_cmd_legacy_setup(const char *input, struct og_cmd *cmd)
3222{
3223        json_t *root, *disk, *cache, *cache_size, *partition_setup, *object;
3224        struct og_legacy_partition part_cfg[OG_PARTITION_MAX] = {};
3225        char cache_size_str [OG_DB_INT_MAXLEN + 1];
3226        char disk_str [OG_DB_SMALLINT_MAXLEN + 1];
3227        json_t *part, *code, *fs, *size, *format;
3228        unsigned int partition_len = 0;
3229        const char *in_ptr;
3230        char cache_str[2];
3231
3232        if (sscanf(input, "dsk=%s\rcfg=dis=%*[^*]*che=%[^*]*tch=%[^!]!",
3233                   disk_str, cache_str, cache_size_str) != 3)
3234                return -1;
3235
3236        in_ptr = strstr(input, "!") + 1;
3237        while (strlen(in_ptr) > 0) {
3238                if(sscanf(in_ptr,
3239                          "par=%[^*]*cpt=%[^*]*sfi=%[^*]*tam=%[^*]*ope=%[^%%]%%",
3240                          part_cfg[partition_len].partition,
3241                          part_cfg[partition_len].code,
3242                          part_cfg[partition_len].filesystem,
3243                          part_cfg[partition_len].size,
3244                          part_cfg[partition_len].format) != 5)
3245                        return -1;
3246                in_ptr = strstr(in_ptr, "%") + 1;
3247                partition_len++;
3248        }
3249
3250        root = json_object();
3251        if (!root)
3252                return -1;
3253
3254        cache_size = json_string(cache_size_str);
3255        cache = json_string(cache_str);
3256        partition_setup = json_array();
3257        disk = json_string(disk_str);
3258
3259        for (unsigned int i = 0; i < partition_len; ++i) {
3260                object = json_object();
3261                if (!object) {
3262                        json_decref(root);
3263                        return -1;
3264                }
3265
3266                part = json_string(part_cfg[i].partition);
3267                fs = json_string(part_cfg[i].filesystem);
3268                format = json_string(part_cfg[i].format);
3269                code = json_string(part_cfg[i].code);
3270                size = json_string(part_cfg[i].size);
3271
3272                json_object_set_new(object, "partition", part);
3273                json_object_set_new(object, "filesystem", fs);
3274                json_object_set_new(object, "format", format);
3275                json_object_set_new(object, "code", code);
3276                json_object_set_new(object, "size", size);
3277
3278                json_array_append_new(partition_setup, object);
3279        }
3280
3281        json_object_set_new(root, "partition_setup", partition_setup);
3282        json_object_set_new(root, "cache_size", cache_size);
3283        json_object_set_new(root, "cache", cache);
3284        json_object_set_new(root, "disk", disk);
3285
3286        og_cmd_init(cmd, OG_METHOD_POST, OG_CMD_SETUP, root);
3287
3288        return 0;
3289}
3290
3291static int og_cmd_legacy_run_schedule(const char *input, struct og_cmd *cmd)
3292{
3293        og_cmd_init(cmd, OG_METHOD_GET, OG_CMD_RUN_SCHEDULE, NULL);
3294
3295        return 0;
3296}
3297
3298static int og_cmd_legacy(const char *input, struct og_cmd *cmd)
3299{
3300        char legacy_cmd[32] = {};
3301        int err = -1;
3302
3303        if (sscanf(input, "nfn=%31s\r", legacy_cmd) != 1) {
3304                syslog(LOG_ERR, "malformed database legacy input\n");
3305                return -1;
3306        }
3307        input = strchr(input, '\r') + 1;
3308
3309        if (!strcmp(legacy_cmd, "Arrancar")) {
3310                err = og_cmd_legacy_wol(input, cmd);
3311        } else if (!strcmp(legacy_cmd, "EjecutarScript")) {
3312                err = og_cmd_legacy_shell_run(input, cmd);
3313        } else if (!strcmp(legacy_cmd, "IniciarSesion")) {
3314                err = og_cmd_legacy_session(input, cmd);
3315        } else if (!strcmp(legacy_cmd, "Apagar")) {
3316                err = og_cmd_legacy_poweroff(input, cmd);
3317        } else if (!strcmp(legacy_cmd, "Actualizar")) {
3318                err = og_cmd_legacy_refresh(input, cmd);
3319        } else if (!strcmp(legacy_cmd, "Reiniciar")) {
3320                err = og_cmd_legacy_reboot(input, cmd);
3321        } else if (!strcmp(legacy_cmd, "Purgar")) {
3322                err = og_cmd_legacy_stop(input, cmd);
3323        } else if (!strcmp(legacy_cmd, "InventarioHardware")) {
3324                err = og_cmd_legacy_hardware(input, cmd);
3325        } else if (!strcmp(legacy_cmd, "InventarioSoftware")) {
3326                err = og_cmd_legacy_software(input, cmd);
3327        } else if (!strcmp(legacy_cmd, "CrearImagen")) {
3328                err = og_cmd_legacy_image_create(input, cmd);
3329        } else if (!strcmp(legacy_cmd, "RestaurarImagen")) {
3330                err = og_cmd_legacy_image_restore(input, cmd);
3331        } else if (!strcmp(legacy_cmd, "Configurar")) {
3332                err = og_cmd_legacy_setup(input, cmd);
3333        } else if (!strcmp(legacy_cmd, "EjecutaComandosPendientes") ||
3334                   !strcmp(legacy_cmd, "Actualizar")) {
3335                err = og_cmd_legacy_run_schedule(input, cmd);
3336        }
3337
3338        return err;
3339}
3340
3341static int og_dbi_add_action(const struct og_dbi *dbi, const struct og_task *task,
3342                             struct og_cmd *cmd)
3343{
3344        char start_date_string[24];
3345        struct tm *start_date;
3346        const char *msglog;
3347        dbi_result result;
3348        time_t now;
3349
3350        time(&now);
3351        start_date = localtime(&now);
3352
3353        sprintf(start_date_string, "%hu/%hhu/%hhu %hhu:%hhu:%hhu",
3354                start_date->tm_year + 1900, start_date->tm_mon + 1,
3355                start_date->tm_mday, start_date->tm_hour, start_date->tm_min,
3356                start_date->tm_sec);
3357        result = dbi_conn_queryf(dbi->conn,
3358                                "INSERT INTO acciones (idordenador, "
3359                                "tipoaccion, idtipoaccion, descriaccion, ip, "
3360                                "sesion, idcomando, parametros, fechahorareg, "
3361                                "estado, resultado, ambito, idambito, "
3362                                "restrambito, idprocedimiento, idcentro, "
3363                                "idprogramacion) "
3364                                "VALUES (%d, %d, %d, '%s', '%s', %d, %d, '%s', "
3365                                "'%s', %d, %d, %d, %d, '%s', %d, %d, %d)",
3366                                cmd->client_id, EJECUCION_TAREA, task->task_id,
3367                                "", cmd->ip, 0, task->command_id,
3368                                task->params, start_date_string,
3369                                ACCION_INICIADA, ACCION_SINRESULTADO,
3370                                task->type_scope, task->scope, "",
3371                                task->procedure_id, task->center_id,
3372                                task->schedule_id);
3373        if (!result) {
3374                dbi_conn_error(dbi->conn, &msglog);
3375                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3376                       __func__, __LINE__, msglog);
3377                return -1;
3378        }
3379        cmd->id = dbi_conn_sequence_last(dbi->conn, NULL);
3380        dbi_result_free(result);
3381
3382        return 0;
3383}
3384
3385static int og_queue_task_command(struct og_dbi *dbi, const struct og_task *task,
3386                                 char *query)
3387{
3388        struct og_cmd *cmd;
3389        const char *msglog;
3390        dbi_result result;
3391
3392        result = dbi_conn_queryf(dbi->conn, query);
3393        if (!result) {
3394                dbi_conn_error(dbi->conn, &msglog);
3395                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3396                       __func__, __LINE__, msglog);
3397                return -1;
3398        }
3399
3400        while (dbi_result_next_row(result)) {
3401                cmd = (struct og_cmd *)calloc(1, sizeof(struct og_cmd));
3402                if (!cmd) {
3403                        dbi_result_free(result);
3404                        return -1;
3405                }
3406
3407                cmd->client_id  = dbi_result_get_uint(result, "idordenador");
3408                cmd->ip         = strdup(dbi_result_get_string(result, "ip"));
3409                cmd->mac        = strdup(dbi_result_get_string(result, "mac"));
3410
3411                og_cmd_legacy(task->params, cmd);
3412
3413                if (task->procedure_id) {
3414                        if (og_dbi_add_action(dbi, task, cmd)) {
3415                                dbi_result_free(result);
3416                                return -1;
3417                        }
3418                } else {
3419                        cmd->id = task->task_id;
3420                }
3421
3422                list_add_tail(&cmd->list, &cmd_list);
3423        }
3424
3425        dbi_result_free(result);
3426
3427        return 0;
3428}
3429
3430static int og_queue_task_group_clients(struct og_dbi *dbi, struct og_task *task,
3431                                       char *query)
3432{
3433
3434        const char *msglog;
3435        dbi_result result;
3436
3437        result = dbi_conn_queryf(dbi->conn, query);
3438        if (!result) {
3439                dbi_conn_error(dbi->conn, &msglog);
3440                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3441                       __func__, __LINE__, msglog);
3442                return -1;
3443        }
3444
3445        while (dbi_result_next_row(result)) {
3446                uint32_t group_id = dbi_result_get_uint(result, "idgrupo");
3447
3448                sprintf(query, "SELECT idgrupo FROM gruposordenadores "
3449                                "WHERE grupoid=%d", group_id);
3450                if (og_queue_task_group_clients(dbi, task, query)) {
3451                        dbi_result_free(result);
3452                        return -1;
3453                }
3454
3455                sprintf(query,"SELECT ip, mac, idordenador FROM ordenadores "
3456                              "WHERE grupoid=%d", group_id);
3457                if (og_queue_task_command(dbi, task, query)) {
3458                        dbi_result_free(result);
3459                        return -1;
3460                }
3461
3462        }
3463
3464        dbi_result_free(result);
3465
3466        return 0;
3467}
3468
3469static int og_queue_task_group_classrooms(struct og_dbi *dbi,
3470                                          struct og_task *task, char *query)
3471{
3472
3473        const char *msglog;
3474        dbi_result result;
3475
3476        result = dbi_conn_queryf(dbi->conn, query);
3477        if (!result) {
3478                dbi_conn_error(dbi->conn, &msglog);
3479                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3480                       __func__, __LINE__, msglog);
3481                return -1;
3482        }
3483
3484        while (dbi_result_next_row(result)) {
3485                uint32_t group_id = dbi_result_get_uint(result, "idgrupo");
3486
3487                sprintf(query, "SELECT idgrupo FROM grupos "
3488                                "WHERE grupoid=%d AND tipo=%d", group_id, AMBITO_GRUPOSAULAS);
3489                if (og_queue_task_group_classrooms(dbi, task, query)) {
3490                        dbi_result_free(result);
3491                        return -1;
3492                }
3493
3494                sprintf(query,
3495                        "SELECT ip,mac,idordenador "
3496                        "FROM ordenadores INNER JOIN aulas "
3497                        "WHERE ordenadores.idaula=aulas.idaula "
3498                        "AND aulas.grupoid=%d",
3499                        group_id);
3500                if (og_queue_task_command(dbi, task, query)) {
3501                        dbi_result_free(result);
3502                        return -1;
3503                }
3504
3505        }
3506
3507        dbi_result_free(result);
3508
3509        return 0;
3510}
3511
3512static int og_queue_task_clients(struct og_dbi *dbi, struct og_task *task)
3513{
3514        char query[4096];
3515
3516        switch (task->type_scope) {
3517                case AMBITO_CENTROS:
3518                        sprintf(query,
3519                                "SELECT ip,mac,idordenador "
3520                                "FROM ordenadores INNER JOIN aulas "
3521                                "WHERE ordenadores.idaula=aulas.idaula "
3522                                "AND idcentro=%d",
3523                                task->scope);
3524                        return og_queue_task_command(dbi, task, query);
3525                case AMBITO_GRUPOSAULAS:
3526                        sprintf(query,
3527                                "SELECT idgrupo FROM grupos "
3528                                "WHERE idgrupo=%i AND tipo=%d",
3529                                task->scope, AMBITO_GRUPOSAULAS);
3530                        return og_queue_task_group_classrooms(dbi, task, query);
3531                case AMBITO_AULAS:
3532                        sprintf(query,
3533                                "SELECT ip,mac,idordenador FROM ordenadores "
3534                                "WHERE idaula=%d",
3535                                task->scope);
3536                        return og_queue_task_command(dbi, task, query);
3537                case AMBITO_GRUPOSORDENADORES:
3538                        sprintf(query,
3539                                "SELECT idgrupo FROM gruposordenadores "
3540                                "WHERE idgrupo = %d",
3541                                task->scope);
3542                        return og_queue_task_group_clients(dbi, task, query);
3543                case AMBITO_ORDENADORES:
3544                        sprintf(query,
3545                                "SELECT ip, mac, idordenador FROM ordenadores "
3546                                "WHERE idordenador = %d",
3547                                task->scope);
3548                        return og_queue_task_command(dbi, task, query);
3549        }
3550        return 0;
3551}
3552
3553static int og_dbi_queue_procedure(struct og_dbi *dbi, struct og_task *task)
3554{
3555        uint32_t procedure_id;
3556        const char *msglog;
3557        dbi_result result;
3558
3559        result = dbi_conn_queryf(dbi->conn,
3560                        "SELECT parametros, procedimientoid, idcomando "
3561                        "FROM procedimientos_acciones "
3562                        "WHERE idprocedimiento=%d ORDER BY orden", task->procedure_id);
3563        if (!result) {
3564                dbi_conn_error(dbi->conn, &msglog);
3565                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3566                       __func__, __LINE__, msglog);
3567                return -1;
3568        }
3569
3570        while (dbi_result_next_row(result)) {
3571                procedure_id = dbi_result_get_uint(result, "procedimientoid");
3572                if (procedure_id > 0) {
3573                        task->procedure_id = procedure_id;
3574                        if (og_dbi_queue_procedure(dbi, task))
3575                                return -1;
3576                        continue;
3577                }
3578
3579                task->params    = strdup(dbi_result_get_string(result, "parametros"));
3580                task->command_id = dbi_result_get_uint(result, "idcomando");
3581                if (og_queue_task_clients(dbi, task))
3582                        return -1;
3583        }
3584
3585        dbi_result_free(result);
3586
3587        return 0;
3588}
3589
3590static int og_dbi_queue_task(struct og_dbi *dbi, uint32_t task_id,
3591                             uint32_t schedule_id)
3592{
3593        struct og_task task = {};
3594        uint32_t task_id_next;
3595        const char *msglog;
3596        dbi_result result;
3597
3598        task.schedule_id = schedule_id;
3599
3600        result = dbi_conn_queryf(dbi->conn,
3601                        "SELECT tareas_acciones.orden, "
3602                                "tareas_acciones.idprocedimiento, "
3603                                "tareas_acciones.tareaid, "
3604                                "tareas.idtarea, "
3605                                "tareas.idcentro, "
3606                                "tareas.ambito, "
3607                                "tareas.idambito, "
3608                                "tareas.restrambito "
3609                        " FROM tareas"
3610                                " INNER JOIN tareas_acciones ON tareas_acciones.idtarea=tareas.idtarea"
3611                        " WHERE tareas_acciones.idtarea=%u ORDER BY tareas_acciones.orden ASC", task_id);
3612        if (!result) {
3613                dbi_conn_error(dbi->conn, &msglog);
3614                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3615                       __func__, __LINE__, msglog);
3616                return -1;
3617        }
3618
3619        while (dbi_result_next_row(result)) {
3620                task_id_next = dbi_result_get_uint(result, "tareaid");
3621
3622                if (task_id_next > 0) {
3623                        if (og_dbi_queue_task(dbi, task_id_next, schedule_id))
3624                                return -1;
3625
3626                        continue;
3627                }
3628                task.task_id = dbi_result_get_uint(result, "idtarea");
3629                task.center_id = dbi_result_get_uint(result, "idcentro");
3630                task.procedure_id = dbi_result_get_uint(result, "idprocedimiento");
3631                task.type_scope = dbi_result_get_uint(result, "ambito");
3632                task.scope = dbi_result_get_uint(result, "idambito");
3633                task.filtered_scope = dbi_result_get_string(result, "restrambito");
3634
3635                og_dbi_queue_procedure(dbi, &task);
3636        }
3637
3638        dbi_result_free(result);
3639
3640        return 0;
3641}
3642
3643static int og_dbi_queue_command(struct og_dbi *dbi, uint32_t task_id,
3644                                uint32_t schedule_id)
3645{
3646        struct og_task task = {};
3647        const char *msglog;
3648        dbi_result result;
3649        char query[4096];
3650
3651        result = dbi_conn_queryf(dbi->conn,
3652                        "SELECT idaccion, idcentro, idordenador, parametros "
3653                        "FROM acciones "
3654                        "WHERE sesion = %u", task_id);
3655        if (!result) {
3656                dbi_conn_error(dbi->conn, &msglog);
3657                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3658                       __func__, __LINE__, msglog);
3659                return -1;
3660        }
3661
3662        while (dbi_result_next_row(result)) {
3663                task.task_id = dbi_result_get_uint(result, "idaccion");
3664                task.center_id = dbi_result_get_uint(result, "idcentro");
3665                task.scope = dbi_result_get_uint(result, "idordenador");
3666                task.params = strdup(dbi_result_get_string(result, "parametros"));
3667
3668                sprintf(query,
3669                        "SELECT ip, mac, idordenador FROM ordenadores "
3670                        "WHERE idordenador = %d",
3671                        task.scope);
3672                if (og_queue_task_command(dbi, &task, query)) {
3673                        dbi_result_free(result);
3674                        return -1;
3675                }
3676        }
3677
3678        dbi_result_free(result);
3679
3680        return 0;
3681}
3682
3683static int og_dbi_update_action(uint32_t id, bool success)
3684{
3685        char end_date_string[24];
3686        struct tm *end_date;
3687        const char *msglog;
3688        struct og_dbi *dbi;
3689        uint8_t status = 2;
3690        dbi_result result;
3691        time_t now;
3692
3693        if (!id)
3694                return 0;
3695
3696        dbi = og_dbi_open(&dbi_config);
3697        if (!dbi) {
3698                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
3699                       __func__, __LINE__);
3700                return -1;
3701        }
3702
3703        time(&now);
3704        end_date = localtime(&now);
3705
3706        sprintf(end_date_string, "%hu/%hhu/%hhu %hhu:%hhu:%hhu",
3707                end_date->tm_year + 1900, end_date->tm_mon + 1,
3708                end_date->tm_mday, end_date->tm_hour, end_date->tm_min,
3709                end_date->tm_sec);
3710        result = dbi_conn_queryf(dbi->conn,
3711                                 "UPDATE acciones SET fechahorafin='%s', "
3712                                 "estado=%d, resultado=%d WHERE idaccion=%d",
3713                                 end_date_string, ACCION_FINALIZADA,
3714                                 status - success, id);
3715
3716        if (!result) {
3717                dbi_conn_error(dbi->conn, &msglog);
3718                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3719                       __func__, __LINE__, msglog);
3720                og_dbi_close(dbi);
3721                return -1;
3722        }
3723        dbi_result_free(result);
3724        og_dbi_close(dbi);
3725
3726        return 0;
3727}
3728
3729void og_schedule_run(unsigned int task_id, unsigned int schedule_id,
3730                     enum og_schedule_type type)
3731{
3732        struct og_msg_params params = {};
3733        bool duplicated = false;
3734        struct og_cmd *cmd, *next;
3735        struct og_dbi *dbi;
3736        unsigned int i;
3737
3738        dbi = og_dbi_open(&dbi_config);
3739        if (!dbi) {
3740                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
3741                       __func__, __LINE__);
3742                return;
3743        }
3744
3745        switch (type) {
3746        case OG_SCHEDULE_TASK:
3747                og_dbi_queue_task(dbi, task_id, schedule_id);
3748                break;
3749        case OG_SCHEDULE_PROCEDURE:
3750        case OG_SCHEDULE_COMMAND:
3751                og_dbi_queue_command(dbi, task_id, schedule_id);
3752                break;
3753        }
3754        og_dbi_close(dbi);
3755
3756        list_for_each_entry(cmd, &cmd_list, list) {
3757                for (i = 0; i < params.ips_array_len; i++) {
3758                        if (!strncmp(cmd->ip, params.ips_array[i],
3759                                     OG_DB_IP_MAXLEN)) {
3760                                duplicated = true;
3761                                break;
3762                        }
3763                }
3764
3765                if (!duplicated)
3766                        params.ips_array[params.ips_array_len++] = cmd->ip;
3767                else
3768                        duplicated = false;
3769        }
3770
3771        list_for_each_entry_safe(cmd, next, &cmd_list, list) {
3772                if (cmd->type != OG_CMD_WOL)
3773                        continue;
3774
3775                if (Levanta((char **)cmd->params.ips_array,
3776                            (char **)cmd->params.mac_array,
3777                            cmd->params.ips_array_len,
3778                            (char *)cmd->params.wol_type))
3779                        og_dbi_update_action(cmd->id, true);
3780
3781                list_del(&cmd->list);
3782                og_cmd_free(cmd);
3783        }
3784
3785        og_send_request(OG_METHOD_GET, OG_CMD_RUN_SCHEDULE, &params, NULL);
3786}
3787
3788static int og_cmd_task_post(json_t *element, struct og_msg_params *params)
3789{
3790        struct og_cmd *cmd;
3791        struct og_dbi *dbi;
3792        const char *key;
3793        json_t *value;
3794        int err;
3795
3796        if (json_typeof(element) != JSON_OBJECT)
3797                return -1;
3798
3799        json_object_foreach(element, key, value) {
3800                if (!strcmp(key, "task")) {
3801                        err = og_json_parse_string(value, &params->task_id);
3802                        params->flags |= OG_REST_PARAM_TASK;
3803                }
3804
3805                if (err < 0)
3806                        break;
3807        }
3808
3809        if (!og_msg_params_validate(params, OG_REST_PARAM_TASK))
3810                return -1;
3811
3812        dbi = og_dbi_open(&dbi_config);
3813        if (!dbi) {
3814                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
3815                           __func__, __LINE__);
3816                return -1;
3817        }
3818
3819        og_schedule_run(atoi(params->task_id), 0, OG_SCHEDULE_TASK);
3820        og_dbi_close(dbi);
3821
3822        list_for_each_entry(cmd, &cmd_list, list)
3823                params->ips_array[params->ips_array_len++] = cmd->ip;
3824
3825        return og_send_request(OG_METHOD_GET, OG_CMD_RUN_SCHEDULE, params,
3826                               NULL);
3827}
3828
3829static int og_dbi_schedule_get(void)
3830{
3831        uint32_t schedule_id, task_id;
3832        struct og_schedule_time time;
3833        struct og_dbi *dbi;
3834        const char *msglog;
3835        dbi_result result;
3836
3837        dbi = og_dbi_open(&dbi_config);
3838        if (!dbi) {
3839                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
3840                       __func__, __LINE__);
3841                return -1;
3842        }
3843
3844        result = dbi_conn_queryf(dbi->conn,
3845                                 "SELECT idprogramacion, tipoaccion, identificador, "
3846                                 "sesion, annos, meses, diario, dias, semanas, horas, "
3847                                 "ampm, minutos FROM programaciones "
3848                                 "WHERE suspendida = 0");
3849        if (!result) {
3850                dbi_conn_error(dbi->conn, &msglog);
3851                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3852                       __func__, __LINE__, msglog);
3853                og_dbi_close(dbi);
3854                return -1;
3855        }
3856
3857        while (dbi_result_next_row(result)) {
3858                memset(&time, 0, sizeof(time));
3859                schedule_id = dbi_result_get_uint(result, "idprogramacion");
3860                task_id = dbi_result_get_uint(result, "identificador");
3861                time.years = dbi_result_get_uint(result, "annos");
3862                time.months = dbi_result_get_uint(result, "meses");
3863                time.weeks = dbi_result_get_uint(result, "semanas");
3864                time.week_days = dbi_result_get_uint(result, "dias");
3865                time.days = dbi_result_get_uint(result, "diario");
3866                time.hours = dbi_result_get_uint(result, "horas");
3867                time.am_pm = dbi_result_get_uint(result, "ampm");
3868                time.minutes = dbi_result_get_uint(result, "minutos");
3869                time.on_start = true;
3870
3871                og_schedule_create(schedule_id, task_id, OG_SCHEDULE_TASK,
3872                                   &time);
3873        }
3874
3875        dbi_result_free(result);
3876        og_dbi_close(dbi);
3877
3878        return 0;
3879}
3880
3881static int og_dbi_schedule_create(struct og_dbi *dbi,
3882                                  struct og_msg_params *params,
3883                                  uint32_t *schedule_id,
3884                                  enum og_schedule_type schedule_type)
3885{
3886        uint8_t suspended = 0;
3887        uint32_t session = 0;
3888        const char *msglog;
3889        dbi_result result;
3890        uint8_t type;
3891
3892        switch (schedule_type) {
3893        case OG_SCHEDULE_TASK:
3894                type = 3;
3895                break;
3896        case OG_SCHEDULE_PROCEDURE:
3897                type = 2;
3898                break;
3899        case OG_SCHEDULE_COMMAND:
3900                session = atoi(params->task_id);
3901                type = 1;
3902                break;
3903        }
3904
3905        result = dbi_conn_queryf(dbi->conn,
3906                                 "INSERT INTO programaciones (tipoaccion,"
3907                                 " identificador, nombrebloque, annos, meses,"
3908                                 " semanas, dias, diario, horas, ampm, minutos,"
3909                                 " suspendida, sesion) VALUES (%d, %s, '%s',"
3910                                 " %d, %d, %d, %d, %d, %d, %d, %d, %d, %d)",
3911                                 type, params->task_id, params->name,
3912                                 params->time.years, params->time.months,
3913                                 params->time.weeks, params->time.week_days,
3914                                 params->time.days, params->time.hours,
3915                                 params->time.am_pm, params->time.minutes,
3916                                 suspended, session);
3917        if (!result) {
3918                dbi_conn_error(dbi->conn, &msglog);
3919                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3920                       __func__, __LINE__, msglog);
3921                return -1;
3922        }
3923        dbi_result_free(result);
3924
3925        *schedule_id = dbi_conn_sequence_last(dbi->conn, NULL);
3926
3927        return 0;
3928}
3929
3930static int og_dbi_schedule_update(struct og_dbi *dbi,
3931                                  struct og_msg_params *params)
3932{
3933        const char *msglog;
3934        dbi_result result;
3935        uint8_t type = 3;
3936
3937        result = dbi_conn_queryf(dbi->conn,
3938                                 "UPDATE programaciones SET tipoaccion=%d, "
3939                                 "identificador='%s', nombrebloque='%s', "
3940                                 "annos=%d, meses=%d, "
3941                                 "diario=%d, horas=%d, ampm=%d, minutos=%d "
3942                                 "WHERE idprogramacion='%s'",
3943                                 type, params->task_id, params->name,
3944                                 params->time.years, params->time.months,
3945                                 params->time.days, params->time.hours,
3946                                 params->time.am_pm, params->time.minutes,
3947                                 params->id);
3948
3949        if (!result) {
3950                dbi_conn_error(dbi->conn, &msglog);
3951                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3952                       __func__, __LINE__, msglog);
3953                return -1;
3954        }
3955        dbi_result_free(result);
3956
3957        return 0;
3958}
3959
3960static int og_dbi_schedule_delete(struct og_dbi *dbi, uint32_t id)
3961{
3962        const char *msglog;
3963        dbi_result result;
3964
3965        result = dbi_conn_queryf(dbi->conn,
3966                                 "DELETE FROM programaciones WHERE idprogramacion=%d",
3967                                 id);
3968        if (!result) {
3969                dbi_conn_error(dbi->conn, &msglog);
3970                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
3971                       __func__, __LINE__, msglog);
3972                return -1;
3973        }
3974        dbi_result_free(result);
3975
3976        return 0;
3977}
3978
3979struct og_db_schedule {
3980        uint32_t                id;
3981        uint32_t                task_id;
3982        const char              *name;
3983        struct og_schedule_time time;
3984        uint32_t                week_days;
3985        uint32_t                weeks;
3986        uint32_t                suspended;
3987        uint32_t                session;
3988};
3989
3990static int og_dbi_schedule_get_json(struct og_dbi *dbi, json_t *root,
3991                                    const char *task_id, const char *schedule_id)
3992{
3993        struct og_db_schedule schedule;
3994        json_t *obj, *array;
3995        const char *msglog;
3996        dbi_result result;
3997        int err = 0;
3998
3999        if (task_id) {
4000                result = dbi_conn_queryf(dbi->conn,
4001                                         "SELECT idprogramacion,"
4002                                         "       identificador, nombrebloque,"
4003                                         "       annos, meses, diario, dias,"
4004                                         "       semanas, horas, ampm,"
4005                                         "       minutos,suspendida, sesion "
4006                                         "FROM programaciones "
4007                                         "WHERE identificador=%d",
4008                                         atoi(task_id));
4009        } else if (schedule_id) {
4010                result = dbi_conn_queryf(dbi->conn,
4011                                         "SELECT idprogramacion,"
4012                                         "       identificador, nombrebloque,"
4013                                         "       annos, meses, diario, dias,"
4014                                         "       semanas, horas, ampm,"
4015                                         "       minutos,suspendida, sesion "
4016                                         "FROM programaciones "
4017                                         "WHERE idprogramacion=%d",
4018                                         atoi(schedule_id));
4019        } else {
4020                result = dbi_conn_queryf(dbi->conn,
4021                                         "SELECT idprogramacion,"
4022                                         "       identificador, nombrebloque,"
4023                                         "       annos, meses, diario, dias,"
4024                                         "       semanas, horas, ampm,"
4025                                         "       minutos,suspendida, sesion "
4026                                         "FROM programaciones");
4027        }
4028
4029        if (!result) {
4030                dbi_conn_error(dbi->conn, &msglog);
4031                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
4032                       __func__, __LINE__, msglog);
4033                return -1;
4034        }
4035
4036        array = json_array();
4037        if (!array)
4038                return -1;
4039
4040        while (dbi_result_next_row(result)) {
4041                schedule.id = dbi_result_get_uint(result, "idprogramacion");
4042                schedule.task_id = dbi_result_get_uint(result, "identificador");
4043                schedule.name = dbi_result_get_string(result, "nombrebloque");
4044                schedule.time.years = dbi_result_get_uint(result, "annos");
4045                schedule.time.months = dbi_result_get_uint(result, "meses");
4046                schedule.time.days = dbi_result_get_uint(result, "diario");
4047                schedule.time.hours = dbi_result_get_uint(result, "horas");
4048                schedule.time.am_pm = dbi_result_get_uint(result, "ampm");
4049                schedule.time.minutes = dbi_result_get_uint(result, "minutos");
4050                schedule.week_days = dbi_result_get_uint(result, "dias");
4051                schedule.weeks = dbi_result_get_uint(result, "semanas");
4052                schedule.suspended = dbi_result_get_uint(result, "suspendida");
4053                schedule.session = dbi_result_get_uint(result, "sesion");
4054
4055                obj = json_object();
4056                if (!obj) {
4057                        err = -1;
4058                        break;
4059                }
4060                json_object_set_new(obj, "id", json_integer(schedule.id));
4061                json_object_set_new(obj, "task", json_integer(schedule.task_id));
4062                json_object_set_new(obj, "name", json_string(schedule.name));
4063                json_object_set_new(obj, "years", json_integer(schedule.time.years));
4064                json_object_set_new(obj, "months", json_integer(schedule.time.months));
4065                json_object_set_new(obj, "days", json_integer(schedule.time.days));
4066                json_object_set_new(obj, "hours", json_integer(schedule.time.hours));
4067                json_object_set_new(obj, "am_pm", json_integer(schedule.time.am_pm));
4068                json_object_set_new(obj, "minutes", json_integer(schedule.time.minutes));
4069                json_object_set_new(obj, "week_days", json_integer(schedule.week_days));
4070                json_object_set_new(obj, "weeks", json_integer(schedule.weeks));
4071                json_object_set_new(obj, "suspended", json_integer(schedule.suspended));
4072                json_object_set_new(obj, "session", json_integer(schedule.session));
4073
4074                json_array_append_new(array, obj);
4075        }
4076
4077        json_object_set_new(root, "schedule", array);
4078
4079        dbi_result_free(result);
4080
4081        return err;
4082}
4083
4084static struct ev_loop *og_loop;
4085
4086static int og_task_schedule_create(struct og_msg_params *params)
4087{
4088        enum og_schedule_type type;
4089        uint32_t schedule_id;
4090        struct og_dbi *dbi;
4091        int err;
4092
4093        if (!strcmp(params->type, "task"))
4094                type = OG_SCHEDULE_TASK;
4095        else if (!strcmp(params->type, "procedure"))
4096                type = OG_SCHEDULE_PROCEDURE;
4097        else if (!strcmp(params->type, "command"))
4098                type = OG_SCHEDULE_COMMAND;
4099        else
4100                return -1;
4101
4102        dbi = og_dbi_open(&dbi_config);
4103        if (!dbi) {
4104                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
4105                       __func__, __LINE__);
4106                return -1;
4107        }
4108
4109        err = og_dbi_schedule_create(dbi, params, &schedule_id, type);
4110        if (err < 0) {
4111                og_dbi_close(dbi);
4112                return -1;
4113        }
4114        og_schedule_create(schedule_id, atoi(params->task_id), type,
4115                           &params->time);
4116        og_schedule_refresh(og_loop);
4117        og_dbi_close(dbi);
4118
4119        return 0;
4120}
4121
4122static int og_cmd_schedule_create(json_t *element, struct og_msg_params *params)
4123{
4124        const char *key;
4125        json_t *value;
4126        int err;
4127
4128        if (json_typeof(element) != JSON_OBJECT)
4129                return -1;
4130
4131        json_object_foreach(element, key, value) {
4132                if (!strcmp(key, "task")) {
4133                        err = og_json_parse_string(value, &params->task_id);
4134                        params->flags |= OG_REST_PARAM_TASK;
4135                } else if (!strcmp(key, "name")) {
4136                        err = og_json_parse_string(value, &params->name);
4137                        params->flags |= OG_REST_PARAM_NAME;
4138                } else if (!strcmp(key, "when")) {
4139                        err = og_json_parse_time_params(value, params);
4140                } else if (!strcmp(key, "type")) {
4141                        err = og_json_parse_string(value, &params->type);
4142                        params->flags |= OG_REST_PARAM_TYPE;
4143                }
4144
4145                if (err < 0)
4146                        break;
4147        }
4148
4149        if (!og_msg_params_validate(params, OG_REST_PARAM_TASK |
4150                                            OG_REST_PARAM_NAME |
4151                                            OG_REST_PARAM_TIME_YEARS |
4152                                            OG_REST_PARAM_TIME_MONTHS |
4153                                            OG_REST_PARAM_TIME_WEEKS |
4154                                            OG_REST_PARAM_TIME_WEEK_DAYS |
4155                                            OG_REST_PARAM_TIME_DAYS |
4156                                            OG_REST_PARAM_TIME_HOURS |
4157                                            OG_REST_PARAM_TIME_MINUTES |
4158                                            OG_REST_PARAM_TIME_AM_PM |
4159                                            OG_REST_PARAM_TYPE))
4160                return -1;
4161
4162        return og_task_schedule_create(params);
4163}
4164
4165static int og_cmd_schedule_update(json_t *element, struct og_msg_params *params)
4166{
4167        struct og_dbi *dbi;
4168        const char *key;
4169        json_t *value;
4170        int err;
4171
4172        if (json_typeof(element) != JSON_OBJECT)
4173                return -1;
4174
4175        json_object_foreach(element, key, value) {
4176                if (!strcmp(key, "id")) {
4177                        err = og_json_parse_string(value, &params->id);
4178                        params->flags |= OG_REST_PARAM_ID;
4179                } else if (!strcmp(key, "task")) {
4180                        err = og_json_parse_string(value, &params->task_id);
4181                        params->flags |= OG_REST_PARAM_TASK;
4182                } else if (!strcmp(key, "name")) {
4183                        err = og_json_parse_string(value, &params->name);
4184                        params->flags |= OG_REST_PARAM_NAME;
4185                } else if (!strcmp(key, "when"))
4186                        err = og_json_parse_time_params(value, params);
4187
4188                if (err < 0)
4189                        break;
4190        }
4191
4192        if (!og_msg_params_validate(params, OG_REST_PARAM_ID |
4193                                            OG_REST_PARAM_TASK |
4194                                            OG_REST_PARAM_NAME |
4195                                            OG_REST_PARAM_TIME_YEARS |
4196                                            OG_REST_PARAM_TIME_MONTHS |
4197                                            OG_REST_PARAM_TIME_DAYS |
4198                                            OG_REST_PARAM_TIME_HOURS |
4199                                            OG_REST_PARAM_TIME_MINUTES |
4200                                            OG_REST_PARAM_TIME_AM_PM))
4201                return -1;
4202
4203        dbi = og_dbi_open(&dbi_config);
4204        if (!dbi) {
4205                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
4206                           __func__, __LINE__);
4207                return -1;
4208        }
4209
4210        err = og_dbi_schedule_update(dbi, params);
4211        og_dbi_close(dbi);
4212
4213        if (err < 0)
4214                return err;
4215
4216        og_schedule_update(og_loop, atoi(params->id), atoi(params->task_id),
4217                           &params->time);
4218        og_schedule_refresh(og_loop);
4219
4220        return err;
4221}
4222
4223static int og_cmd_schedule_delete(json_t *element, struct og_msg_params *params)
4224{
4225        struct og_dbi *dbi;
4226        const char *key;
4227        json_t *value;
4228        int err;
4229
4230        if (json_typeof(element) != JSON_OBJECT)
4231                return -1;
4232
4233        json_object_foreach(element, key, value) {
4234                if (!strcmp(key, "id")) {
4235                        err = og_json_parse_string(value, &params->id);
4236                        params->flags |= OG_REST_PARAM_ID;
4237                } else {
4238                        return -1;
4239                }
4240
4241                if (err < 0)
4242                        break;
4243        }
4244
4245        if (!og_msg_params_validate(params, OG_REST_PARAM_ID))
4246                return -1;
4247
4248        dbi = og_dbi_open(&dbi_config);
4249        if (!dbi) {
4250                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
4251                           __func__, __LINE__);
4252                return -1;
4253        }
4254
4255        err = og_dbi_schedule_delete(dbi, atoi(params->id));
4256        og_dbi_close(dbi);
4257
4258        og_schedule_delete(og_loop, atoi(params->id));
4259
4260        return err;
4261}
4262
4263static int og_cmd_schedule_get(json_t *element, struct og_msg_params *params,
4264                               char *buffer_reply)
4265{
4266        struct og_buffer og_buffer = {
4267                .data   = buffer_reply,
4268        };
4269        json_t *schedule_root;
4270        struct og_dbi *dbi;
4271        const char *key;
4272        json_t *value;
4273        int err;
4274
4275        if (element) {
4276                if (json_typeof(element) != JSON_OBJECT)
4277                        return -1;
4278
4279                json_object_foreach(element, key, value) {
4280                        if (!strcmp(key, "task")) {
4281                                err = og_json_parse_string(value,
4282                                                           &params->task_id);
4283                        } else if (!strcmp(key, "id")) {
4284                                err = og_json_parse_string(value, &params->id);
4285                        } else {
4286                                return -1;
4287                        }
4288
4289                        if (err < 0)
4290                                break;
4291                }
4292        }
4293
4294        dbi = og_dbi_open(&dbi_config);
4295        if (!dbi) {
4296                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
4297                           __func__, __LINE__);
4298                return -1;
4299        }
4300
4301        schedule_root = json_object();
4302        if (!schedule_root) {
4303                og_dbi_close(dbi);
4304                return -1;
4305        }
4306
4307        err = og_dbi_schedule_get_json(dbi, schedule_root,
4308                                       params->task_id, params->id);
4309        og_dbi_close(dbi);
4310
4311        if (err >= 0)
4312                json_dump_callback(schedule_root, og_json_dump_clients, &og_buffer, 0);
4313
4314        json_decref(schedule_root);
4315
4316        return err;
4317}
4318
4319static int og_client_method_not_found(struct og_client *cli)
4320{
4321        /* To meet RFC 7231, this function MUST generate an Allow header field
4322         * containing the correct methods. For example: "Allow: POST\r\n"
4323         */
4324        char buf[] = "HTTP/1.1 405 Method Not Allowed\r\n"
4325                     "Content-Length: 0\r\n\r\n";
4326
4327        send(og_client_socket(cli), buf, strlen(buf), 0);
4328
4329        return -1;
4330}
4331
4332static int og_client_bad_request(struct og_client *cli)
4333{
4334        char buf[] = "HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\n\r\n";
4335
4336        send(og_client_socket(cli), buf, strlen(buf), 0);
4337
4338        return -1;
4339}
4340
4341static int og_client_not_found(struct og_client *cli)
4342{
4343        char buf[] = "HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n";
4344
4345        send(og_client_socket(cli), buf, strlen(buf), 0);
4346
4347        return -1;
4348}
4349
4350static int og_client_not_authorized(struct og_client *cli)
4351{
4352        char buf[] = "HTTP/1.1 401 Unauthorized\r\n"
4353                     "WWW-Authenticate: Basic\r\n"
4354                     "Content-Length: 0\r\n\r\n";
4355
4356        send(og_client_socket(cli), buf, strlen(buf), 0);
4357
4358        return -1;
4359}
4360
4361static int og_server_internal_error(struct og_client *cli)
4362{
4363        char buf[] = "HTTP/1.1 500 Internal Server Error\r\n"
4364                     "Content-Length: 0\r\n\r\n";
4365
4366        send(og_client_socket(cli), buf, strlen(buf), 0);
4367
4368        return -1;
4369}
4370
4371static int og_client_payload_too_large(struct og_client *cli)
4372{
4373        char buf[] = "HTTP/1.1 413 Payload Too Large\r\n"
4374                     "Content-Length: 0\r\n\r\n";
4375
4376        send(og_client_socket(cli), buf, strlen(buf), 0);
4377
4378        return -1;
4379}
4380
4381#define OG_MSG_RESPONSE_MAXLEN  65536
4382
4383static int og_client_ok(struct og_client *cli, char *buf_reply)
4384{
4385        char buf[OG_MSG_RESPONSE_MAXLEN] = {};
4386        int err = 0, len;
4387
4388        len = snprintf(buf, sizeof(buf),
4389                       "HTTP/1.1 200 OK\r\nContent-Length: %ld\r\n\r\n%s",
4390                       strlen(buf_reply), buf_reply);
4391        if (len >= (int)sizeof(buf))
4392                err = og_server_internal_error(cli);
4393
4394        send(og_client_socket(cli), buf, strlen(buf), 0);
4395
4396        return err;
4397}
4398
4399static int og_client_state_process_payload_rest(struct og_client *cli)
4400{
4401        char buf_reply[OG_MSG_RESPONSE_MAXLEN] = {};
4402        struct og_msg_params params = {};
4403        enum og_rest_method method;
4404        const char *cmd, *body;
4405        json_error_t json_err;
4406        json_t *root = NULL;
4407        int err = 0;
4408
4409        syslog(LOG_DEBUG, "%s:%hu %.32s ...\n",
4410               inet_ntoa(cli->addr.sin_addr),
4411               ntohs(cli->addr.sin_port), cli->buf);
4412
4413        if (!strncmp(cli->buf, "GET", strlen("GET"))) {
4414                method = OG_METHOD_GET;
4415                cmd = cli->buf + strlen("GET") + 2;
4416        } else if (!strncmp(cli->buf, "POST", strlen("POST"))) {
4417                method = OG_METHOD_POST;
4418                cmd = cli->buf + strlen("POST") + 2;
4419        } else
4420                return og_client_method_not_found(cli);
4421
4422        body = strstr(cli->buf, "\r\n\r\n") + 4;
4423
4424        if (strcmp(cli->auth_token, auth_token)) {
4425                syslog(LOG_ERR, "wrong Authentication key\n");
4426                return og_client_not_authorized(cli);
4427        }
4428
4429        if (cli->content_length) {
4430                root = json_loads(body, 0, &json_err);
4431                if (!root) {
4432                        syslog(LOG_ERR, "malformed json line %d: %s\n",
4433                               json_err.line, json_err.text);
4434                        return og_client_not_found(cli);
4435                }
4436        }
4437
4438        if (!strncmp(cmd, "clients", strlen("clients"))) {
4439                if (method != OG_METHOD_POST &&
4440                    method != OG_METHOD_GET)
4441                        return og_client_method_not_found(cli);
4442
4443                if (method == OG_METHOD_POST && !root) {
4444                        syslog(LOG_ERR, "command clients with no payload\n");
4445                        return og_client_bad_request(cli);
4446                }
4447                switch (method) {
4448                case OG_METHOD_POST:
4449                        err = og_cmd_post_clients(root, &params);
4450                        break;
4451                case OG_METHOD_GET:
4452                        err = og_cmd_get_clients(root, &params, buf_reply);
4453                        break;
4454                default:
4455                        return og_client_bad_request(cli);
4456                }
4457        } else if (!strncmp(cmd, "wol", strlen("wol"))) {
4458                if (method != OG_METHOD_POST)
4459                        return og_client_method_not_found(cli);
4460
4461                if (!root) {
4462                        syslog(LOG_ERR, "command wol with no payload\n");
4463                        return og_client_bad_request(cli);
4464                }
4465                err = og_cmd_wol(root, &params);
4466        } else if (!strncmp(cmd, "shell/run", strlen("shell/run"))) {
4467                if (method != OG_METHOD_POST)
4468                        return og_client_method_not_found(cli);
4469
4470                if (!root) {
4471                        syslog(LOG_ERR, "command run with no payload\n");
4472                        return og_client_bad_request(cli);
4473                }
4474                err = og_cmd_run_post(root, &params);
4475        } else if (!strncmp(cmd, "shell/output", strlen("shell/output"))) {
4476                if (method != OG_METHOD_POST)
4477                        return og_client_method_not_found(cli);
4478
4479                if (!root) {
4480                        syslog(LOG_ERR, "command output with no payload\n");
4481                        return og_client_bad_request(cli);
4482                }
4483
4484                err = og_cmd_run_get(root, &params, buf_reply);
4485        } else if (!strncmp(cmd, "session", strlen("session"))) {
4486                if (method != OG_METHOD_POST)
4487                        return og_client_method_not_found(cli);
4488
4489                if (!root) {
4490                        syslog(LOG_ERR, "command session with no payload\n");
4491                        return og_client_bad_request(cli);
4492                }
4493                err = og_cmd_session(root, &params);
4494        } else if (!strncmp(cmd, "poweroff", strlen("poweroff"))) {
4495                if (method != OG_METHOD_POST)
4496                        return og_client_method_not_found(cli);
4497
4498                if (!root) {
4499                        syslog(LOG_ERR, "command poweroff with no payload\n");
4500                        return og_client_bad_request(cli);
4501                }
4502                err = og_cmd_poweroff(root, &params);
4503        } else if (!strncmp(cmd, "reboot", strlen("reboot"))) {
4504                if (method != OG_METHOD_POST)
4505                        return og_client_method_not_found(cli);
4506
4507                if (!root) {
4508                        syslog(LOG_ERR, "command reboot with no payload\n");
4509                        return og_client_bad_request(cli);
4510                }
4511                err = og_cmd_reboot(root, &params);
4512        } else if (!strncmp(cmd, "stop", strlen("stop"))) {
4513                if (method != OG_METHOD_POST)
4514                        return og_client_method_not_found(cli);
4515
4516                if (!root) {
4517                        syslog(LOG_ERR, "command stop with no payload\n");
4518                        return og_client_bad_request(cli);
4519                }
4520                err = og_cmd_stop(root, &params);
4521        } else if (!strncmp(cmd, "refresh", strlen("refresh"))) {
4522                if (method != OG_METHOD_POST)
4523                        return og_client_method_not_found(cli);
4524
4525                if (!root) {
4526                        syslog(LOG_ERR, "command refresh with no payload\n");
4527                        return og_client_bad_request(cli);
4528                }
4529                err = og_cmd_refresh(root, &params);
4530        } else if (!strncmp(cmd, "hardware", strlen("hardware"))) {
4531                if (method != OG_METHOD_POST)
4532                        return og_client_method_not_found(cli);
4533
4534                if (!root) {
4535                        syslog(LOG_ERR, "command hardware with no payload\n");
4536                        return og_client_bad_request(cli);
4537                }
4538                err = og_cmd_hardware(root, &params);
4539        } else if (!strncmp(cmd, "software", strlen("software"))) {
4540                if (method != OG_METHOD_POST)
4541                        return og_client_method_not_found(cli);
4542
4543                if (!root) {
4544                        syslog(LOG_ERR, "command software with no payload\n");
4545                        return og_client_bad_request(cli);
4546                }
4547                err = og_cmd_software(root, &params);
4548        } else if (!strncmp(cmd, "image/create/basic",
4549                            strlen("image/create/basic"))) {
4550                if (method != OG_METHOD_POST)
4551                        return og_client_method_not_found(cli);
4552
4553                if (!root) {
4554                        syslog(LOG_ERR, "command create with no payload\n");
4555                        return og_client_bad_request(cli);
4556                }
4557                err = og_cmd_create_basic_image(root, &params);
4558        } else if (!strncmp(cmd, "image/create/incremental",
4559                            strlen("image/create/incremental"))) {
4560                if (method != OG_METHOD_POST)
4561                        return og_client_method_not_found(cli);
4562
4563                if (!root) {
4564                        syslog(LOG_ERR, "command create with no payload\n");
4565                        return og_client_bad_request(cli);
4566                }
4567                err = og_cmd_create_incremental_image(root, &params);
4568        } else if (!strncmp(cmd, "image/create", strlen("image/create"))) {
4569                if (method != OG_METHOD_POST)
4570                        return og_client_method_not_found(cli);
4571
4572                if (!root) {
4573                        syslog(LOG_ERR, "command create with no payload\n");
4574                        return og_client_bad_request(cli);
4575                }
4576                err = og_cmd_create_image(root, &params);
4577        } else if (!strncmp(cmd, "image/restore/basic",
4578                                strlen("image/restore/basic"))) {
4579                if (method != OG_METHOD_POST)
4580                        return og_client_method_not_found(cli);
4581
4582                if (!root) {
4583                        syslog(LOG_ERR, "command create with no payload\n");
4584                        return og_client_bad_request(cli);
4585                }
4586                err = og_cmd_restore_basic_image(root, &params);
4587        } else if (!strncmp(cmd, "image/restore/incremental",
4588                                strlen("image/restore/incremental"))) {
4589                if (method != OG_METHOD_POST)
4590                        return og_client_method_not_found(cli);
4591
4592                if (!root) {
4593                        syslog(LOG_ERR, "command create with no payload\n");
4594                        return og_client_bad_request(cli);
4595                }
4596                err = og_cmd_restore_incremental_image(root, &params);
4597        } else if (!strncmp(cmd, "image/restore", strlen("image/restore"))) {
4598                if (method != OG_METHOD_POST)
4599                        return og_client_method_not_found(cli);
4600
4601                if (!root) {
4602                        syslog(LOG_ERR, "command create with no payload\n");
4603                        return og_client_bad_request(cli);
4604                }
4605                err = og_cmd_restore_image(root, &params);
4606        } else if (!strncmp(cmd, "setup", strlen("setup"))) {
4607                if (method != OG_METHOD_POST)
4608                        return og_client_method_not_found(cli);
4609
4610                if (!root) {
4611                        syslog(LOG_ERR, "command create with no payload\n");
4612                        return og_client_bad_request(cli);
4613                }
4614                err = og_cmd_setup(root, &params);
4615        } else if (!strncmp(cmd, "run/schedule", strlen("run/schedule"))) {
4616                if (method != OG_METHOD_POST)
4617                        return og_client_method_not_found(cli);
4618
4619                if (!root) {
4620                        syslog(LOG_ERR, "command create with no payload\n");
4621                        return og_client_bad_request(cli);
4622                }
4623
4624                err = og_cmd_run_schedule(root, &params);
4625        } else if (!strncmp(cmd, "task/run", strlen("task/run"))) {
4626                if (method != OG_METHOD_POST)
4627                        return og_client_method_not_found(cli);
4628
4629                if (!root) {
4630                        syslog(LOG_ERR, "command task with no payload\n");
4631                        return og_client_bad_request(cli);
4632                }
4633                err = og_cmd_task_post(root, &params);
4634        } else if (!strncmp(cmd, "schedule/create",
4635                            strlen("schedule/create"))) {
4636                if (method != OG_METHOD_POST)
4637                        return og_client_method_not_found(cli);
4638
4639                if (!root) {
4640                        syslog(LOG_ERR, "command task with no payload\n");
4641                        return og_client_bad_request(cli);
4642                }
4643                err = og_cmd_schedule_create(root, &params);
4644        } else if (!strncmp(cmd, "schedule/delete",
4645                            strlen("schedule/delete"))) {
4646                if (method != OG_METHOD_POST)
4647                        return og_client_method_not_found(cli);
4648
4649                if (!root) {
4650                        syslog(LOG_ERR, "command task with no payload\n");
4651                        return og_client_bad_request(cli);
4652                }
4653                err = og_cmd_schedule_delete(root, &params);
4654        } else if (!strncmp(cmd, "schedule/update",
4655                            strlen("schedule/update"))) {
4656                if (method != OG_METHOD_POST)
4657                        return og_client_method_not_found(cli);
4658
4659                if (!root) {
4660                        syslog(LOG_ERR, "command task with no payload\n");
4661                        return og_client_bad_request(cli);
4662                }
4663                err = og_cmd_schedule_update(root, &params);
4664        } else if (!strncmp(cmd, "schedule/get",
4665                            strlen("schedule/get"))) {
4666                if (method != OG_METHOD_POST)
4667                        return og_client_method_not_found(cli);
4668
4669                err = og_cmd_schedule_get(root, &params, buf_reply);
4670        } else {
4671                syslog(LOG_ERR, "unknown command: %.32s ...\n", cmd);
4672                err = og_client_not_found(cli);
4673        }
4674
4675        if (root)
4676                json_decref(root);
4677
4678        if (err < 0)
4679                return og_client_bad_request(cli);
4680
4681        err = og_client_ok(cli, buf_reply);
4682        if (err < 0) {
4683                syslog(LOG_ERR, "HTTP response to %s:%hu is too large\n",
4684                       inet_ntoa(cli->addr.sin_addr),
4685                       ntohs(cli->addr.sin_port));
4686        }
4687
4688        return err;
4689}
4690
4691static int og_client_state_recv_hdr_rest(struct og_client *cli)
4692{
4693        char *ptr;
4694
4695        ptr = strstr(cli->buf, "\r\n\r\n");
4696        if (!ptr)
4697                return 0;
4698
4699        cli->msg_len = ptr - cli->buf + 4;
4700
4701        ptr = strstr(cli->buf, "Content-Length: ");
4702        if (ptr) {
4703                sscanf(ptr, "Content-Length: %i[^\r\n]", &cli->content_length);
4704                if (cli->content_length < 0)
4705                        return -1;
4706                cli->msg_len += cli->content_length;
4707        }
4708
4709        ptr = strstr(cli->buf, "Authorization: ");
4710        if (ptr)
4711                sscanf(ptr, "Authorization: %63[^\r\n]", cli->auth_token);
4712
4713        return 1;
4714}
4715
4716static int og_client_recv(struct og_client *cli, int events)
4717{
4718        struct ev_io *io = &cli->io;
4719        int ret;
4720
4721        if (events & EV_ERROR) {
4722                syslog(LOG_ERR, "unexpected error event from client %s:%hu\n",
4723                               inet_ntoa(cli->addr.sin_addr),
4724                               ntohs(cli->addr.sin_port));
4725                return 0;
4726        }
4727
4728        ret = recv(io->fd, cli->buf + cli->buf_len,
4729                   sizeof(cli->buf) - cli->buf_len, 0);
4730        if (ret <= 0) {
4731                if (ret < 0) {
4732                        syslog(LOG_ERR, "error reading from client %s:%hu (%s)\n",
4733                               inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port),
4734                               strerror(errno));
4735                } else {
4736                        syslog(LOG_DEBUG, "closed connection by %s:%hu\n",
4737                               inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
4738                }
4739                return ret;
4740        }
4741
4742        return ret;
4743}
4744
4745static void og_client_read_cb(struct ev_loop *loop, struct ev_io *io, int events)
4746{
4747        struct og_client *cli;
4748        int ret;
4749
4750        cli = container_of(io, struct og_client, io);
4751
4752        ret = og_client_recv(cli, events);
4753        if (ret <= 0)
4754                goto close;
4755
4756        if (cli->keepalive_idx >= 0)
4757                return;
4758
4759        ev_timer_again(loop, &cli->timer);
4760
4761        cli->buf_len += ret;
4762        if (cli->buf_len >= sizeof(cli->buf)) {
4763                syslog(LOG_ERR, "client request from %s:%hu is too long\n",
4764                       inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
4765                og_client_payload_too_large(cli);
4766                goto close;
4767        }
4768
4769        switch (cli->state) {
4770        case OG_CLIENT_RECEIVING_HEADER:
4771                ret = og_client_state_recv_hdr_rest(cli);
4772                if (ret < 0)
4773                        goto close;
4774                if (!ret)
4775                        return;
4776
4777                cli->state = OG_CLIENT_RECEIVING_PAYLOAD;
4778                /* Fall through. */
4779        case OG_CLIENT_RECEIVING_PAYLOAD:
4780                /* Still not enough data to process request. */
4781                if (cli->buf_len < cli->msg_len)
4782                        return;
4783
4784                cli->state = OG_CLIENT_PROCESSING_REQUEST;
4785                /* fall through. */
4786        case OG_CLIENT_PROCESSING_REQUEST:
4787                ret = og_client_state_process_payload_rest(cli);
4788                if (ret < 0) {
4789                        syslog(LOG_ERR, "Failed to process HTTP request from %s:%hu\n",
4790                               inet_ntoa(cli->addr.sin_addr),
4791                               ntohs(cli->addr.sin_port));
4792                }
4793                if (ret < 0)
4794                        goto close;
4795
4796                if (cli->keepalive_idx < 0) {
4797                        syslog(LOG_DEBUG, "server closing connection to %s:%hu\n",
4798                               inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
4799                        goto close;
4800                } else {
4801                        syslog(LOG_DEBUG, "leaving client %s:%hu in keepalive mode\n",
4802                               inet_ntoa(cli->addr.sin_addr),
4803                               ntohs(cli->addr.sin_port));
4804                        og_client_keepalive(loop, cli);
4805                        og_client_reset_state(cli);
4806                }
4807                break;
4808        default:
4809                syslog(LOG_ERR, "unknown state, critical internal error\n");
4810                goto close;
4811        }
4812        return;
4813close:
4814        ev_timer_stop(loop, &cli->timer);
4815        og_client_release(loop, cli);
4816}
4817
4818enum og_agent_state {
4819        OG_AGENT_RECEIVING_HEADER       = 0,
4820        OG_AGENT_RECEIVING_PAYLOAD,
4821        OG_AGENT_PROCESSING_RESPONSE,
4822};
4823
4824static int og_agent_state_recv_hdr_rest(struct og_client *cli)
4825{
4826        char *ptr;
4827
4828        ptr = strstr(cli->buf, "\r\n\r\n");
4829        if (!ptr)
4830                return 0;
4831
4832        cli->msg_len = ptr - cli->buf + 4;
4833
4834        ptr = strstr(cli->buf, "Content-Length: ");
4835        if (ptr) {
4836                sscanf(ptr, "Content-Length: %i[^\r\n]", &cli->content_length);
4837                if (cli->content_length < 0)
4838                        return -1;
4839                cli->msg_len += cli->content_length;
4840        }
4841
4842        return 1;
4843}
4844
4845static void og_agent_reset_state(struct og_client *cli)
4846{
4847        cli->state = OG_AGENT_RECEIVING_HEADER;
4848        cli->buf_len = 0;
4849        cli->content_length = 0;
4850        memset(cli->buf, 0, sizeof(cli->buf));
4851}
4852
4853static int og_dbi_get_computer_info(struct og_computer *computer,
4854                                    struct in_addr addr)
4855{
4856        const char *msglog;
4857        struct og_dbi *dbi;
4858        dbi_result result;
4859
4860        dbi = og_dbi_open(&dbi_config);
4861        if (!dbi) {
4862                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
4863                       __func__, __LINE__);
4864                return -1;
4865        }
4866        result = dbi_conn_queryf(dbi->conn,
4867                                 "SELECT ordenadores.idordenador,"
4868                                 "       ordenadores.nombreordenador,"
4869                                 "       ordenadores.idaula,"
4870                                 "       ordenadores.idproautoexec,"
4871                                 "       centros.idcentro FROM ordenadores "
4872                                 "INNER JOIN aulas ON aulas.idaula=ordenadores.idaula "
4873                                 "INNER JOIN centros ON centros.idcentro=aulas.idcentro "
4874                                 "WHERE ordenadores.ip='%s'", inet_ntoa(addr));
4875        if (!result) {
4876                dbi_conn_error(dbi->conn, &msglog);
4877                syslog(LOG_ERR, "failed to query database (%s:%d) %s\n",
4878                       __func__, __LINE__, msglog);
4879                og_dbi_close(dbi);
4880                return -1;
4881        }
4882        if (!dbi_result_next_row(result)) {
4883                syslog(LOG_ERR, "client does not exist in database (%s:%d)\n",
4884                       __func__, __LINE__);
4885                dbi_result_free(result);
4886                og_dbi_close(dbi);
4887                return -1;
4888        }
4889
4890        computer->id = dbi_result_get_uint(result, "idordenador");
4891        computer->center = dbi_result_get_uint(result, "idcentro");
4892        computer->room = dbi_result_get_uint(result, "idaula");
4893        computer->procedure_id = dbi_result_get_uint(result, "idproautoexec");
4894        strncpy(computer->name,
4895                dbi_result_get_string(result, "nombreordenador"),
4896                OG_COMPUTER_NAME_MAXLEN);
4897
4898        dbi_result_free(result);
4899        og_dbi_close(dbi);
4900
4901        return 0;
4902}
4903
4904static int og_resp_probe(struct og_client *cli, json_t *data)
4905{
4906        const char *status = NULL;
4907        const char *key;
4908        json_t *value;
4909        int err = 0;
4910
4911        if (json_typeof(data) != JSON_OBJECT)
4912                return -1;
4913
4914        json_object_foreach(data, key, value) {
4915                if (!strcmp(key, "status")) {
4916                        err = og_json_parse_string(value, &status);
4917                        if (err < 0)
4918                                return err;
4919                } else {
4920                        return -1;
4921                }
4922        }
4923
4924        if (!strcmp(status, "BSY"))
4925                cli->status = OG_CLIENT_STATUS_BUSY;
4926        else if (!strcmp(status, "OPG"))
4927                cli->status = OG_CLIENT_STATUS_OGLIVE;
4928
4929        return status ? 0 : -1;
4930}
4931
4932static int og_resp_shell_run(struct og_client *cli, json_t *data)
4933{
4934        const char *output = NULL;
4935        char filename[4096];
4936        const char *key;
4937        json_t *value;
4938        int err = -1;
4939        FILE *file;
4940
4941        if (json_typeof(data) != JSON_OBJECT)
4942                return -1;
4943
4944        json_object_foreach(data, key, value) {
4945                if (!strcmp(key, "out")) {
4946                        err = og_json_parse_string(value, &output);
4947                        if (err < 0)
4948                                return err;
4949                } else {
4950                        return -1;
4951                }
4952        }
4953
4954        if (!output) {
4955                syslog(LOG_ERR, "%s:%d: malformed json response\n",
4956                       __FILE__, __LINE__);
4957                return -1;
4958        }
4959
4960        sprintf(filename, "/tmp/_Seconsola_%s", inet_ntoa(cli->addr.sin_addr));
4961        file = fopen(filename, "wt");
4962        if (!file) {
4963                syslog(LOG_ERR, "cannot open file %s: %s\n",
4964                       filename, strerror(errno));
4965                return -1;
4966        }
4967
4968        fprintf(file, "%s", output);
4969        fclose(file);
4970
4971        return 0;
4972}
4973
4974struct og_computer_legacy  {
4975        char center[OG_DB_INT_MAXLEN + 1];
4976        char id[OG_DB_INT_MAXLEN + 1];
4977        char hardware[8192];
4978};
4979
4980static int og_resp_hardware(json_t *data, struct og_client *cli)
4981{
4982        struct og_computer_legacy legacy = {};
4983        const char *hardware = NULL;
4984        struct og_computer computer;
4985        struct og_dbi *dbi;
4986        const char *key;
4987        json_t *value;
4988        int err = 0;
4989        bool res;
4990
4991        if (json_typeof(data) != JSON_OBJECT)
4992                return -1;
4993
4994        json_object_foreach(data, key, value) {
4995                if (!strcmp(key, "hardware")) {
4996                        err = og_json_parse_string(value, &hardware);
4997                        if (err < 0)
4998                                return -1;
4999                } else {
5000                        return -1;
5001                }
5002        }
5003
5004        if (!hardware) {
5005                syslog(LOG_ERR, "malformed response json\n");
5006                return -1;
5007        }
5008
5009        err = og_dbi_get_computer_info(&computer, cli->addr.sin_addr);
5010        if (err < 0)
5011                return -1;
5012
5013        snprintf(legacy.center, sizeof(legacy.center), "%d", computer.center);
5014        snprintf(legacy.id, sizeof(legacy.id), "%d", computer.id);
5015        snprintf(legacy.hardware, sizeof(legacy.hardware), "%s", hardware);
5016
5017        dbi = og_dbi_open(&dbi_config);
5018        if (!dbi) {
5019                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
5020                       __func__, __LINE__);
5021                return -1;
5022        }
5023
5024        res = actualizaHardware(dbi, legacy.hardware, legacy.id, computer.name,
5025                                legacy.center);
5026        og_dbi_close(dbi);
5027
5028        if (!res) {
5029                syslog(LOG_ERR, "Problem updating client configuration\n");
5030                return -1;
5031        }
5032
5033        return 0;
5034}
5035
5036struct og_software_legacy {
5037        char software[8192];
5038        char center[OG_DB_INT_MAXLEN + 1];
5039        char part[OG_DB_SMALLINT_MAXLEN + 1];
5040        char id[OG_DB_INT_MAXLEN + 1];
5041};
5042
5043static int og_resp_software(json_t *data, struct og_client *cli)
5044{
5045        struct og_software_legacy legacy = {};
5046        const char *partition = NULL;
5047        const char *software = NULL;
5048        struct og_computer computer;
5049        struct og_dbi *dbi;
5050        const char *key;
5051        json_t *value;
5052        int err = 0;
5053        bool res;
5054
5055        if (json_typeof(data) != JSON_OBJECT)
5056                return -1;
5057
5058        json_object_foreach(data, key, value) {
5059                if (!strcmp(key, "software"))
5060                        err = og_json_parse_string(value, &software);
5061                else if (!strcmp(key, "partition"))
5062                        err = og_json_parse_string(value, &partition);
5063                else
5064                        return -1;
5065
5066                if (err < 0)
5067                        return -1;
5068        }
5069
5070        if (!software || !partition) {
5071                syslog(LOG_ERR, "malformed response json\n");
5072                return -1;
5073        }
5074
5075        err = og_dbi_get_computer_info(&computer, cli->addr.sin_addr);
5076        if (err < 0)
5077                return -1;
5078
5079        snprintf(legacy.software, sizeof(legacy.software), "%s", software);
5080        snprintf(legacy.part, sizeof(legacy.part), "%s", partition);
5081        snprintf(legacy.id, sizeof(legacy.id), "%d", computer.id);
5082        snprintf(legacy.center, sizeof(legacy.center), "%d", computer.center);
5083
5084        dbi = og_dbi_open(&dbi_config);
5085        if (!dbi) {
5086                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
5087                       __func__, __LINE__);
5088                return -1;
5089        }
5090
5091        res = actualizaSoftware(dbi, legacy.software, legacy.part, legacy.id,
5092                                computer.name, legacy.center);
5093        og_dbi_close(dbi);
5094
5095        if (!res) {
5096                syslog(LOG_ERR, "Problem updating client configuration\n");
5097                return -1;
5098        }
5099
5100        return 0;
5101}
5102
5103#define OG_PARAMS_RESP_REFRESH  (OG_PARAM_PART_DISK |           \
5104                                 OG_PARAM_PART_NUMBER |         \
5105                                 OG_PARAM_PART_CODE |           \
5106                                 OG_PARAM_PART_FILESYSTEM |     \
5107                                 OG_PARAM_PART_OS |             \
5108                                 OG_PARAM_PART_SIZE |           \
5109                                 OG_PARAM_PART_USED_SIZE)
5110
5111static int og_json_parse_partition_array(json_t *value,
5112                                         struct og_partition *partitions)
5113{
5114        json_t *element;
5115        int i, err;
5116
5117        if (json_typeof(value) != JSON_ARRAY)
5118                return -1;
5119
5120        for (i = 0; i < json_array_size(value) && i < OG_PARTITION_MAX; i++) {
5121                element = json_array_get(value, i);
5122
5123                err = og_json_parse_partition(element, &partitions[i],
5124                                              OG_PARAMS_RESP_REFRESH);
5125                if (err < 0)
5126                        return err;
5127        }
5128
5129        return 0;
5130}
5131
5132static int og_dbi_queue_autorun(uint32_t computer_id, uint32_t proc_id)
5133{
5134        struct og_task dummy_task = {
5135                .scope          = computer_id,
5136                .type_scope     = AMBITO_ORDENADORES,
5137                .procedure_id   = proc_id,
5138        };
5139        struct og_dbi *dbi;
5140
5141        dbi = og_dbi_open(&dbi_config);
5142        if (!dbi) {
5143                syslog(LOG_ERR, "cannot open connection database "
5144                                "(%s:%d)\n", __func__, __LINE__);
5145                return -1;
5146        }
5147        if (og_dbi_queue_procedure(dbi, &dummy_task)) {
5148                og_dbi_close(dbi);
5149                return -1;
5150        }
5151        og_dbi_close(dbi);
5152
5153        return 0;
5154}
5155
5156static int og_resp_refresh(json_t *data, struct og_client *cli)
5157{
5158        struct og_partition partitions[OG_PARTITION_MAX] = {};
5159        const char *serial_number = NULL;
5160        struct og_computer computer = {};
5161        struct og_partition disk_setup;
5162        char cfg[1024] = {};
5163        struct og_dbi *dbi;
5164        const char *key;
5165        unsigned int i;
5166        json_t *value;
5167        int err = 0;
5168        bool res;
5169
5170        if (json_typeof(data) != JSON_OBJECT)
5171                return -1;
5172
5173        json_object_foreach(data, key, value) {
5174                if (!strcmp(key, "disk_setup")) {
5175                        err = og_json_parse_partition(value,
5176                                                      &disk_setup,
5177                                                      OG_PARAMS_RESP_REFRESH);
5178                } else if (!strcmp(key, "partition_setup")) {
5179                        err = og_json_parse_partition_array(value, partitions);
5180                } else if (!strcmp(key, "serial_number")) {
5181                        err = og_json_parse_string(value, &serial_number);
5182                } else {
5183                        return -1;
5184                }
5185
5186                if (err < 0)
5187                        return err;
5188        }
5189
5190        err = og_dbi_get_computer_info(&computer, cli->addr.sin_addr);
5191        if (err < 0)
5192                return -1;
5193
5194        if (strlen(serial_number) > 0)
5195                snprintf(cfg, sizeof(cfg), "ser=%s\n", serial_number);
5196
5197        if (!disk_setup.disk || !disk_setup.number || !disk_setup.code ||
5198            !disk_setup.filesystem || !disk_setup.os || !disk_setup.size ||
5199            !disk_setup.used_size)
5200                return -1;
5201
5202        snprintf(cfg + strlen(cfg), sizeof(cfg) - strlen(cfg),
5203                 "disk=%s\tpar=%s\tcpt=%s\tfsi=%s\tsoi=%s\ttam=%s\tuso=%s\n",
5204                 disk_setup.disk, disk_setup.number, disk_setup.code,
5205                 disk_setup.filesystem, disk_setup.os, disk_setup.size,
5206                 disk_setup.used_size);
5207
5208        for (i = 0; i < OG_PARTITION_MAX; i++) {
5209                if (!partitions[i].disk || !partitions[i].number ||
5210                    !partitions[i].code || !partitions[i].filesystem ||
5211                    !partitions[i].os || !partitions[i].size ||
5212                    !partitions[i].used_size)
5213                        continue;
5214
5215                snprintf(cfg + strlen(cfg), sizeof(cfg) - strlen(cfg),
5216                         "disk=%s\tpar=%s\tcpt=%s\tfsi=%s\tsoi=%s\ttam=%s\tuso=%s\n",
5217                         partitions[i].disk, partitions[i].number,
5218                         partitions[i].code, partitions[i].filesystem,
5219                         partitions[i].os, partitions[i].size,
5220                         partitions[i].used_size);
5221        }
5222
5223        dbi = og_dbi_open(&dbi_config);
5224        if (!dbi) {
5225                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
5226                                  __func__, __LINE__);
5227                return -1;
5228        }
5229        res = actualizaConfiguracion(dbi, cfg, computer.id);
5230        og_dbi_close(dbi);
5231
5232        if (!res) {
5233                syslog(LOG_ERR, "Problem updating client configuration\n");
5234                return -1;
5235        }
5236
5237        if (!cli->autorun && computer.procedure_id) {
5238                cli->autorun = true;
5239
5240                if (og_dbi_queue_autorun(computer.id, computer.procedure_id))
5241                        return -1;
5242        }
5243
5244        return 0;
5245}
5246
5247static int og_resp_image_create(json_t *data, struct og_client *cli)
5248{
5249        struct og_software_legacy soft_legacy;
5250        struct og_image_legacy img_legacy;
5251        const char *partition = NULL;
5252        const char *software = NULL;
5253        const char *image_id = NULL;
5254        struct og_computer computer;
5255        const char *disk = NULL;
5256        const char *code = NULL;
5257        const char *name = NULL;
5258        const char *repo = NULL;
5259        struct og_dbi *dbi;
5260        const char *key;
5261        json_t *value;
5262        int err = 0;
5263        bool res;
5264
5265        if (json_typeof(data) != JSON_OBJECT)
5266                return -1;
5267
5268        json_object_foreach(data, key, value) {
5269                if (!strcmp(key, "software"))
5270                        err = og_json_parse_string(value, &software);
5271                else if (!strcmp(key, "partition"))
5272                        err = og_json_parse_string(value, &partition);
5273                else if (!strcmp(key, "disk"))
5274                        err = og_json_parse_string(value, &disk);
5275                else if (!strcmp(key, "code"))
5276                        err = og_json_parse_string(value, &code);
5277                else if (!strcmp(key, "id"))
5278                        err = og_json_parse_string(value, &image_id);
5279                else if (!strcmp(key, "name"))
5280                        err = og_json_parse_string(value, &name);
5281                else if (!strcmp(key, "repository"))
5282                        err = og_json_parse_string(value, &repo);
5283                else
5284                        return -1;
5285
5286                if (err < 0)
5287                        return err;
5288        }
5289
5290        if (!software || !partition || !disk || !code || !image_id || !name ||
5291            !repo) {
5292                syslog(LOG_ERR, "malformed response json\n");
5293                return -1;
5294        }
5295
5296        err = og_dbi_get_computer_info(&computer, cli->addr.sin_addr);
5297        if (err < 0)
5298                return -1;
5299
5300        snprintf(soft_legacy.center, sizeof(soft_legacy.center), "%d",
5301                 computer.center);
5302        snprintf(soft_legacy.software, sizeof(soft_legacy.software), "%s",
5303                 software);
5304        snprintf(img_legacy.image_id, sizeof(img_legacy.image_id), "%s",
5305                 image_id);
5306        snprintf(soft_legacy.id, sizeof(soft_legacy.id), "%d", computer.id);
5307        snprintf(img_legacy.part, sizeof(img_legacy.part), "%s", partition);
5308        snprintf(img_legacy.disk, sizeof(img_legacy.disk), "%s", disk);
5309        snprintf(img_legacy.code, sizeof(img_legacy.code), "%s", code);
5310        snprintf(img_legacy.name, sizeof(img_legacy.name), "%s", name);
5311        snprintf(img_legacy.repo, sizeof(img_legacy.repo), "%s", repo);
5312
5313        dbi = og_dbi_open(&dbi_config);
5314        if (!dbi) {
5315                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
5316                       __func__, __LINE__);
5317                return -1;
5318        }
5319
5320        res = actualizaSoftware(dbi,
5321                                soft_legacy.software,
5322                                img_legacy.part,
5323                                soft_legacy.id,
5324                                computer.name,
5325                                soft_legacy.center);
5326        if (!res) {
5327                og_dbi_close(dbi);
5328                syslog(LOG_ERR, "Problem updating client configuration\n");
5329                return -1;
5330        }
5331
5332        res = actualizaCreacionImagen(dbi,
5333                                      img_legacy.image_id,
5334                                      img_legacy.disk,
5335                                      img_legacy.part,
5336                                      img_legacy.code,
5337                                      img_legacy.repo,
5338                                      soft_legacy.id);
5339        og_dbi_close(dbi);
5340
5341        if (!res) {
5342                syslog(LOG_ERR, "Problem updating client configuration\n");
5343                return -1;
5344        }
5345
5346        return 0;
5347}
5348
5349static int og_resp_image_restore(json_t *data, struct og_client *cli)
5350{
5351        struct og_software_legacy soft_legacy;
5352        struct og_image_legacy img_legacy;
5353        const char *partition = NULL;
5354        const char *image_id = NULL;
5355        struct og_computer computer;
5356        const char *disk = NULL;
5357        dbi_result query_result;
5358        struct og_dbi *dbi;
5359        const char *key;
5360        json_t *value;
5361        int err = 0;
5362        bool res;
5363
5364        if (json_typeof(data) != JSON_OBJECT)
5365                return -1;
5366
5367        json_object_foreach(data, key, value) {
5368                if (!strcmp(key, "partition"))
5369                        err = og_json_parse_string(value, &partition);
5370                else if (!strcmp(key, "disk"))
5371                        err = og_json_parse_string(value, &disk);
5372                else if (!strcmp(key, "image_id"))
5373                        err = og_json_parse_string(value, &image_id);
5374                else
5375                        return -1;
5376
5377                if (err < 0)
5378                        return err;
5379        }
5380
5381        if (!partition || !disk || !image_id) {
5382                syslog(LOG_ERR, "malformed response json\n");
5383                return -1;
5384        }
5385
5386        err = og_dbi_get_computer_info(&computer, cli->addr.sin_addr);
5387        if (err < 0)
5388                return -1;
5389
5390        snprintf(img_legacy.image_id, sizeof(img_legacy.image_id), "%s",
5391                 image_id);
5392        snprintf(img_legacy.part, sizeof(img_legacy.part), "%s", partition);
5393        snprintf(img_legacy.disk, sizeof(img_legacy.disk), "%s", disk);
5394        snprintf(soft_legacy.id, sizeof(soft_legacy.id), "%d", computer.id);
5395
5396        dbi = og_dbi_open(&dbi_config);
5397        if (!dbi) {
5398                syslog(LOG_ERR, "cannot open connection database (%s:%d)\n",
5399                       __func__, __LINE__);
5400                return -1;
5401        }
5402
5403        query_result = dbi_conn_queryf(dbi->conn,
5404                                       "SELECT idperfilsoft FROM imagenes "
5405                                       " WHERE idimagen='%s'",
5406                                       image_id);
5407        if (!query_result) {
5408                og_dbi_close(dbi);
5409                syslog(LOG_ERR, "failed to query database\n");
5410                return -1;
5411        }
5412        if (!dbi_result_next_row(query_result)) {
5413                dbi_result_free(query_result);
5414                og_dbi_close(dbi);
5415                syslog(LOG_ERR, "software profile does not exist in database\n");
5416                return -1;
5417        }
5418        snprintf(img_legacy.software_id, sizeof(img_legacy.software_id),
5419                 "%d", dbi_result_get_uint(query_result, "idperfilsoft"));
5420        dbi_result_free(query_result);
5421
5422        res = actualizaRestauracionImagen(dbi,
5423                                          img_legacy.image_id,
5424                                          img_legacy.disk,
5425                                          img_legacy.part,
5426                                          soft_legacy.id,
5427                                          img_legacy.software_id);
5428        og_dbi_close(dbi);
5429
5430        if (!res) {
5431                syslog(LOG_ERR, "Problem updating client configuration\n");
5432                return -1;
5433        }
5434
5435        return 0;
5436}
5437
5438static int og_agent_state_process_response(struct og_client *cli)
5439{
5440        json_error_t json_err;
5441        json_t *root;
5442        int err = -1;
5443        char *body;
5444
5445        if (!strncmp(cli->buf, "HTTP/1.0 202 Accepted",
5446                     strlen("HTTP/1.0 202 Accepted"))) {
5447                og_dbi_update_action(cli->last_cmd_id, true);
5448                cli->last_cmd_id = 0;
5449                return 1;
5450        }
5451
5452        if (strncmp(cli->buf, "HTTP/1.0 200 OK", strlen("HTTP/1.0 200 OK"))) {
5453                og_dbi_update_action(cli->last_cmd_id, false);
5454                cli->last_cmd_id = 0;
5455                return -1;
5456        }
5457        og_dbi_update_action(cli->last_cmd_id, true);
5458        cli->last_cmd_id = 0;
5459
5460        if (!cli->content_length) {
5461                cli->last_cmd = OG_CMD_UNSPEC;
5462                return 0;
5463        }
5464
5465        body = strstr(cli->buf, "\r\n\r\n") + 4;
5466
5467        root = json_loads(body, 0, &json_err);
5468        if (!root) {
5469                syslog(LOG_ERR, "%s:%d: malformed json line %d: %s\n",
5470                       __FILE__, __LINE__, json_err.line, json_err.text);
5471                return -1;
5472        }
5473
5474        switch (cli->last_cmd) {
5475        case OG_CMD_PROBE:
5476                err = og_resp_probe(cli, root);
5477                break;
5478        case OG_CMD_SHELL_RUN:
5479                err = og_resp_shell_run(cli, root);
5480                break;
5481        case OG_CMD_HARDWARE:
5482                err = og_resp_hardware(root, cli);
5483                break;
5484        case OG_CMD_SOFTWARE:
5485                err = og_resp_software(root, cli);
5486                break;
5487        case OG_CMD_REFRESH:
5488                err = og_resp_refresh(root, cli);
5489                break;
5490        case OG_CMD_SETUP:
5491                err = og_resp_refresh(root, cli);
5492                break;
5493        case OG_CMD_IMAGE_CREATE:
5494                err = og_resp_image_create(root, cli);
5495                break;
5496        case OG_CMD_IMAGE_RESTORE:
5497                err = og_resp_image_restore(root, cli);
5498                break;
5499        default:
5500                err = -1;
5501                break;
5502        }
5503
5504        cli->last_cmd = OG_CMD_UNSPEC;
5505
5506        return err;
5507}
5508
5509static void og_agent_deliver_pending_cmd(struct og_client *cli)
5510{
5511        const struct og_cmd *cmd;
5512
5513        cmd = og_cmd_find(inet_ntoa(cli->addr.sin_addr));
5514        if (!cmd)
5515                return;
5516
5517        og_send_request(cmd->method, cmd->type, &cmd->params, cmd->json);
5518        cli->last_cmd_id = cmd->id;
5519
5520        og_cmd_free(cmd);
5521}
5522
5523static void og_agent_read_cb(struct ev_loop *loop, struct ev_io *io, int events)
5524{
5525        struct og_client *cli;
5526        int ret;
5527
5528        cli = container_of(io, struct og_client, io);
5529
5530        ret = og_client_recv(cli, events);
5531        if (ret <= 0)
5532                goto close;
5533
5534        ev_timer_again(loop, &cli->timer);
5535
5536        cli->buf_len += ret;
5537        if (cli->buf_len >= sizeof(cli->buf)) {
5538                syslog(LOG_ERR, "client request from %s:%hu is too long\n",
5539                       inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
5540                goto close;
5541        }
5542
5543        switch (cli->state) {
5544        case OG_AGENT_RECEIVING_HEADER:
5545                ret = og_agent_state_recv_hdr_rest(cli);
5546                if (ret < 0)
5547                        goto close;
5548                if (!ret)
5549                        return;
5550
5551                cli->state = OG_AGENT_RECEIVING_PAYLOAD;
5552                /* Fall through. */
5553        case OG_AGENT_RECEIVING_PAYLOAD:
5554                /* Still not enough data to process request. */
5555                if (cli->buf_len < cli->msg_len)
5556                        return;
5557
5558                cli->state = OG_AGENT_PROCESSING_RESPONSE;
5559                /* fall through. */
5560        case OG_AGENT_PROCESSING_RESPONSE:
5561                ret = og_agent_state_process_response(cli);
5562                if (ret < 0) {
5563                        syslog(LOG_ERR, "Failed to process HTTP request from %s:%hu\n",
5564                               inet_ntoa(cli->addr.sin_addr),
5565                               ntohs(cli->addr.sin_port));
5566                        goto close;
5567                } else if (ret == 0) {
5568                        og_agent_deliver_pending_cmd(cli);
5569                }
5570
5571                syslog(LOG_DEBUG, "leaving client %s:%hu in keepalive mode\n",
5572                       inet_ntoa(cli->addr.sin_addr),
5573                       ntohs(cli->addr.sin_port));
5574                og_agent_reset_state(cli);
5575                break;
5576        default:
5577                syslog(LOG_ERR, "unknown state, critical internal error\n");
5578                goto close;
5579        }
5580        return;
5581close:
5582        ev_timer_stop(loop, &cli->timer);
5583        og_client_release(loop, cli);
5584}
5585
5586static void og_client_timer_cb(struct ev_loop *loop, ev_timer *timer, int events)
5587{
5588        struct og_client *cli;
5589
5590        cli = container_of(timer, struct og_client, timer);
5591        if (cli->keepalive_idx >= 0) {
5592                ev_timer_again(loop, &cli->timer);
5593                return;
5594        }
5595        syslog(LOG_ERR, "timeout request for client %s:%hu\n",
5596               inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
5597
5598        og_client_release(loop, cli);
5599}
5600
5601static void og_agent_send_refresh(struct og_client *cli)
5602{
5603        struct og_msg_params params;
5604        int err;
5605
5606        params.ips_array[0] = inet_ntoa(cli->addr.sin_addr);
5607        params.ips_array_len = 1;
5608
5609        err = og_send_request(OG_METHOD_GET, OG_CMD_REFRESH, &params, NULL);
5610        if (err < 0) {
5611                syslog(LOG_ERR, "Can't send refresh to: %s\n",
5612                       params.ips_array[0]);
5613        } else {
5614                syslog(LOG_INFO, "Sent refresh to: %s\n",
5615                       params.ips_array[0]);
5616        }
5617}
5618
5619static int socket_rest, socket_agent_rest;
5620
5621static void og_server_accept_cb(struct ev_loop *loop, struct ev_io *io,
5622                                int events)
5623{
5624        struct sockaddr_in client_addr;
5625        socklen_t addrlen = sizeof(client_addr);
5626        struct og_client *cli;
5627        int client_sd;
5628
5629        if (events & EV_ERROR)
5630                return;
5631
5632        client_sd = accept(io->fd, (struct sockaddr *)&client_addr, &addrlen);
5633        if (client_sd < 0) {
5634                syslog(LOG_ERR, "cannot accept client connection\n");
5635                return;
5636        }
5637
5638        cli = (struct og_client *)calloc(1, sizeof(struct og_client));
5639        if (!cli) {
5640                close(client_sd);
5641                return;
5642        }
5643        memcpy(&cli->addr, &client_addr, sizeof(client_addr));
5644        if (io->fd == socket_agent_rest)
5645                cli->keepalive_idx = 0;
5646        else
5647                cli->keepalive_idx = -1;
5648
5649        if (io->fd == socket_rest)
5650                cli->rest = true;
5651        else if (io->fd == socket_agent_rest)
5652                cli->agent = true;
5653
5654        syslog(LOG_DEBUG, "connection from client %s:%hu\n",
5655               inet_ntoa(cli->addr.sin_addr), ntohs(cli->addr.sin_port));
5656
5657        if (io->fd == socket_agent_rest)
5658                ev_io_init(&cli->io, og_agent_read_cb, client_sd, EV_READ);
5659        else
5660                ev_io_init(&cli->io, og_client_read_cb, client_sd, EV_READ);
5661
5662        ev_io_start(loop, &cli->io);
5663        if (io->fd == socket_agent_rest) {
5664                ev_timer_init(&cli->timer, og_client_timer_cb,
5665                              OG_AGENT_CLIENT_TIMEOUT, 0.);
5666        } else {
5667                ev_timer_init(&cli->timer, og_client_timer_cb,
5668                              OG_CLIENT_TIMEOUT, 0.);
5669        }
5670        ev_timer_start(loop, &cli->timer);
5671        list_add(&cli->list, &client_list);
5672
5673        if (io->fd == socket_agent_rest) {
5674                og_agent_send_refresh(cli);
5675        }
5676}
5677
5678static int og_socket_server_init(const char *port)
5679{
5680        struct sockaddr_in local;
5681        int sd, on = 1;
5682
5683        sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
5684        if (sd < 0) {
5685                syslog(LOG_ERR, "cannot create main socket\n");
5686                return -1;
5687        }
5688        setsockopt(sd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(int));
5689
5690        local.sin_addr.s_addr = htonl(INADDR_ANY);
5691        local.sin_family = AF_INET;
5692        local.sin_port = htons(atoi(port));
5693
5694        if (bind(sd, (struct sockaddr *) &local, sizeof(local)) < 0) {
5695                close(sd);
5696                syslog(LOG_ERR, "cannot bind socket\n");
5697                return -1;
5698        }
5699
5700        listen(sd, 250);
5701
5702        return sd;
5703}
5704
5705int main(int argc, char *argv[])
5706{
5707        struct ev_io ev_io_server_rest, ev_io_agent_rest;
5708        int i;
5709
5710        og_loop = ev_default_loop(0);
5711
5712        if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
5713                exit(EXIT_FAILURE);
5714
5715        openlog("ogAdmServer", LOG_PID, LOG_DAEMON);
5716
5717        /*--------------------------------------------------------------------------------------------------------
5718         Validación de parámetros de ejecución y lectura del fichero de configuración del servicio
5719         ---------------------------------------------------------------------------------------------------------*/
5720        if (!validacionParametros(argc, argv, 1)) // Valida parámetros de ejecución
5721                exit(EXIT_FAILURE);
5722
5723        if (!tomaConfiguracion(szPathFileCfg)) { // Toma parametros de configuracion
5724                exit(EXIT_FAILURE);
5725        }
5726
5727        /*--------------------------------------------------------------------------------------------------------
5728         // Inicializa array de información de los clientes
5729         ---------------------------------------------------------------------------------------------------------*/
5730        for (i = 0; i < MAXIMOS_CLIENTES; i++) {
5731                tbsockets[i].ip[0] = '\0';
5732                tbsockets[i].cli = NULL;
5733        }
5734        /*--------------------------------------------------------------------------------------------------------
5735         Creación y configuración del socket del servicio
5736         ---------------------------------------------------------------------------------------------------------*/
5737
5738        socket_rest = og_socket_server_init("8888");
5739        if (socket_rest < 0)
5740                exit(EXIT_FAILURE);
5741
5742        ev_io_init(&ev_io_server_rest, og_server_accept_cb, socket_rest, EV_READ);
5743        ev_io_start(og_loop, &ev_io_server_rest);
5744
5745        socket_agent_rest = og_socket_server_init("8889");
5746        if (socket_agent_rest < 0)
5747                exit(EXIT_FAILURE);
5748
5749        ev_io_init(&ev_io_agent_rest, og_server_accept_cb, socket_agent_rest, EV_READ);
5750        ev_io_start(og_loop, &ev_io_agent_rest);
5751
5752        if (og_dbi_schedule_get() < 0)
5753                exit(EXIT_FAILURE);
5754
5755        og_schedule_next(og_loop);
5756
5757        syslog(LOG_INFO, "Waiting for connections\n");
5758
5759        while (1)
5760                ev_loop(og_loop, 0);
5761
5762        exit(EXIT_SUCCESS);
5763}
Note: See TracBrowser for help on using the repository browser.