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

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

#942 Fix immediate procedures

New versions of ogAdmServer handle pending commands in a different way.
Instant procedures uses the old way, now unsupported, so we need to
adapt instant procedures.

This commit adapts instant procedures to work with the new pending
commands implementation.

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