source: ogServer-Git/sources/ogAdmServer.c @ 9a85c7a

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

#942 Fix task break down

OpenGnsys tasks can contain other tasks. To know if a element of the
task is another task, we need to check if it has the parameter tareaid
(Task ID). The code had a bug and the check was done on an non-existent
parameter

This commit fix this bug changing the non-existent parameter for
tareaid.

Signed-off-by: OpenGnSys Support Team <soporte-og@…>

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