From bb6a73ed368fe4b00eec53070acb089e9d2afc99 Mon Sep 17 00:00:00 2001 From: lgromero Date: Tue, 14 May 2024 01:30:10 +0200 Subject: [PATCH] refs 310 273 adds ogadmclient compiltation and ipxe script generation --- installer/ogboot_installer.sh | 94 +- sources/clients/README.es.txt | 9 + sources/clients/ogAdmClient/Makefile | 31 + sources/clients/ogAdmClient/ogAdmClient.cfg | 5 + .../clients/ogAdmClient/sources/ogAdmClient.c | 2331 +++++++++++++++++ .../clients/ogAdmClient/sources/ogAdmClient.h | 183 ++ .../clients/ogAdmClient/sources/ogAdmClient.o | Bin 0 -> 108604 bytes 7 files changed, 2617 insertions(+), 36 deletions(-) create mode 100644 sources/clients/README.es.txt create mode 100644 sources/clients/ogAdmClient/Makefile create mode 100644 sources/clients/ogAdmClient/ogAdmClient.cfg create mode 100644 sources/clients/ogAdmClient/sources/ogAdmClient.c create mode 100644 sources/clients/ogAdmClient/sources/ogAdmClient.h create mode 100644 sources/clients/ogAdmClient/sources/ogAdmClient.o diff --git a/installer/ogboot_installer.sh b/installer/ogboot_installer.sh index 94fdd6c..86a3924 100755 --- a/installer/ogboot_installer.sh +++ b/installer/ogboot_installer.sh @@ -436,28 +436,10 @@ function servicesCompilation () { local hayErrores=0 - # Compilar OpenGnsys Server - echoAndLog "${FUNCNAME}(): Compiling OpenGnsys Admin Server" - pushd $WORKDIR/ogboot/admin/Sources/Services/ogAdmServer - make && mv ogAdmServer $INSTALL_TARGET/sbin - if [ $? -ne 0 ]; then - echoAndLog "${FUNCNAME}(): error while compiling OpenGnsys Admin Server" - hayErrores=1 - fi - popd - # Compilar OpenGnsys Agent - echoAndLog "${FUNCNAME}(): Compiling OpenGnsys Agent" - pushd $WORKDIR/ogboot/admin/Sources/Services/ogAdmAgent - make && mv ogAdmAgent $INSTALL_TARGET/sbin - if [ $? -ne 0 ]; then - echoAndLog "${FUNCNAME}(): error while compiling OpenGnsys Agent" - hayErrores=1 - fi - popd # Compilar OpenGnsys Client echoAndLog "${FUNCNAME}(): Compiling OpenGnsys Admin Client" - pushd $WORKDIR/ogboot/admin/Sources/Clients/ogAdmClient - make && mv ogAdmClient ../../../../client/shared/bin + pushd $WORKDIR/ogboot/sources/clients/ogAdmClient + make && mv ogAdmClient ../../client/shared/bin if [ $? -ne 0 ]; then echoAndLog "${FUNCNAME}(): error while compiling OpenGnsys Admin Client" hayErrores=1 @@ -475,7 +457,7 @@ function copyClientFiles() local errstatus=0 echoAndLog "${FUNCNAME}(): Copying OpenGnsys Client files." - cp -a $WORKDIR/opengnsys/client/shared/* $INSTALL_TARGET/client + cp -a $WORKDIR/ogboot/client/shared/* $INSTALL_TARGET/client if [ $? -ne 0 ]; then errorAndLog "${FUNCNAME}(): error while copying client estructure" errstatus=1 @@ -483,7 +465,7 @@ function copyClientFiles() echoAndLog "${FUNCNAME}(): Copying OpenGnsys Cloning Engine files." mkdir -p $INSTALL_TARGET/client/lib/engine/bin - cp -a $WORKDIR/opengnsys/client/engine/*.lib* $INSTALL_TARGET/client/lib/engine/bin + cp -a $WORKDIR/ogboot/client/engine/*.lib* $INSTALL_TARGET/client/lib/engine/bin if [ $? -ne 0 ]; then errorAndLog "${FUNCNAME}(): error while copying engine files" errstatus=1 @@ -503,7 +485,7 @@ generate_ipxe_script() { echo "Generando script IPXE..." ip_address_server=$(ifconfig eth0 | awk '/inet / {print $2}') - template="etc/dhcp_boot.ipxe.tmpl" + template="$WORKDIR/ogboot/etc/dhcp_boot.ipxe.tmpl" ipxe_output="/opt/opengnsys/tftpboot/ipxe_scripts/dhcp_boot.ipxe" @@ -518,19 +500,6 @@ generate_ipxe_script() { sed "s/SERVERIP/$ip_address_server/g" "$template_default" > "$default_output" echo "Creando ficheros MAC script" - for client_declaration in "${CLIENTS[@]}"; do - # Evaluar la cadena para reconstruir el array asociativo del cliente - eval "$client_declaration" - - hostname="${CLIENT[hostname]}" - mac_address="${CLIENT[mac_address]}" - ip_address="${CLIENT[ip_address]}" - mac_address_lower=$(echo "$mac_address" | tr '[:upper:]' '[:lower:]') - filename="01-${mac_address_lower}" - sed "s/SERVERIP/$ip_address_server/g; s/IP_ADDRESS/$ip_address/g; s/HOSTNAME/$hostname/g; s/MAC_ADDRESS/$mac_address/g" $mac_script_template > "/opt/opengnsys/tftpboot/ipxe_scripts/$filename" - echo "Archivo $filename creado con los parámetros modificados." - done - echo "Archivos creados correctamente." @@ -568,6 +537,46 @@ function testPxe () rm -f $TFTPCFGDIR/testpxe /tmp/testpxe } +mount_NFS() { + if sudo mount -t nfs ognartefactos.evlt.uma.es:/ /mnt; then + echo "Sistema NFS montado correctamente." + else + echo "Error: No se pudo montar el sistema NFS." + exit 1 + fi + + ls /mnt/ + + sudo cp -r /mnt/srv/artefactos/ipxe/ /tmp + + cd /tmp/ipxe/src + if sudo make -j 4; then + echo "Directorio /tmp/ipxe/src montado correctamente." + else + echo "Error: No se pudo montar el directorio /tmp/ipxe/src." + exit 1 + fi + + if sudo make bin/undionly.kpxe EMBED=/opt/opengnsys/tftpboot/ipxe_scripts/dhcp_boot.ipxe; then + echo "Fichero de arranque montado correctamente." + else + echo "Error: No se pudo montar el fichero de arranque." + exit 1 + fi + + sudo cp bin/undionly.kpxe /opt/opengnsys/tftpboot + + if sudo make bin-x86_64-efi/ipxe.efi EMBED=/opt/opengnsys/tftpboot/ipxe_scripts/dhcp_boot.ipxe; then + echo "Fichero EFI construido correctamente." + else + echo "Error: No se pudo construir el fichero EFI." + exit 1 + fi + + sudo cp bin-x86_64-efi/ipxe.efi /opt/opengnsys/tftpboot + +} + ######################################################################## ## Configuración servicio Samba ######################################################################## @@ -898,6 +907,19 @@ fi # Configuración de TFTP. tftpConfigure +generate_ipxe_script +if [ $? -ne 0 ]; then + echo "Error en la generación de scripts IPXE" + exit 1 +fi + + +mount_NFS +if [ $? -ne 0 ]; then + echo "Error en el montaje NFS" + exit 1 +fi + # Configuración de Samba. smbConfigure if [ $? -ne 0 ]; then diff --git a/sources/clients/README.es.txt b/sources/clients/README.es.txt new file mode 100644 index 0000000..56900d8 --- /dev/null +++ b/sources/clients/README.es.txt @@ -0,0 +1,9 @@ +OpenGnsys Services for Clients README +======================================= + + +Este directorio contiene el código fuente de los servicios OpenGnsys específicos para clientes. + +- ogAdmClient servicio para cliente ogLive que atiende peticiones de OpenGnsys Server +- ogagent OGAgent: agente modular para sistemas operativos con API REST + diff --git a/sources/clients/ogAdmClient/Makefile b/sources/clients/ogAdmClient/Makefile new file mode 100644 index 0000000..d3628c9 --- /dev/null +++ b/sources/clients/ogAdmClient/Makefile @@ -0,0 +1,31 @@ +# makefile + +# Nombre del proyecto +PROYECTO := ogAdmClient + +# Directorios y librerias +DIRS := +LIBS := -static + +# Opciones de compilacion +OPCS := -m32 -O0 -g -Wall # Depuracion +#OPCS := -m32 -O3 -Wall # Optimizacion + +# Ficheros objetos +OBJS := sources/ogAdmClient.o + +all: $(PROYECTO) + +$(PROYECTO): $(OBJS) + gcc $(OPCS) $(DIRS) $(LIBS) $(OBJS) -o $(PROYECTO) +# strip $(PROYECTO) # Optimizacion + +clean: + rm -f $(PROYECTO) $(OBJS) + +sources/%.o: sources/%.c + gcc $(OPCS) -I ../../Includes -c -o"$@" "$<" + + + + diff --git a/sources/clients/ogAdmClient/ogAdmClient.cfg b/sources/clients/ogAdmClient/ogAdmClient.cfg new file mode 100644 index 0000000..b15e740 --- /dev/null +++ b/sources/clients/ogAdmClient/ogAdmClient.cfg @@ -0,0 +1,5 @@ +ServidorAdm=SERVERIP +PUERTO=2008 +PATHINTERFACE=/opt/opengnsys/interfaceAdm +UrlMenu=OPENGNSYSURL/varios/menubrowser.php +UrlMsg=http://localhost/cgi-bin/httpd-log.sh \ No newline at end of file diff --git a/sources/clients/ogAdmClient/sources/ogAdmClient.c b/sources/clients/ogAdmClient/sources/ogAdmClient.c new file mode 100644 index 0000000..6f87cc4 --- /dev/null +++ b/sources/clients/ogAdmClient/sources/ogAdmClient.c @@ -0,0 +1,2331 @@ +// ******************************************************************************************************** +// Cliernte: ogAdmClient +// Autor: José Manuel Alonso (E.T.S.I.I.) Universidad de Sevilla +// Fecha Creación: Marzo-2010 +// Fecha Última modificación: Abril-2010 +// Nombre del fichero: ogAdmClient.c +// Descripción :Este fichero implementa el cliente general del sistema +// ******************************************************************************************************** + +#include "ogAdmClient.h" +#include "ogAdmLib.c" +//________________________________________________________________________________________________________ +// Función: tomaConfiguracion +// +// Descripción: +// Lee el fichero de configuración del servicio +// Parámetros: +// filecfg : Ruta completa al fichero de configuración +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//________________________________________________________________________________________________________ +BOOLEAN tomaConfiguracion(char* filecfg) +{ + char modulo[] = "tomaConfiguracion()"; + + if (filecfg == NULL || strlen(filecfg) == 0) { + errorLog(modulo, 1, FALSE); // Fichero de configuración del cliente vacío + return (FALSE); + } + FILE *fcfg; + int lSize; + char * buffer, *lineas[MAXPRM], *dualparametro[2]; + int i, numlin, resul; + + fcfg = fopen(filecfg, "rt"); + if (fcfg == NULL) { + errorLog(modulo, 2, FALSE); // No existe fichero de configuración del cliente + return (FALSE); + } + + fseek(fcfg, 0, SEEK_END); + lSize = ftell(fcfg); // Obtiene tamaño del fichero. + rewind(fcfg); + buffer = (char*) reservaMemoria(lSize+1); // Toma memoria para el buffer de lectura. + if (buffer == NULL) { // No hay memoria suficiente para el buffer + errorLog(modulo, 3, FALSE); + return (FALSE); + } + lSize=fread(buffer, 1, lSize, fcfg); // Lee contenido del fichero + buffer[lSize]=CHARNULL; + fclose(fcfg); + + /* Inicializar variables globales */ + servidoradm[0]=CHARNULL; + puerto[0] = CHARNULL; + pathinterface[0]=CHARNULL; + urlmenu[0]=CHARNULL; + urlmsg[0]=CHARNULL; + + numlin = splitCadena(lineas, buffer, '\n'); + for (i = 0; i < numlin; i++) { + splitCadena(dualparametro, lineas[i], '='); + + resul = strcmp(StrToUpper(dualparametro[0]), "SERVIDORADM"); + if (resul == 0) + strcpy(servidoradm, dualparametro[1]); + + resul = strcmp(StrToUpper(dualparametro[0]), "PUERTO"); + if (resul == 0) + strcpy(puerto, dualparametro[1]); + + resul = strcmp(StrToUpper(dualparametro[0]), "PATHINTERFACE"); + if (resul == 0) + strcpy(pathinterface, dualparametro[1]); + + resul = strcmp(StrToUpper(dualparametro[0]), "URLMENU"); + if (resul == 0) + strcpy(urlmenu, dualparametro[1]); + + resul = strcmp(StrToUpper(dualparametro[0]), "URLMSG"); + if (resul == 0) + strcpy(urlmsg, dualparametro[1]); + } + + if (servidoradm[0] == CHARNULL) { + liberaMemoria(buffer); + errorLog(modulo,4, FALSE); // Falta parámetro SERVIDORADM + return (FALSE); + } + + if (puerto[0] == CHARNULL) { + liberaMemoria(buffer); + errorLog(modulo,5, FALSE); // Falta parámetro PUERTO + return (FALSE); + } + if (pathinterface[0] == CHARNULL) { + liberaMemoria(buffer); + errorLog(modulo,56, FALSE); // Falta parámetro PATHINTERFACE + return (FALSE); + } + + if (urlmenu[0] == CHARNULL) { + liberaMemoria(buffer); + errorLog(modulo,89, FALSE); // Falta parámetro URLMENU + return (FALSE); + } + if (urlmsg[0] == CHARNULL) { + liberaMemoria(buffer); + errorLog(modulo,90, FALSE); // Falta parámetro URLMSG + return (FALSE); + } + liberaMemoria(buffer); + return (TRUE); +} +//______________________________________________________________________________________________________ +// Función: FinterfaceAdmin +// +// Descripción: +// Esta función es la puerta de comunicación entre el módulo de administración y el motor de clonación. +// La Aplicación de administración utiliza una interface para ejecutar funciones del motor de clonación; +// esta interface llamará a la API del motor con lo que cambiando el comportamiento de esta interface +// podremos hacer llamadas a otras API de clonación y de esta manera probar distintos motores. +// +// Parámetros: +// - script: Nombre del módulo,función o script de la interface +// - parametros: Parámetros que se le pasarán a la interface +// - salida: Recoge la salida que genera la llamada a la interface + +// Devuelve: +// Código de error de la ejecución al módulo , función o script de la interface +// +// Especificaciones: +// El parámetro salida recoge la salida desde un fichero que se genera en la ejecución del script siempre que +// sea distinto de NULL, esto es, si al llamar a la función este parámetro es NULL no se recogerá dicha salida. +// Este fichero tiene una ubicación fija: /tmp/_retinterface +//______________________________________________________________________________________________________ + +int FinterfaceAdmin( char *script,char* parametros,char* salida) +{ + FILE *f; + int lSize,nargs,i,resul; + char msglog[LONSTD],*argumentos[MAXARGS]; + char modulo[] = "FinterfaceAdmin()"; + + + if (ndebug>= DEBUG_MEDIO) { + sprintf(msglog, "%s:%s", tbMensajes[8], script); + infoDebug(msglog); + } + + /* Crea matriz de los argumentos */ + nargs=splitCadena(argumentos,parametros,32); + for(i=nargs;i= DEBUG_ALTO) { + sprintf(msglog, "%s: #%d-%s", tbMensajes[9],i+1,argumentos[i]); + infoDebug(msglog); + } + } + /* Elimina fichero de retorno */ + if(salida!=(char*)NULL){ + f = fopen("/tmp/_retinterface_","w" ); + if (f==NULL){ // Error de eliminación + scriptLog(modulo,10); + resul=8; + scriptLog(modulo,resul); + return(resul); + } + fclose(f); + } + /* Compone linea de comando */ + if(parametros){ + strcat(script," "); + strcat(script,parametros); + } + /* LLamada función interface */ + resul=system(script); + if(resul){ + scriptLog(modulo,10); + scriptLog(modulo,resul); + return(resul); + } + /* Lee fichero de retorno */ + if(salida!=(char*)NULL){ + f = fopen("/tmp/_retinterface_","rb" ); + if (f==NULL){ // Error de apertura + scriptLog(modulo,10); + resul=9; + scriptLog(modulo,resul); + return(resul); + } + else{ + fseek (f ,0,SEEK_END); // Obtiene tamaño del fichero. + lSize = ftell (f); + rewind (f); + if(lSize>LONGITUD_SCRIPTSALIDA){ + scriptLog(modulo,10); + resul=11; + scriptLog(modulo,resul); + return(resul); + } + fread (salida,1,lSize,f); // Lee contenido del fichero + rTrim(salida); + fclose(f); + } + } + /* Muestra información de retorno */ + if(salida!=(char*)NULL){ + if(ndebug>2){ + sprintf(msglog,"Información devuelta %s",salida); + infoDebug(msglog); + } + } + return(resul); +} +//______________________________________________________________________________________________________ +// Función: interfaceAdmin +// +// Descripción: +// Esta función es la puerta de comunicación entre el módulo de administración y el motor de clonación. +// La Aplicación de administración utiliza una interface para ejecutar funciones del motor de clonación; +// esta interface llamará a la API del motor con lo que cambiando el comportamiento de esta interface +// podremos hacer llamadas a otras API de clonación y de esta manera probar distintos motores. +// +// Parámetros: +// - script: Nombre del módulo,función o script de la interface +// - parametros: Parámetros que se le pasarán a la interface +// - salida: Recoge la salida que genera la llamada a la interface + +// Devuelve: +// Código de error de la ejecución al módulo , función o script de la interface +// +// Especificaciones: +// El parámetro salida recoge la salida desde el procedimiento hijo que se genera en la ejecución de éste +// siempre que sea distinto de NULL, esto es, si al llamar a la función este parámetro es NULL no se +// recogerá dicha salida. +//______________________________________________________________________________________________________ + +int interfaceAdmin( char *script,char* parametros,char* salida) +{ + int descr[2]; /* Descriptores de E y S de la turbería */ + int bytesleidos; /* Bytes leidos en el mensaje */ + int estado; + pid_t pid; + char buffer[LONBLK]; // Buffer de lectura de fichero + pipe (descr); + int i,nargs,resul; + int lon; // Longitud de cadena + char msglog[LONSUC]; // Mensaje de registro de sucesos + char *argumentos[MAXARGS]; + char modulo[] = "interfaceAdmin()"; + if (ndebug>= DEBUG_MEDIO) { + sprintf(msglog, "%s:%s", tbMensajes[8], script); + infoDebug(msglog); + } + + /* Crea matriz de los argumentos */ + nargs=splitCadena(argumentos,parametros,32); + for(i=nargs;i= DEBUG_ALTO) { + // Truncar la cadena si es mayor que el tamaño de la línea de log. + sprintf(msglog, "%s: #%d-", tbMensajes[9], i+1); + lon = strlen (msglog); + if (lon + strlen (argumentos[i]) < LONSUC) { + strcat (msglog, argumentos[i]); + } + else + { + strncat (msglog, argumentos[i], LONSUC - lon - 4); + strcat (msglog, "..."); + } + infoDebug(msglog); + } + } + + if((pid=fork())==0) + { + //_______________________________________________________________ + + /* Proceso hijo que ejecuta la función de interface */ + + close (descr[LEER]); + dup2 (descr[ESCRIBIR], 1); + close (descr[ESCRIBIR]); + resul=execv(script,argumentos); + //resul=execlp (script, script, argumentos[0],argumentos[1],NULL); + exit(resul); + + /* Fin de proceso hijo */ + //_______________________________________________________________ + } + else + { + //_______________________________________________________________ + + /* Proceso padre que espera la ejecución del hijo */ + + if (pid ==-1){ // Error en la creación del proceso hijo + scriptLog(modulo,10); + resul=13; + scriptLog(modulo,resul); + return(resul); + } + close (descr[ESCRIBIR]); + bytesleidos = read (descr[LEER], buffer, LONBLK-1); + while(bytesleidos>0){ + if(salida!=(char*)NULL){ // Si se solicita retorno de información... + buffer[bytesleidos]='\0'; + // Error si se supera el tamaño máximo de cadena de salida. + if(strlen(buffer)+strlen(salida)>LONGITUD_SCRIPTSALIDA){ + scriptLog(modulo,10); + resul=11; + scriptLog(modulo,resul); + return(resul); + } + rTrim(buffer); + strcat(salida,buffer); + } + bytesleidos = read (descr[LEER], buffer, LONBLK-1); + } + close (descr[LEER]); + //kill(pid,SIGQUIT); + waitpid(pid,&estado,0); + resul=WEXITSTATUS(estado); + if(resul){ + scriptLog(modulo,10); + scriptLog(modulo,resul); + return(resul); + } + /* Fin de proceso padre */ + //_______________________________________________________________ + } + + /* Muestra información de retorno */ + if(salida!=(char*)NULL){ + if(ndebug>2){ + // Truncar la cadena si es mayor que el tamaño de la línea de log. + strcpy(msglog,"Informacion devuelta "); + lon = strlen (msglog); + if (lon + strlen (salida) < LONSUC) { + strcat (msglog, salida); + } + else + { + strncat (msglog, salida, LONSUC-lon-4); + strcat (msglog, "..."); + } + infoDebug(msglog); + } + } + return(resul); +} +//______________________________________________________________________________________________________ +// Función: scriptLog +// +// Descripción: +// Registra los sucesos de errores de scripts en el fichero de log +// Parametros: +// - modulo: Módulo donde se produjo el error +// - coderr : Código del mensaje de error del script +//______________________________________________________________________________________________________ +void scriptLog(const char *modulo,int coderr) +{ + char msglog[LONSUC]; + + if(coderr>>>>>>>>>>>>>>>>>>>>>>>>> + char msglog[LONSTD]; + char modulo[] = "cuestionCache()"; + + sprintf(interface,"%s/%s",pathinterface,"procesaCache"); + sprintf(parametros,"%s %s","procesaCache",tam); + + herror=interfaceAdmin(interface,parametros,NULL); + if(herror){ + sprintf(msglog,"%s",tbErrores[88]); + errorInfo(modulo,msglog); + return(FALSE); + } + + return(TRUE); +} +//______________________________________________________________________________________________________ +// Función: cargaPaginaWeb +// +// Descripción: +// Muestra una pégina web usando el browser +// Parámetros: +// urp: Dirección url de la página +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +int cargaPaginaWeb(char *url) +{ + pid_t pidbrowser; // Identificador del proceso que se crea para mostrar una página web con el browser + int resul=0; + char* argumentos[4]; + char modulo[] = "cargaPaginaWeb()"; + + // Destruye los procesos del Browser y lanza uno nuevo. + system("pkill -9 browser"); + + sprintf(interface,"/opt/opengnsys/bin/browser"); + sprintf(parametros,"browser -qws %s",url); + + splitCadena(argumentos,parametros,' '); // Crea matriz de los argumentos del scripts + argumentos[3]=NULL; + if((pidbrowser=fork())==0){ + /* Proceso hijo que ejecuta el script */ + resul=execv(interface,argumentos); + exit(resul); + } + else { + if (pidbrowser ==-1){ + scriptLog(modulo,10); + resul=13; + scriptLog(modulo,resul); + return(resul); + } + } + return(resul); +} +//________________________________________________________________________________________________________ +// Función: muestraMenu +// +// Descripción: +// Muestra el menu inicial del cliente +// Parámetros: +// Ninguno +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//________________________________________________________________________________________________________ +void muestraMenu() +{ + cargaPaginaWeb(urlmenu); +} +//______________________________________________________________________________________________________ +// Función: muestraMensaje +// +// Descripción: +// Muestra un mensaje en pantalla +// Parámetros: +// - idx: Indice del mensaje +// - msg: Descripción Mensaje +// ________________________________________________________________________________________________________ +void muestraMensaje(int idx,char*msg) +{ + char *msgpan,url[250]; + + if(msg){ + msgpan=URLEncode(msg); + sprintf(url,"%s?msg=%s",urlmsg,msgpan); // Url de la página de mensajes + liberaMemoria(msgpan); + } + else + sprintf(url,"%s?idx=%d",urlmsg,idx); // Url de la página de mensajes + cargaPaginaWeb(url); +} +//______________________________________________________________________________________________________ +// Función: InclusionCliente +// Descripción: +// Abre una sesión en el servidor de administración y registra al cliente en el sistema +// Parámetros: +// Ninguno +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//______________________________________________________________________________________________________ +BOOLEAN inclusionCliente(TRAMA* ptrTrama) +{ + int lon; // Longitud de cadena + char msglog[LONSUC]; // Mensaje de registro de sucesos + char *cfg; // Datos de configuración + SOCKET socket_c; + char modulo[] = "inclusionCliente()"; + + cfg=LeeConfiguracion(); + + if(!cfg){ // No se puede recuperar la configuración del cliente + errorLog(modulo,36,FALSE); + errorLog(modulo,37,FALSE); + return(FALSE); + } + if (ndebug>= DEBUG_ALTO) { + // Truncar la cadena si es mayor que el tamaño de la línea de log. + sprintf(msglog, "%s", tbMensajes[14]); + lon = strlen (msglog); + if (lon + strlen (cfg) < LONSUC) { + strcat (msglog, cfg); + } + else + { + strncat (msglog, cfg, LONSUC - lon - 4); + strcat (msglog, "..."); + } + infoDebug(msglog); + } + initParametros(ptrTrama,0); + lon=sprintf(ptrTrama->parametros,"nfn=InclusionCliente\r"); // Nombre de la función a ejecutar en el servidor + lon+=sprintf(ptrTrama->parametros+lon,"cfg=%s\r",cfg); // Configuración de los Sistemas Operativos del cliente + liberaMemoria(cfg); + + if(!enviaMensajeServidor(&socket_c,ptrTrama,MSG_PETICION)){ + errorLog(modulo,37,FALSE); + return(FALSE); + } + ptrTrama=recibeMensaje(&socket_c); + if(!ptrTrama){ + errorLog(modulo,45,FALSE); + return(FALSE); + } + + close(socket_c); + + if(!gestionaTrama(ptrTrama)){ // Análisis de la trama + errorLog(modulo,39,FALSE); + return(FALSE); + } + + return(TRUE); +} +//______________________________________________________________________________________________________ +// Función: RESPUESTA_InclusionCliente +// +// Descripción: +// Respuesta del servidor de administración a la petición de inicio +// enviando los datos identificativos del cliente y otras configuraciones +// Parámetros: +// - ptrTrama: Trama recibida por el servidor con el contenido y los parámetros +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//______________________________________________________________________________________________________ +BOOLEAN RESPUESTA_InclusionCliente(TRAMA* ptrTrama) +{ + char* res; + char modulo[] = "RESPUESTA_InclusionCliente()"; + + res=copiaParametro("res",ptrTrama); // Resultado del proceso de inclusión + if(atoi(res)==0){ // Error en el proceso de inclusión + liberaMemoria(res); + errorLog(modulo,41,FALSE); + return (FALSE); + } + liberaMemoria(res); + + idordenador=copiaParametro("ido",ptrTrama); // Identificador del ordenador + nombreordenador=copiaParametro("npc",ptrTrama); // Nombre del ordenador + cache=copiaParametro("che",ptrTrama); // Tamaño de la caché reservada al cliente + idproautoexec=copiaParametro("exe",ptrTrama); // Procedimento de inicio (Autoexec) + idcentro=copiaParametro("idc",ptrTrama); // Identificador de la Unidad Organizativa + idaula=copiaParametro("ida",ptrTrama); // Identificador del aula + + if(idordenador==NULL || nombreordenador==NULL){ + errorLog(modulo,40,FALSE); + return (FALSE); + } + return(TRUE); +} +//______________________________________________________________________________________________________ +// +// Función: LeeConfiguracion +// Descripción: +// Abre una sesión en el servidor de administración y registra al cliente en el sistema +// Parámetros: +// Ninguno +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//______________________________________________________________________________________________________ + +char* LeeConfiguracion() +{ + char* parametroscfg; + char modulo[] = "LeeConfiguracion()"; + int herrorcfg; + + // Reservar memoria para los datos de cofiguración. + parametroscfg=(char*)reservaMemoria(LONGITUD_SCRIPTSALIDA); + if(!parametroscfg){ + errorLog(modulo,3,FALSE); + return(NULL); + } + // Ejecutar script y obtener datos. + sprintf(interface,"%s/%s",pathinterface,"getConfiguration"); + herrorcfg=interfaceAdmin(interface,NULL,parametroscfg); + + if(herrorcfg){ // No se puede recuperar la configuración del cliente + liberaMemoria(parametroscfg); + errorLog(modulo,36,FALSE); + return(NULL); + } + return(parametroscfg); +} +//________________________________________________________________________________________________________ +// Función: autoexecCliente +// +// Descripción: +// Solicita procedimiento de autoexec para el cliebnte +// Parámetros: +// Ninguno +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//________________________________________________________________________________________________________ +BOOLEAN autoexecCliente(TRAMA* ptrTrama) +{ + SOCKET socket_c; + char modulo[] = "autoexecCliente()"; + + initParametros(ptrTrama,0); + sprintf(ptrTrama->parametros,"nfn=AutoexecCliente\rexe=%s\r",idproautoexec); + + if(!enviaMensajeServidor(&socket_c,ptrTrama,MSG_PETICION)){ + errorLog(modulo,42,FALSE); + return(FALSE); + } + ptrTrama=recibeMensaje(&socket_c); + if(!ptrTrama){ + errorLog(modulo,45,FALSE); + return(FALSE); + } + + close(socket_c); + + if(!gestionaTrama(ptrTrama)){ // Análisis de la trama + errorLog(modulo,39,FALSE); + return(FALSE); + } + + return(TRUE); +} +//________________________________________________________________________________________________________ +// Función: autoexecCliente +// +// Descripción: +// Ejecuta un script de autoexec personalizado en todos los inicios para el cliente +// Parámetros: +// Ninguno +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//________________________________________________________________________________________________________ +BOOLEAN RESPUESTA_AutoexecCliente(TRAMA* ptrTrama) +{ + SOCKET socket_c; + char *res,*nfl; + char modulo[] = "RESPUESTA_AutoexecCliente()"; + + res=copiaParametro("res",ptrTrama); + if(atoi(res)==0){ // Error en el proceso de autoexec + liberaMemoria(res); + return (FALSE); + } + liberaMemoria(res); + + nfl=copiaParametro("nfl",ptrTrama); + initParametros(ptrTrama,0); + sprintf(ptrTrama->parametros,"nfn=enviaArchivo\rnfl=%s\r",nfl); + liberaMemoria(nfl); + + /* Envía petición */ + if(!enviaMensajeServidor(&socket_c,ptrTrama,MSG_PETICION)){ + errorLog(modulo,42,FALSE); + return(FALSE); + } + /* Nombre del archivo destino (local)*/ + char fileautoexec[LONPRM]; + sprintf(fileautoexec,"/tmp/_autoexec_%s",IPlocal); + + /* Recibe archivo */ + if(!recArchivo(&socket_c,fileautoexec)){ + errorLog(modulo,58, FALSE); + close(socket_c); + return(FALSE); + } + + close(socket_c); + + /* Ejecuta archivo */ + ejecutaArchivo(fileautoexec,ptrTrama); + return(TRUE); +} +//______________________________________________________________________________________________________ +// Función: comandosPendientes +// +// Descripción: +// Búsqueda de acciones pendientes en el servidor de administración +// Parámetros: +// Ninguno +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//______________________________________________________________________________________________________ +BOOLEAN comandosPendientes(TRAMA* ptrTrama) +{ + SOCKET socket_c; + char modulo[] = "comandosPendientes()"; + + CMDPTES=TRUE; + initParametros(ptrTrama,0); + + while(CMDPTES){ + sprintf(ptrTrama->parametros,"nfn=ComandosPendientes\r"); + if(!enviaMensajeServidor(&socket_c,ptrTrama,MSG_PETICION)){ + errorLog(modulo,42,FALSE); + return(FALSE); + } + ptrTrama=recibeMensaje(&socket_c); + if(!ptrTrama){ + errorLog(modulo,45,FALSE); + return(FALSE); + } + + close(socket_c); + + if(!gestionaTrama(ptrTrama)){ // Análisis de la trama + errorLog(modulo,39,FALSE); + return(FALSE); + } + } + return(TRUE); +} +//______________________________________________________________________________________________________ +// Función: NoComandosPtes +// +// Descripción: +// Conmuta el switch de los comandos pendientes y lo pone a false +// Parámetros: +// - ptrTrama: contenido del mensaje +// Devuelve: +// TRUE siempre +// Especificaciones: +// Cuando se ejecuta esta función se sale del bucle que recupera los comandos pendientes en el +// servidor y el cliente pasa a a estar disponible para recibir comandos desde el éste. +//______________________________________________________________________________________________________ +BOOLEAN NoComandosPtes(TRAMA* ptrTrama) +{ + CMDPTES=FALSE; // Corta el bucle de comandos pendientes + return(TRUE); +} +//______________________________________________________________________________________________________ +// Función: ProcesaComandos +// +// Descripción: +// Espera comando desde el Servidor de Administración para ejecutarlos +// Parámetros: +// Ninguno +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +void procesaComandos(TRAMA* ptrTrama) +{ + int lon; + SOCKET socket_c; + char modulo[] = "procesaComandos()"; + + initParametros(ptrTrama,0); + while(TRUE){ + lon=sprintf(ptrTrama->parametros,"nfn=DisponibilidadComandos\r"); + lon+=sprintf(ptrTrama->parametros+lon,"tpc=%s\r",CLIENTE_OPENGNSYS); // Activar disponibilidad + if(!enviaMensajeServidor(&socket_c,ptrTrama,MSG_INFORMACION)){ + errorLog(modulo,43,FALSE); + return; + } + infoLog(19); // Disponibilidad de cliente activada + ptrTrama=recibeMensaje(&socket_c); + if(!ptrTrama){ + errorLog(modulo,46,FALSE); + return; + } + + close(socket_c); + + if(!gestionaTrama(ptrTrama)){ // Análisis de la trama + errorLog(modulo,39,FALSE); + return; + } + if(!comandosPendientes(ptrTrama)){ + errorLog(modulo,42,FALSE); + } + } +} +//______________________________________________________________________________________________________ +// Función: Actualizar +// +// Descripción: +// Actualiza los datos de un ordenador como si volviera a solicitar la entrada +// en el sistema al servidor de administración +// Parámetros: +// ptrTrama: contenido del mensajede +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//______________________________________________________________________________________________________ +BOOLEAN Actualizar(TRAMA* ptrTrama) +{ + char msglog[LONSTD]; // Mensaje de log + char *cfg; // Cadena de datos de configuración + int lon; // Longitud de cadena + char modulo[] = "Actualizar()"; + + if (ndebug>=DEBUG_MAXIMO) { + sprintf(msglog, "%s:%s",tbMensajes[21],modulo); + infoDebug(msglog); + } + muestraMensaje(1,NULL); + if(!comandosPendientes(ptrTrama)){ + errorLog(modulo,84,FALSE); + return(FALSE); + } + + cfg=LeeConfiguracion(); + herror=0; + if(!cfg){ // No se puede recuperar la configuración del cliente + errorLog(modulo,36,FALSE); + herror=3; + } + // Envia Configuracion al servidor + initParametros(ptrTrama,0); + lon=sprintf(ptrTrama->parametros,"nfn=%s\r","RESPUESTA_Configurar"); + lon+=sprintf(ptrTrama->parametros+lon,"cfg=%s\r",cfg); // Configuración de los Sistemas Operativos del cliente + respuestaEjecucionComando(ptrTrama,herror,0); + + muestraMenu(); + + return(TRUE); +} +//______________________________________________________________________________________________________ +// Función: Purgar +// +// Descripción: +// Detiene la ejecución del browser +// Parámetros: +// ptrTrama: contenido del mensajede +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//______________________________________________________________________________________________________ +int Purgar(TRAMA* ptrTrama) +{ + + exit(EXIT_SUCCESS); +} +//______________________________________________________________________________________________________ +// Función: Sondeo +// +// Descripción: +// Envía al servidor una confirmación de que está dentro del sistema +// Parámetros: +// ptrTrama: contenido del mensajede +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//______________________________________________________________________________________________________ +BOOLEAN Sondeo(TRAMA* ptrTrama) +{ + return(TRUE); +} +//______________________________________________________________________________________________________ +// Función: ConsolaRemota +// +// Descripción: +// Ejecuta un comando de la Shell y envia el eco al servidor (Consola remota) +// Parámetros: +// ptrTrama: contenido del mensaje +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//______________________________________________________________________________________________________ +BOOLEAN ConsolaRemota(TRAMA* ptrTrama) +{ + SOCKET socket_c; + char *nfn,*scp,*aux,ecosrc[LONPRM],ecodst[LONPRM],msglog[LONSTD];; + char modulo[] = "ConsolaRemota()"; + + /* Nombre del archivo de script */ + char filescript[LONPRM]; + sprintf(filescript,"/tmp/_script_%s",IPlocal); + + aux=copiaParametro("scp",ptrTrama); + scp=URLDecode(aux); + escribeArchivo(filescript,scp); + liberaMemoria(aux); + liberaMemoria(scp); + + nfn=copiaParametro("nfn",ptrTrama); + sprintf(interface,"%s/%s",pathinterface,nfn); + sprintf(ecosrc,"/tmp/_econsola_%s",IPlocal); + sprintf(parametros,"%s %s %s",nfn,filescript,ecosrc); + herror=interfaceAdmin(interface,parametros,NULL); + if(herror){ + sprintf(msglog,"%s:%s",tbErrores[86],nfn); + errorInfo(modulo,msglog); + } + else{ + /* Envía fichero de inventario al servidor */ + sprintf(ecodst,"/tmp/_Seconsola_%s",IPlocal); // Nombre que tendra el archivo en el Servidor + initParametros(ptrTrama,0); + sprintf(ptrTrama->parametros,"nfn=recibeArchivo\rnfl=%s\r",ecodst); + if(!enviaMensajeServidor(&socket_c,ptrTrama,MSG_COMANDO)){ + errorLog(modulo,42,FALSE); + return(FALSE); + } + /* Espera señal para comenzar el envío */ + liberaMemoria(ptrTrama); + recibeFlag(&socket_c,ptrTrama); + /* Envía archivo */ + if(!sendArchivo(&socket_c,ecosrc)){ + errorLog(modulo,57, FALSE); + herror=12; // Error de envío de fichero por la red + } + close(socket_c); + } + liberaMemoria(nfn); + return(TRUE); +} +//_____________________________________________________________________________________________________ +// Función: Comando +// +// Descripción: +// COmando personalizado enviado desde el servidor +// Parámetros: +// ptrTrama: contenido del mensaje +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//_____________________________________________________________________________________________________ +BOOLEAN Comando(TRAMA* ptrTrama) +{ + char *ids,*nfn,msglog[LONSTD]; + char modulo[] = "Comando()"; + + if (ndebug>=DEBUG_MAXIMO) { + sprintf(msglog, "%s:%s",tbMensajes[21],modulo); + infoDebug(msglog); + } + nfn=copiaParametro("nfn",ptrTrama); + ids=copiaParametro("ids",ptrTrama); + + sprintf(interface,"%s/%s",pathinterface,nfn); + herror=interfaceAdmin(interface,NULL,NULL); + if(herror){ + sprintf(msglog,"%s:%s",tbErrores[86],nfn); + errorInfo(modulo,msglog); + } + /* Envia respuesta de ejecucución del comando */ + initParametros(ptrTrama,0); + sprintf(ptrTrama->parametros,"nfn=RESPUESTA_%s\r",nfn); + respuestaEjecucionComando(ptrTrama,herror,ids); + liberaMemoria(nfn); + liberaMemoria(ids); + return(TRUE); +} +//_____________________________________________________________________________________________________ +// Función: Arrancar +// +// Descripción: +// Responde a un comando de encendido por la red +// Parámetros: +// ptrTrama: contenido del mensaje +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//_____________________________________________________________________________________________________ +BOOLEAN Arrancar(TRAMA* ptrTrama) +{ + int lon; + char *ids,msglog[LONSTD]; + char modulo[] = "Arrancar()"; + + if (ndebug>=DEBUG_MAXIMO) { + sprintf(msglog, "%s:%s",tbMensajes[21],modulo); + infoDebug(msglog); + } + + ids=copiaParametro("ids",ptrTrama); + + /* Envia respuesta de ejecucución del script */ + initParametros(ptrTrama,0); + lon=sprintf(ptrTrama->parametros,"nfn=%s\r","RESPUESTA_Arrancar"); + lon+=sprintf(ptrTrama->parametros+lon,"tpc=%s\r",CLIENTE_OPENGNSYS); + respuestaEjecucionComando(ptrTrama,0,ids); + liberaMemoria(ids); + return(TRUE); +} +//_____________________________________________________________________________________________________ +// Función: Apagar +// +// Descripción: +// Apaga el cliente +// Parámetros: +// ptrTrama: contenido del mensaje +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//_____________________________________________________________________________________________________ +BOOLEAN Apagar(TRAMA* ptrTrama) +{ + char *ids,*nfn,msglog[LONSTD]; + char modulo[] = "Apagar()"; + + if (ndebug>=DEBUG_MAXIMO) { + sprintf(msglog, "%s:%s",tbMensajes[21],modulo); + infoDebug(msglog); + } + nfn=copiaParametro("nfn",ptrTrama); + ids=copiaParametro("ids",ptrTrama); + + initParametros(ptrTrama,0); + sprintf(ptrTrama->parametros,"nfn=%s\r","RESPUESTA_Apagar"); + respuestaEjecucionComando(ptrTrama,0,ids); + + sprintf(interface,"%s/%s",pathinterface,nfn); + herror=interfaceAdmin(interface,NULL,NULL); + if(herror){ + sprintf(msglog,"%s:%s",tbErrores[86],nfn); + liberaMemoria(nfn); + liberaMemoria(ids); + errorInfo(modulo,msglog); + return(FALSE); + } + liberaMemoria(nfn); + liberaMemoria(ids); + return(TRUE); +} +//_____________________________________________________________________________________________________ +// Función: Reiniciar +// +// Descripción: +// Apaga el cliente +// Parámetros: +// ptrTrama: contenido del mensaje +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//_____________________________________________________________________________________________________ +BOOLEAN Reiniciar(TRAMA* ptrTrama) +{ + char *nfn,*ids,msglog[LONSTD]; + char modulo[] = "Reiniciar()"; + + if (ndebug>=DEBUG_MAXIMO) { + sprintf(msglog, "%s:%s",tbMensajes[21],modulo); + infoDebug(msglog); + } + nfn=copiaParametro("nfn",ptrTrama); + ids=copiaParametro("ids",ptrTrama); + + initParametros(ptrTrama,0); + sprintf(ptrTrama->parametros,"nfn=%s\r","RESPUESTA_Reiniciar"); + respuestaEjecucionComando(ptrTrama,0,ids); + + sprintf(interface,"%s/%s",pathinterface,nfn); + herror=interfaceAdmin(interface,NULL,NULL); + if(herror){ + sprintf(msglog,"%s:%s",tbErrores[86],nfn); + liberaMemoria(nfn); + liberaMemoria(ids); + errorInfo(modulo,msglog); + return(FALSE); + } + liberaMemoria(nfn); + liberaMemoria(ids); + return(TRUE); +} +//_____________________________________________________________________________________________________ +// Función: IniciarSesion +// +// Descripción: +// Inicia sesión en el Sistema Operativo de una de las particiones +// Parámetros: +// ptrTrama: contenido del mensaje +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//_____________________________________________________________________________________________________ +BOOLEAN IniciarSesion(TRAMA* ptrTrama) +{ + char *nfn,*ids,*disk,*par,msglog[LONSTD]; + char modulo[] = "IniciarSesion()"; + + if (ndebug>=DEBUG_MAXIMO) { + sprintf(msglog, "%s:%s",tbMensajes[21],modulo); + infoDebug(msglog); + } + nfn=copiaParametro("nfn",ptrTrama); + ids=copiaParametro("ids",ptrTrama); + disk=copiaParametro("dsk",ptrTrama); + par=copiaParametro("par",ptrTrama); + + initParametros(ptrTrama,0); + sprintf(ptrTrama->parametros,"nfn=%s\r","RESPUESTA_IniciarSesion"); + respuestaEjecucionComando(ptrTrama,0,ids); + liberaMemoria(ids); + + sprintf(interface,"%s/%s",pathinterface,nfn); + sprintf(parametros,"%s %s %s",nfn,disk,par); + liberaMemoria(par); + + herror=interfaceAdmin(interface,parametros,NULL); + + if(herror){ + sprintf(msglog,"%s:%s",tbErrores[86],nfn); + liberaMemoria(nfn); + errorInfo(modulo,msglog); + return(FALSE); + } + liberaMemoria(nfn); + return(TRUE); +} +//______________________________________________________________________________________________________ +// Función: CrearImagen +// +// Descripción: +// Crea una imagen de una partición +// Parámetros: +// ptrTrama: contenido del mensaje +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//______________________________________________________________________________________________________ +BOOLEAN CrearImagen(TRAMA* ptrTrama) +{ + int lon; + char *nfn,*dsk,*par,*cpt,*idi,*ipr,*nci,*ids,msglog[LONSTD]; + char modulo[] = "CrearImagen()"; + + if (ndebug>=DEBUG_MAXIMO) { + sprintf(msglog, "%s:%s",tbMensajes[21],modulo); + infoDebug(msglog); + } + + dsk=copiaParametro("dsk",ptrTrama); // Disco + par=copiaParametro("par",ptrTrama); // Número de partición + cpt=copiaParametro("cpt",ptrTrama); // Código de la partición + idi=copiaParametro("idi",ptrTrama); // Identificador de la imagen + nci=copiaParametro("nci",ptrTrama); // Nombre canónico de la imagen + ipr=copiaParametro("ipr",ptrTrama); // Ip del repositorio + + nfn=copiaParametro("nfn",ptrTrama); + ids=copiaParametro("ids",ptrTrama); + muestraMensaje(7,NULL); + + if(InventariandoSoftware(ptrTrama,FALSE,"InventarioSoftware")){ // Crea inventario Software previamente + muestraMensaje(2,NULL); + sprintf(interface,"%s/%s",pathinterface,nfn); + sprintf(parametros,"%s %s %s %s %s",nfn,dsk,par,nci,ipr); + herror=interfaceAdmin(interface,parametros,NULL); + if(herror){ + sprintf(msglog,"%s:%s",tbErrores[86],nfn); + errorInfo(modulo,msglog); + muestraMensaje(10,NULL); + } + else + muestraMensaje(9,NULL); + } + else{ + sprintf(msglog,"%s:%s",tbErrores[86],nfn); + errorInfo(modulo,msglog); + } + + /* Envia respuesta de ejecución de la función de interface */ + initParametros(ptrTrama,0); + lon=sprintf(ptrTrama->parametros,"nfn=%s\r","RESPUESTA_CrearImagen"); + lon+=sprintf(ptrTrama->parametros+lon,"idi=%s\r",idi); // Identificador de la imagen + lon+=sprintf(ptrTrama->parametros+lon,"dsk=%s\r",dsk); // Número de disco + lon+=sprintf(ptrTrama->parametros+lon,"par=%s\r",par); // Número de partición de donde se creó + lon+=sprintf(ptrTrama->parametros+lon,"cpt=%s\r",cpt); // Tipo o código de partición + lon+=sprintf(ptrTrama->parametros+lon,"ipr=%s\r",ipr); // Ip del repositorio donde se alojó + respuestaEjecucionComando(ptrTrama,herror,ids); + + liberaMemoria(dsk); + liberaMemoria(par); + liberaMemoria(cpt); + liberaMemoria(idi); + liberaMemoria(nci); + liberaMemoria(ipr); + liberaMemoria(nfn); + liberaMemoria(ids); + + muestraMenu(); + + return(TRUE); +} +//______________________________________________________________________________________________________ +// Función: CrearImagenBasica +// +// Descripción: +// Crea una imagen básica a travers dela sincronización +// Parámetros: +// ptrTrama: contenido del mensaje +// +// FDevuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//______________________________________________________________________________________________________ +BOOLEAN CrearImagenBasica(TRAMA* ptrTrama) +{ + int lon; + char *nfn,*dsk,*par,*cpt,*idi,*nci,*rti,*ipr,*msy,*whl,*eli,*cmp,*bpi,*cpc,*bpc,*nba,*ids,msglog[LONSTD]; + char modulo[] = "CrearImagenBasica()"; + + if (ndebug>=DEBUG_MAXIMO) { + sprintf(msglog, "%s:%s",tbMensajes[21],modulo); + infoDebug(msglog); + } + nfn=copiaParametro("nfn",ptrTrama); + dsk=copiaParametro("dsk",ptrTrama); // Disco + par=copiaParametro("par",ptrTrama); // Número de partición + cpt=copiaParametro("cpt",ptrTrama); // Tipo de partición + idi=copiaParametro("idi",ptrTrama); // Identificador de la imagen + nci=copiaParametro("nci",ptrTrama); // Nombre canónico de la imagen + rti=copiaParametro("rti",ptrTrama); // Ruta de origen de la imagen + ipr=copiaParametro("ipr",ptrTrama); // Ip del repositorio + + msy=copiaParametro("msy",ptrTrama); // Método de sincronización + + whl=copiaParametro("whl",ptrTrama); // Envío del fichero completo si hay diferencias + eli=copiaParametro("eli",ptrTrama); // Elimiar archivos en destino que no estén en origen + cmp=copiaParametro("cmp",ptrTrama); // Comprimir antes de enviar + + bpi=copiaParametro("bpi",ptrTrama); // Borrar la imagen antes de crearla + cpc=copiaParametro("cpc",ptrTrama); // Copiar también imagen a la cache + bpc=copiaParametro("bpc",ptrTrama); // Borrarla de la cache antes de copiarla en ella + nba=copiaParametro("nba",ptrTrama); // No borrar archivos en destino + + muestraMensaje(7,NULL); // Creando Inventario Software + if(InventariandoSoftware(ptrTrama,FALSE,"InventarioSoftware")){ // Crea inventario Software previamente + muestraMensaje(30,NULL);// Creando Imagen Básica, por favor espere... + sprintf(interface,"%s/%s",pathinterface,nfn); + sprintf(parametros,"%s %s %s %s %s %s%s%s %s%s%s%s %s %s",nfn,dsk,par,nci,ipr,whl,eli,cmp,bpi,cpc,bpc,nba,msy,rti); + herror=interfaceAdmin(interface,parametros,NULL); + if(herror){ + sprintf(msglog,"%s:%s",tbErrores[86],nfn); + errorInfo(modulo,msglog); + muestraMensaje(29,NULL);// Ha habido algún error en el proceso de creación de imagen básica + } + else + muestraMensaje(28,NULL);// El proceso de creación de imagen básica ha terminado correctamente + } + else{ + sprintf(msglog,"%s:%s",tbErrores[86],nfn); + errorInfo(modulo,msglog); + } + + ids=copiaParametro("ids",ptrTrama); // Identificador de la sesión + + /* Envia respuesta de ejecución de la función de interface */ + initParametros(ptrTrama,0); + lon=sprintf(ptrTrama->parametros,"nfn=%s\r","RESPUESTA_CrearImagenBasica"); + lon+=sprintf(ptrTrama->parametros+lon,"idi=%s\r",idi); // Identificador de la imagen + lon+=sprintf(ptrTrama->parametros+lon,"dsk=%s\r",dsk); // Número de disco + lon+=sprintf(ptrTrama->parametros+lon,"par=%s\r",par); // Número de partición de donde se creó + lon+=sprintf(ptrTrama->parametros+lon,"cpt=%s\r",cpt); // Tipo o código de partición + lon+=sprintf(ptrTrama->parametros+lon,"ipr=%s\r",ipr); // Ip del repositorio donde se alojó + respuestaEjecucionComando(ptrTrama,herror,ids); + + liberaMemoria(nfn); + liberaMemoria(dsk); + liberaMemoria(par); + liberaMemoria(cpt); + liberaMemoria(idi); + liberaMemoria(nci); + liberaMemoria(rti); + liberaMemoria(ipr); + + liberaMemoria(msy); + + liberaMemoria(whl); + liberaMemoria(eli); + liberaMemoria(cmp); + + liberaMemoria(bpi); + liberaMemoria(cpc); + liberaMemoria(bpc); + liberaMemoria(nba); + liberaMemoria(ids); + + muestraMenu(); + + return(TRUE); +} +//______________________________________________________________________________________________________ +// Función: CrearSoftIncremental +// +// Descripción: +// Crea una software incremental comparando una partición con una imagen básica +// Parámetros: +// ptrTrama: contenido del mensaje +// +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//______________________________________________________________________________________________________ +BOOLEAN CrearSoftIncremental(TRAMA* ptrTrama) +{ + int lon; + char *nfn,*dsk,*par,*idi,*idf,*ipr,*nci,*rti,*ncf,*msy,*whl,*eli,*cmp,*bpi,*cpc,*bpc,*nba,*ids,msglog[LONSTD]; + char modulo[] = "CrearSoftIncremental()"; + + if (ndebug>=DEBUG_MAXIMO) { + sprintf(msglog, "%s:%s",tbMensajes[21],modulo); + infoDebug(msglog); + } + nfn=copiaParametro("nfn",ptrTrama); + + dsk=copiaParametro("dsk",ptrTrama); // Disco + par=copiaParametro("par",ptrTrama); // Número de partición + idi=copiaParametro("idi",ptrTrama); // Identificador de la imagen + nci=copiaParametro("nci",ptrTrama); // Nombre canónico de la imagen + rti=copiaParametro("rti",ptrTrama); // Ruta de origen de la imagen + ipr=copiaParametro("ipr",ptrTrama); // Ip del repositorio + idf=copiaParametro("idf",ptrTrama); // Identificador de la imagen diferencial + ncf=copiaParametro("ncf",ptrTrama); // Nombre canónico de la imagen diferencial + + msy=copiaParametro("msy",ptrTrama); // Método de sincronización + + whl=copiaParametro("whl",ptrTrama); // Envío del fichero completo si hay diferencias + eli=copiaParametro("eli",ptrTrama); // Elimiar archivos en destino que no estén en origen + cmp=copiaParametro("cmp",ptrTrama); // Comprimir antes de enviar + + bpi=copiaParametro("bpi",ptrTrama); // Borrar la imagen antes de crearla + cpc=copiaParametro("cpc",ptrTrama); // Copiar también imagen a la cache + bpc=copiaParametro("bpc",ptrTrama); // Borrarla de la cache antes de copiarla en ella + nba=copiaParametro("nba",ptrTrama); // No borrar archivos en destino + + muestraMensaje(7,NULL); // Creando Inventario Software + if(InventariandoSoftware(ptrTrama,FALSE,"InventarioSoftware")){ // Crea inventario Software previamente + muestraMensaje(25,NULL);// Creando Imagen Incremental, por favor espere... + sprintf(interface,"%s/%s",pathinterface,nfn); + sprintf(parametros,"%s %s %s %s %s %s %s%s%s %s%s%s%s %s %s",nfn,dsk,par,nci,ipr,ncf,whl,eli,cmp,bpi,cpc,bpc,nba,msy,rti); + + herror=interfaceAdmin(interface,parametros,NULL); + if(herror){ + sprintf(msglog,"%s:%s",tbErrores[86],nfn); + errorInfo(modulo,msglog); + muestraMensaje(27,NULL);// Ha habido algún error en el proceso de creación de imagen básica + } + else + muestraMensaje(26,NULL);// El proceso de creación de imagen incremental ha terminado correctamente + } + else{ + sprintf(msglog,"%s:%s",tbErrores[86],nfn); + errorInfo(modulo,msglog); + } + + ids=copiaParametro("ids",ptrTrama); // Identificador de la sesión + + /* Envia respuesta de ejecución de la función de interface */ + initParametros(ptrTrama,0); + lon=sprintf(ptrTrama->parametros,"nfn=%s\r","RESPUESTA_CrearSoftIncremental"); + lon+=sprintf(ptrTrama->parametros+lon,"idf=%s\r",idf); // Identificador de la imagen incremental + lon+=sprintf(ptrTrama->parametros+lon,"dsk=%s\r",dsk); // Número de disco + lon+=sprintf(ptrTrama->parametros+lon,"par=%s\r",par); // Número de partición + respuestaEjecucionComando(ptrTrama,herror,ids); + + liberaMemoria(nfn); + liberaMemoria(dsk); + liberaMemoria(par); + liberaMemoria(idi); + liberaMemoria(nci); + liberaMemoria(rti); + liberaMemoria(ipr); + liberaMemoria(idf); + liberaMemoria(ncf); + liberaMemoria(msy); + liberaMemoria(whl); + liberaMemoria(eli); + liberaMemoria(cmp); + liberaMemoria(bpi); + liberaMemoria(cpc); + liberaMemoria(bpc); + liberaMemoria(nba); + liberaMemoria(ids); + + muestraMenu(); + + return(TRUE); +} +//______________________________________________________________________________________________________ +// Función: RestaurarImagen +// +// Descripción: +// Restaura una imagen en una partición +// Parámetros: +// ptrTrama: contenido del mensaje +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En bpccaso de ocurrir algún error +//______________________________________________________________________________________________________ +BOOLEAN RestaurarImagen(TRAMA* ptrTrama) +{ + int lon; + char *nfn,*dsk,*par,*idi,*ipr,*ifs,*cfg,*nci,*ids,*ptc,msglog[LONSTD]; + char modulo[] = "RestaurarImagen()"; + + if (ndebug>=DEBUG_MAXIMO) { + sprintf(msglog, "%s:%s",tbMensajes[21],modulo); + infoDebug(msglog); + } + + dsk=copiaParametro("dsk",ptrTrama); + par=copiaParametro("par",ptrTrama); + idi=copiaParametro("idi",ptrTrama); + ipr=copiaParametro("ipr",ptrTrama); + nci=copiaParametro("nci",ptrTrama); + ifs=copiaParametro("ifs",ptrTrama); + ptc=copiaParametro("ptc",ptrTrama); + + nfn=copiaParametro("nfn",ptrTrama); + ids=copiaParametro("ids",ptrTrama); + muestraMensaje(3,NULL); + sprintf(interface,"%s/%s",pathinterface,nfn); + sprintf(parametros,"%s %s %s %s %s %s",nfn,dsk,par,nci,ipr,ptc); + herror=interfaceAdmin(interface,parametros,NULL); + if(herror){ + sprintf(msglog,"%s:%s",tbErrores[86],nfn); + errorInfo(modulo,msglog); + muestraMensaje(12,NULL); + } + else + muestraMensaje(11,NULL); + + /* Obtener nueva configuración */ + cfg=LeeConfiguracion(); + if(!cfg){ // No se puede recuperar la configuración del cliente + errorLog(modulo,36,FALSE); + } + + /* Envia respuesta de ejecución de la función de interface */ + initParametros(ptrTrama,0); + lon=sprintf(ptrTrama->parametros,"nfn=%s\r","RESPUESTA_RestaurarImagen"); + lon+=sprintf(ptrTrama->parametros+lon,"idi=%s\r",idi); // Identificador de la imagen + lon+=sprintf(ptrTrama->parametros+lon,"dsk=%s\r",dsk); // Número de disco + lon+=sprintf(ptrTrama->parametros+lon,"par=%s\r",par); // Número de partición + lon+=sprintf(ptrTrama->parametros+lon,"ifs=%s\r",ifs); // Identificador del perfil software + lon+=sprintf(ptrTrama->parametros+lon,"cfg=%s\r",cfg); // Configuración de discos + respuestaEjecucionComando(ptrTrama,herror,ids); + + liberaMemoria(nfn); + liberaMemoria(dsk); + liberaMemoria(par); + liberaMemoria(idi); + liberaMemoria(nci); + liberaMemoria(ipr); + liberaMemoria(ifs); + liberaMemoria(cfg); + liberaMemoria(ptc); + liberaMemoria(ids); + + muestraMenu(); + + return(TRUE); +} +//______________________________________________________________________________________________________ +// Función: RestaurarImagenBasica +// +// Descripción: +// Restaura una imagen básica en una partición +// Parámetros: +// ptrTrama: contenido del mensaje +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//______________________________________________________________________________________________________ +BOOLEAN RestaurarImagenBasica(TRAMA* ptrTrama) +{ + int lon; + char *nfn,*dsk,*par,*idi,*ipr,*met,*nci,*rti,*ifs,*cfg,*msy,*whl,*eli,*cmp,*tpt,*bpi,*cpc,*bpc,*nba,*ids,msglog[LONSTD]; + char modulo[] = "RestaurarImagenBasica()"; + + if (ndebug>=DEBUG_MAXIMO) { + sprintf(msglog, "%s:%s",tbMensajes[21],modulo); + infoDebug(msglog); + } + dsk=copiaParametro("dsk",ptrTrama); + par=copiaParametro("par",ptrTrama); + idi=copiaParametro("idi",ptrTrama); + ipr=copiaParametro("ipr",ptrTrama); + met=copiaParametro("met",ptrTrama); // Método de clonación 0= desde caché 1= desde repositorio + nci=copiaParametro("nci",ptrTrama); + rti=copiaParametro("rti",ptrTrama); // Ruta de origen de la imagen + ifs=copiaParametro("ifs",ptrTrama); + + tpt=copiaParametro("tpt",ptrTrama); // Tipo de trasnmisión unicast o multicast + msy=copiaParametro("msy",ptrTrama); // Metodo de sincronizacion + + whl=copiaParametro("whl",ptrTrama); // Envío del fichero completo si hay diferencias + eli=copiaParametro("eli",ptrTrama); // Elimiar archivos en destino que no estén en origen + cmp=copiaParametro("cmp",ptrTrama); // Comprimir antes de enviar + + bpi=copiaParametro("bpi",ptrTrama); // Borrar la imagen antes de crearla + cpc=copiaParametro("cpc",ptrTrama); // Copiar también imagen a la cache + bpc=copiaParametro("bpc",ptrTrama); // Borrarla de la cache antes de copiarla en ella + nba=copiaParametro("nba",ptrTrama); // No borrar archivos en destino + + nfn=copiaParametro("nfn",ptrTrama); + ids=copiaParametro("ids",ptrTrama); + muestraMensaje(31,NULL); + sprintf(interface,"%s/%s",pathinterface,nfn); + sprintf(parametros,"%s %s %s %s %s %s %s%s%s %s%s%s%s %s %s %s",nfn,dsk,par,nci,ipr,tpt,whl,eli,cmp,bpi,cpc,bpc,nba,met,msy,rti); + herror=interfaceAdmin(interface,parametros,NULL); + if(herror){ + sprintf(msglog,"%s:%s",tbErrores[86],nfn); + errorInfo(modulo,msglog); + muestraMensaje(33,NULL); + } + else + muestraMensaje(32,NULL); + + /* Obtener nueva configuración */ + cfg=LeeConfiguracion(); + if(!cfg){ // No se puede recuperar la configuración del cliente + errorLog(modulo,36,FALSE); + } + + /* Envia respuesta de ejecución de la función de interface */ + initParametros(ptrTrama,0); + lon=sprintf(ptrTrama->parametros,"nfn=%s\r","RESPUESTA_RestaurarImagenBasica"); + lon+=sprintf(ptrTrama->parametros+lon,"idi=%s\r",idi); // Identificador de la imagen + lon+=sprintf(ptrTrama->parametros+lon,"dsk=%s\r",dsk); // Número de disco + lon+=sprintf(ptrTrama->parametros+lon,"par=%s\r",par); // Número de partición + lon+=sprintf(ptrTrama->parametros+lon,"ifs=%s\r",ifs); // Identificador del perfil software + lon+=sprintf(ptrTrama->parametros+lon,"cfg=%s\r",cfg); // Configuración de discos + respuestaEjecucionComando(ptrTrama,herror,ids); + + liberaMemoria(nfn); + liberaMemoria(dsk); + liberaMemoria(par); + liberaMemoria(idi); + liberaMemoria(nci); + liberaMemoria(rti); + liberaMemoria(ifs); + liberaMemoria(cfg); + liberaMemoria(ipr); + liberaMemoria(met); + + liberaMemoria(tpt); + liberaMemoria(msy); + + liberaMemoria(whl); + liberaMemoria(eli); + liberaMemoria(cmp); + + liberaMemoria(bpi); + liberaMemoria(cpc); + liberaMemoria(bpc); + liberaMemoria(nba); + liberaMemoria(ids); + + muestraMenu(); + + return(TRUE); +} +//______________________________________________________________________________________________________ +// Función: RestaurarSoftIncremental +// +// Descripción: +// Restaura software incremental en una partición +// Parámetros: +// ptrTrama: contenido del mensaje +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//______________________________________________________________________________________________________ +BOOLEAN RestaurarSoftIncremental(TRAMA* ptrTrama) +{ + int lon; + char *nfn,*dsk,*par,*idi,*ipr,*met,*ifs,*nci,*rti,*idf,*ncf,*msy,*whl,*eli,*cmp,*tpt,*bpi,*cpc,*bpc,*nba,*ids,msglog[LONSTD]; + char modulo[] = "RestaurarSoftIncremental()"; + + if (ndebug>=DEBUG_MAXIMO) { + sprintf(msglog, "%s:%s",tbMensajes[21],modulo); + infoDebug(msglog); + } + dsk=copiaParametro("dsk",ptrTrama); + par=copiaParametro("par",ptrTrama); + idi=copiaParametro("idi",ptrTrama); + idf=copiaParametro("idf",ptrTrama); + ipr=copiaParametro("ipr",ptrTrama); + met=copiaParametro("met",ptrTrama); // Método de clonación 0= desde caché 1= desde repositorio + ifs=copiaParametro("ifs",ptrTrama); + nci=copiaParametro("nci",ptrTrama); + rti=copiaParametro("rti",ptrTrama); // Ruta de origen de la imagen + ncf=copiaParametro("ncf",ptrTrama); + + tpt=copiaParametro("tpt",ptrTrama); // Tipo de trasnmisión unicast o multicast + msy=copiaParametro("msy",ptrTrama); // Metodo de sincronizacion + + whl=copiaParametro("whl",ptrTrama); // Envío del fichero completo si hay diferencias + eli=copiaParametro("eli",ptrTrama); // Elimiar archivos en destino que no estén en origen + cmp=copiaParametro("cmp",ptrTrama); // Comprimir antes de enviar + + bpi=copiaParametro("bpi",ptrTrama); // Borrar la imagen antes de crearla + cpc=copiaParametro("cpc",ptrTrama); // Copiar también imagen a la cache + bpc=copiaParametro("bpc",ptrTrama); // Borrarla de la cache antes de copiarla en ella + nba=copiaParametro("nba",ptrTrama); // No borrar archivos en destino + + nfn=copiaParametro("nfn",ptrTrama); + ids=copiaParametro("ids",ptrTrama); + muestraMensaje(31,NULL); + sprintf(interface,"%s/%s",pathinterface,nfn); + sprintf(parametros,"%s %s %s %s %s %s %s %s%s%s %s%s%s%s %s %s %s",nfn,dsk,par,nci,ipr,ncf,tpt,whl,eli,cmp,bpi,cpc,bpc,nba,met,msy,rti); + herror=interfaceAdmin(interface,parametros,NULL); + if(herror){ + sprintf(msglog,"%s:%s",tbErrores[86],nfn); + errorInfo(modulo,msglog); + muestraMensaje(35,NULL); + } + else + muestraMensaje(34,NULL); + + /* Envia respuesta de ejecución de la función de interface */ + initParametros(ptrTrama,0); + lon=sprintf(ptrTrama->parametros,"nfn=%s\r","RESPUESTA_RestaurarSoftIncremental"); + lon+=sprintf(ptrTrama->parametros+lon,"idi=%s\r",idf); // Identificador de la imagen incremental (Forzada a idi) + lon+=sprintf(ptrTrama->parametros+lon,"dsk=%s\r",dsk); // Número de disco + lon+=sprintf(ptrTrama->parametros+lon,"par=%s\r",par); // Número de partición + lon+=sprintf(ptrTrama->parametros+lon,"ifs=%s\r",ifs); // Identificador del perfil software + + respuestaEjecucionComando(ptrTrama,herror,ids); + + liberaMemoria(nfn); + liberaMemoria(dsk); + liberaMemoria(par); + liberaMemoria(idi); + liberaMemoria(idf); + liberaMemoria(nci); + liberaMemoria(rti); + liberaMemoria(ncf); + liberaMemoria(ifs); + liberaMemoria(ipr); + liberaMemoria(met); + + liberaMemoria(tpt); + liberaMemoria(msy); + + liberaMemoria(whl); + liberaMemoria(eli); + liberaMemoria(cmp); + + liberaMemoria(bpi); + liberaMemoria(cpc); + liberaMemoria(bpc); + liberaMemoria(nba); + liberaMemoria(ids); + + muestraMenu(); + + return(TRUE); +} +//______________________________________________________________________________________________________ +// Función: Configurar +// +// Descripción: +// Configura la tabla de particiones y formatea +// Parámetros: +// ptrTrama: contenido del mensaje +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//______________________________________________________________________________________________________ +BOOLEAN Configurar(TRAMA* ptrTrama) +{ + int lon; + char *nfn,*dsk,*cfg,*ids,msglog[LONSTD]; + char modulo[] = "Configurar()"; + + if (ndebug>=DEBUG_MAXIMO) { + sprintf(msglog, "%s:%s",tbMensajes[21],modulo); + infoDebug(msglog); + } + + dsk=copiaParametro("dsk",ptrTrama); + cfg=copiaParametro("cfg",ptrTrama); + /* Sustituir caracteres */ + sustituir(cfg,'\n','$'); + sustituir(cfg,'\t','#'); + + nfn=copiaParametro("nfn",ptrTrama); + ids=copiaParametro("ids",ptrTrama); + muestraMensaje(4,NULL); + sprintf(interface,"%s/%s",pathinterface,nfn); + sprintf(parametros,"%s %s %s",nfn,dsk,cfg); + + herror=interfaceAdmin(interface,parametros,NULL); + if(herror){ + sprintf(msglog,"%s:%s",tbErrores[86],nfn); + errorInfo(modulo,msglog); + muestraMensaje(13,NULL); + } + else + muestraMensaje(14,NULL); + + cfg=LeeConfiguracion(); + if(!cfg){ // No se puede recuperar la configuración del cliente + errorLog(modulo,36,FALSE); + return(FALSE); + } + + /* Envia respuesta de ejecución del comando*/ + initParametros(ptrTrama,0); + lon=sprintf(ptrTrama->parametros,"nfn=%s\r","RESPUESTA_Configurar"); + lon+=sprintf(ptrTrama->parametros+lon,"cfg=%s\r",cfg); // Configuración de los Sistemas Operativos del cliente + respuestaEjecucionComando(ptrTrama,herror,ids); + + liberaMemoria(dsk); + liberaMemoria(cfg); + liberaMemoria(nfn); + liberaMemoria(ids); + + muestraMenu(); + + return(TRUE); +} +// ________________________________________________________________________________________________________ +// Función: InventarioHardware +// +// Descripción: +// Envia al servidor el nombre del archivo de inventario de su hardware para posteriormente +// esperar que éste lo solicite y enviarlo por la red. +// Parámetros: +// ptrTrama: contenido del mensaje +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//______________________________________________________________________________________________________ +BOOLEAN InventarioHardware(TRAMA* ptrTrama) +{ + int lon; + SOCKET socket_c; + char *nfn,*ids,msglog[LONSTD],hrdsrc[LONPRM],hrddst[LONPRM]; + char modulo[] = "InventarioHardware()"; + + if (ndebug>=DEBUG_MAXIMO) { + sprintf(msglog, "%s:%s",tbMensajes[21],modulo); + infoDebug(msglog); + } + + nfn=copiaParametro("nfn",ptrTrama); + ids=copiaParametro("ids",ptrTrama); + muestraMensaje(6,NULL); + + sprintf(interface,"%s/%s",pathinterface,nfn); + sprintf(hrdsrc,"/tmp/Chrd-%s",IPlocal); // Nombre que tendra el archivo de inventario + sprintf(parametros,"%s %s",nfn,hrdsrc); + herror=interfaceAdmin(interface,parametros,NULL); + if(herror){ + sprintf(msglog,"%s:%s",tbErrores[86],nfn); + errorInfo(modulo,msglog); + muestraMensaje(18,NULL); + } + else{ + /* Envía fichero de inventario al servidor */ + sprintf(hrddst,"/tmp/Shrd-%s",IPlocal); // Nombre que tendra el archivo en el Servidor + initParametros(ptrTrama,0); + sprintf(ptrTrama->parametros,"nfn=recibeArchivo\rnfl=%s\r",hrddst); + if(!enviaMensajeServidor(&socket_c,ptrTrama,MSG_COMANDO)){ + liberaMemoria(nfn); + liberaMemoria(ids); + errorLog(modulo,42,FALSE); + return(FALSE); + } + /* Espera señal para comenzar el envío */ + liberaMemoria(ptrTrama); + recibeFlag(&socket_c,ptrTrama); + /* Envía archivo */ + if(!sendArchivo(&socket_c,hrdsrc)){ + errorLog(modulo,57, FALSE); + herror=12; // Error de envío de fichero por la red + } + close(socket_c); + muestraMensaje(17,NULL); + } + + /* Envia respuesta de ejecución de la función de interface */ + initParametros(ptrTrama,0); + lon=sprintf(ptrTrama->parametros,"nfn=%s\r","RESPUESTA_InventarioHardware"); + lon+=sprintf(ptrTrama->parametros+lon,"hrd=%s\r",hrddst); + respuestaEjecucionComando(ptrTrama,herror,ids); + liberaMemoria(nfn); + liberaMemoria(ids); + + muestraMenu(); + + return(TRUE); +} +// ________________________________________________________________________________________________________ +// Función: InventarioSoftware +// +// Descripción: +// Crea el inventario software de un sistema operativo instalado en una partición. +// Parámetros: +// ptrTrama: contenido del mensaje +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//______________________________________________________________________________________________________ +BOOLEAN InventarioSoftware(TRAMA* ptrTrama) +{ + char *nfn,*ids,msglog[LONSTD]; + char modulo[] = "InventarioSoftware()"; + + if (ndebug>=DEBUG_MAXIMO) { + sprintf(msglog, "%s:%s",tbMensajes[21],modulo); + infoDebug(msglog); + } + nfn=copiaParametro("nfn",ptrTrama); + ids=copiaParametro("ids",ptrTrama); + muestraMensaje(7,NULL); + InventariandoSoftware(ptrTrama,TRUE,nfn); + respuestaEjecucionComando(ptrTrama,herror,ids); + liberaMemoria(nfn); + liberaMemoria(ids); + muestraMenu(); + return(TRUE); +} +// ________________________________________________________________________________________________________ +// +// Función: InventariandoSoftware +// +// Descripción: +// Envia al servidor el nombre del archivo de inventario de su software para posteriormente +// esperar que éste lo solicite y enviarlo por la red. +// Parámetros: +// ptrTrama: contenido del mensaje +// sw: switch que indica si la función es llamada por el comando InventarioSoftware(true) o CrearImagen(false) +// nfn: Nombre de la función del Interface que implementa el comando +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//______________________________________________________________________________________________________ +BOOLEAN InventariandoSoftware(TRAMA* ptrTrama,BOOLEAN sw,char *nfn) +{ + int lon; + SOCKET socket_c; + char *dsk,*par,msglog[LONSTD],sftsrc[LONPRM],sftdst[LONPRM]; + char modulo[] = "InventariandoSoftware()"; + + dsk=copiaParametro("dsk",ptrTrama); // Disco + par=copiaParametro("par",ptrTrama); + + sprintf(interface,"%s/%s",pathinterface,nfn); + sprintf(sftsrc,"/tmp/CSft-%s-%s",IPlocal,par); // Nombre que tendra el archivo de inventario + sprintf(parametros,"%s %s %s %s",nfn,dsk,par,sftsrc); + + herror=interfaceAdmin(interface,parametros,NULL); + herror=0; + if(herror){ + sprintf(msglog,"%s:%s",tbErrores[86],nfn); + errorInfo(modulo,msglog); + muestraMensaje(20,NULL); + } + else{ + /* Envía fichero de inventario al servidor */ + sprintf(sftdst,"/tmp/Ssft-%s-%s",IPlocal,par); // Nombre que tendra el archivo en el Servidor + initParametros(ptrTrama,0); + + sprintf(ptrTrama->parametros,"nfn=recibeArchivo\rnfl=%s\r",sftdst); + if(!enviaMensajeServidor(&socket_c,ptrTrama,MSG_COMANDO)){ + errorLog(modulo,42,FALSE); + liberaMemoria(dsk); + liberaMemoria(par); + return(FALSE); + } + /* Espera señal para comenzar el envío */ + liberaMemoria(ptrTrama); + if(!recibeFlag(&socket_c,ptrTrama)){ + errorLog(modulo,17,FALSE); + } + /* Envía archivo */ + if(!sendArchivo(&socket_c,sftsrc)){ + errorLog(modulo,57, FALSE); + herror=12; // Error de envío de fichero por la red + } + close(socket_c); + muestraMensaje(19,NULL); + } + initParametros(ptrTrama,0); + lon=sprintf(ptrTrama->parametros,"nfn=%s\r","RESPUESTA_InventarioSoftware"); + lon+=sprintf(ptrTrama->parametros+lon,"par=%s\r",par); + lon+=sprintf(ptrTrama->parametros+lon,"sft=%s\r",sftdst); + if(!sw) + respuestaEjecucionComando(ptrTrama,herror,"0"); + + liberaMemoria(dsk); + liberaMemoria(par); + return(TRUE); +} +// ________________________________________________________________________________________________________ +// Función: EjecutarScript +// +// Descripción: +// Ejecuta código de script +// Parámetros: +// ptrTrama: contenido del mensaje +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//______________________________________________________________________________________________________ +BOOLEAN EjecutarScript(TRAMA* ptrTrama) +{ + int lon; + char *nfn,*aux,*ids,*scp,*cfg,msglog[LONSTD]; + char modulo[] = "EjecutarScript()"; + + if (ndebug>=DEBUG_MAXIMO) { + sprintf(msglog, "%s:%s",tbMensajes[21],modulo); + infoDebug(msglog); + } + aux=copiaParametro("scp",ptrTrama); + scp=URLDecode(aux); + + + muestraMensaje(8,NULL); + /* Nombre del archivo de script */ + char filescript[LONPRM]; + sprintf(filescript,"/tmp/_script_%s",IPlocal); + escribeArchivo(filescript,scp); + nfn=copiaParametro("nfn",ptrTrama); + sprintf(interface,"%s/%s",pathinterface,nfn); + sprintf(parametros,"%s %s",nfn,filescript); + herror=interfaceAdmin(interface,parametros,NULL); + if(herror){ + sprintf(msglog,"%s:%s",tbErrores[86],nfn); + errorInfo(modulo,msglog); + muestraMensaje(21,NULL); + } + else + muestraMensaje(22,NULL); + + // Toma configuración de particiones + cfg=LeeConfiguracion(); + if(!cfg){ // No se puede recuperar la configuración del cliente + errorLog(modulo,36,FALSE); + herror=36; + } + + ids=copiaParametro("ids",ptrTrama); + + //herror=ejecutarCodigoBash(scp); + initParametros(ptrTrama,0); + lon=sprintf(ptrTrama->parametros,"nfn=%s\r","RESPUESTA_EjecutarScript"); + lon+=sprintf(ptrTrama->parametros+lon,"cfg=%s\r",cfg); // Configuración de los Sistemas Operativos del cliente + respuestaEjecucionComando(ptrTrama,herror,ids); + + liberaMemoria(nfn); + liberaMemoria(ids); + liberaMemoria(aux); + liberaMemoria(scp); + liberaMemoria(cfg); + + muestraMenu(); + + return(TRUE); +} +//______________________________________________________________________________________________________ +// Función: respuestaEjecucionComando +// +// Descripción: +// Envia una respuesta a una ejecucion de comando al servidor de Administración +// Parámetros: +// - ptrTrama: contenido del mensaje +// - res: Resultado de la ejecución (Código de error devuelto por el script ejecutado) +// - ids: Identificador de la sesion (En caso de no haber seguimiento es NULO) +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +BOOLEAN respuestaEjecucionComando(TRAMA* ptrTrama,int res,char *ids) +{ + int lon; + SOCKET socket_c; + char modulo[] = "respuestaEjecucionComando()"; + + lon=strlen(ptrTrama->parametros); + if(ids){ // Existe seguimiento + lon+=sprintf(ptrTrama->parametros+lon,"ids=%s\r",ids); // Añade identificador de la sesión + } + if (res==0){ // Resultado satisfactorio + lon+=sprintf(ptrTrama->parametros+lon,"res=%s\r","1"); + lon+=sprintf(ptrTrama->parametros+lon,"der=%s\r",""); + } + else{ // Algún error + lon+=sprintf(ptrTrama->parametros+lon,"res=%s\r","2"); + if(res>MAXERRORSCRIPT) + lon+=sprintf(ptrTrama->parametros+lon,"der=%s (Error de script:%d)\r",tbErroresScripts[0],res);// Descripción del error + else + lon+=sprintf(ptrTrama->parametros+lon,"der=%s\r",tbErroresScripts[res]);// Descripción del error + } + if(!(enviaMensajeServidor(&socket_c,ptrTrama,MSG_NOTIFICACION))){ + errorLog(modulo,44,FALSE); + return(FALSE); + } + + close(socket_c); + return(TRUE); +} +// ________________________________________________________________________________________________________ +// Función: gestionaTrama +// +// Descripción: +// Procesa las tramas recibidas. +// Parametros: +// ptrTrama: contenido del mensaje +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +BOOLEAN gestionaTrama(TRAMA *ptrTrama) +{ + int i, res; + char *nfn; + char modulo[] = "gestionaTrama()"; + + INTROaFINCAD(ptrTrama); + nfn = copiaParametro("nfn", ptrTrama); // Toma nombre de función + for (i = 0; i < MAXIMAS_FUNCIONES; i++) { // Recorre funciones que procesan las tramas + res = strcmp(tbfuncionesClient[i].nf, nfn); + if (res == 0) { // Encontrada la función que procesa el mensaje + liberaMemoria(nfn); + return(tbfuncionesClient[i].fptr(ptrTrama)); // Invoca la función + } + } + + liberaMemoria(nfn); + + /* Sólo puede ser un comando personalizado + if (ptrTrama->tipo==MSG_COMANDO) + return(Comando(ptrTrama)); + */ + errorLog(modulo, 18, FALSE); + return (FALSE); +} +//________________________________________________________________________________________________________ +// Función: ejecutaArchivo +// +// Descripción: +// Ejecuta los comando contenido en un archivo (cada comando y sus parametros separados por un +// salto de linea. +// Parámetros: +// filecmd: Nombre del archivo de comandos +// ptrTrama: Puntero a una estructura TRAMA usada en las comunicaciones por red (No debe ser NULL) +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +//________________________________________________________________________________________________________ +BOOLEAN ejecutaArchivo(char* filecmd,TRAMA *ptrTrama) +{ + char* buffer,*lineas[MAXIMAS_LINEAS]; + int i,numlin; + char modulo[] = "ejecutaArchivo()"; + + buffer=leeArchivo(filecmd); + if(buffer){ + numlin = splitCadena(lineas, buffer, '@'); + initParametros(ptrTrama,0); + for (i = 0; i < numlin; i++) { + if(strlen(lineas[i])>0){ + strcpy(ptrTrama->parametros,lineas[i]); + //strcat(ptrTrama->parametros,"\rMCDJ@"); // Fin de trama + if(!gestionaTrama(ptrTrama)){ // Análisis de la trama + errorLog(modulo,39,FALSE); + //return(FALSE); + } + } + } + } + liberaMemoria(buffer); + return(TRUE); +} + +BOOLEAN EjecutaComandosPendientes(TRAMA* ptrTrama) +{ + return(TRUE); +} + +//______________________________________________________________________________________________________ +// Función: enviaMensajeServidor +// +// Descripción: +// Envia un mensaje al servidor de Administración +// Parámetros: +// - socket_c: (Salida) Socket utilizado para el envío +// - ptrTrama: contenido del mensaje +// - tipo: Tipo de mensaje +// C=Comando, N=Respuesta a un comando, P=Peticion,R=Respuesta a una petición, I=Informacion +// Devuelve: +// TRUE: Si el proceso es correcto +// FALSE: En caso de ocurrir algún error +// ________________________________________________________________________________________________________ +BOOLEAN enviaMensajeServidor(SOCKET *socket_c,TRAMA *ptrTrama,char tipo) +{ + int lon; + char modulo[] = "enviaMensajeServidor()"; + + *socket_c=abreConexion(); + if(*socket_c==INVALID_SOCKET){ + errorLog(modulo,38,FALSE); // Error de conexión con el servidor + return(FALSE); + } + ptrTrama->arroba='@'; // Cabecera de la trama + strncpy(ptrTrama->identificador,"JMMLCAMDJ_MCDJ",14); // identificador de la trama + ptrTrama->tipo=tipo; // Tipo de mensaje + lon=strlen(ptrTrama->parametros); // Compone la trama + lon+=sprintf(ptrTrama->parametros+lon,"iph=%s\r",IPlocal); // Ip del ordenador + lon+=sprintf(ptrTrama->parametros+lon,"ido=%s\r",idordenador); // Identificador del ordenador + lon+=sprintf(ptrTrama->parametros+lon,"npc=%s\r",nombreordenador); // Nombre del ordenador + lon+=sprintf(ptrTrama->parametros+lon,"idc=%s\r",idcentro); // Identificador del centro + lon+=sprintf(ptrTrama->parametros+lon,"ida=%s\r",idaula); // Identificador del aula + + if (!mandaTrama(socket_c,ptrTrama)) { + errorLog(modulo,26,FALSE); + return (FALSE); + } + return(TRUE); +} +// ******************************************************************************************************** +// PROGRAMA PRINCIPAL (CLIENTE) +// ******************************************************************************************************** +int main(int argc, char *argv[]) +{ + TRAMA *ptrTrama; + char modulo[] = "main()"; + + ptrTrama=(TRAMA *)reservaMemoria(sizeof(TRAMA)); + if (ptrTrama == NULL) { // No hay memoria suficiente para el bufer de las tramas + errorLog(modulo, 3, FALSE); + exit(EXIT_FAILURE); + } + /*-------------------------------------------------------------------------------------------------------- + Validación de parámetros de ejecución y fichero de configuración + ---------------------------------------------------------------------------------------------------------*/ + if (!validacionParametros(argc, argv,3)) // Valida parámetros de ejecución + exit(EXIT_FAILURE); + + if (!tomaConfiguracion(szPathFileCfg)) // Toma parametros de configuración + exit(EXIT_FAILURE); + /*-------------------------------------------------------------------------------------------------------- + Carga catálogo de funciones que procesan las tramas + ---------------------------------------------------------------------------------------------------------*/ + int cf = 0; + + strcpy(tbfuncionesClient[cf].nf, "RESPUESTA_AutoexecCliente"); + tbfuncionesClient[cf++].fptr = &RESPUESTA_AutoexecCliente; + + strcpy(tbfuncionesClient[cf].nf, "RESPUESTA_InclusionCliente"); + tbfuncionesClient[cf++].fptr = &RESPUESTA_InclusionCliente; + + strcpy(tbfuncionesClient[cf].nf, "NoComandosPtes"); + tbfuncionesClient[cf++].fptr = &NoComandosPtes; + + strcpy(tbfuncionesClient[cf].nf, "Actualizar"); + tbfuncionesClient[cf++].fptr = &Actualizar; + + strcpy(tbfuncionesClient[cf].nf, "Purgar"); + tbfuncionesClient[cf++].fptr = &Purgar; + + strcpy(tbfuncionesClient[cf].nf, "ConsolaRemota"); + tbfuncionesClient[cf++].fptr = &ConsolaRemota; + + strcpy(tbfuncionesClient[cf].nf, "Sondeo"); + tbfuncionesClient[cf++].fptr = &Sondeo; + + strcpy(tbfuncionesClient[cf].nf, "Arrancar"); + tbfuncionesClient[cf++].fptr = &Arrancar; + + strcpy(tbfuncionesClient[cf].nf, "Apagar"); + tbfuncionesClient[cf++].fptr = &Apagar; + + strcpy(tbfuncionesClient[cf].nf, "Reiniciar"); + tbfuncionesClient[cf++].fptr = &Reiniciar; + + strcpy(tbfuncionesClient[cf].nf, "IniciarSesion"); + tbfuncionesClient[cf++].fptr = &IniciarSesion; + + strcpy(tbfuncionesClient[cf].nf, "CrearImagen"); + tbfuncionesClient[cf++].fptr = &CrearImagen; + + strcpy(tbfuncionesClient[cf].nf, "CrearImagenBasica"); + tbfuncionesClient[cf++].fptr = &CrearImagenBasica; + + strcpy(tbfuncionesClient[cf].nf, "CrearSoftIncremental"); + tbfuncionesClient[cf++].fptr = &CrearSoftIncremental; + + strcpy(tbfuncionesClient[cf].nf, "RestaurarImagen"); + tbfuncionesClient[cf++].fptr = &RestaurarImagen; + + strcpy(tbfuncionesClient[cf].nf, "RestaurarImagenBasica"); + tbfuncionesClient[cf++].fptr = &RestaurarImagenBasica; + + strcpy(tbfuncionesClient[cf].nf, "RestaurarSoftIncremental"); + tbfuncionesClient[cf++].fptr = &RestaurarSoftIncremental; + + + strcpy(tbfuncionesClient[cf].nf, "Configurar"); + tbfuncionesClient[cf++].fptr = &Configurar; + + strcpy(tbfuncionesClient[cf].nf, "EjecutarScript"); + tbfuncionesClient[cf++].fptr = &EjecutarScript; + + strcpy(tbfuncionesClient[cf].nf, "InventarioHardware"); + tbfuncionesClient[cf++].fptr = &InventarioHardware; + + strcpy(tbfuncionesClient[cf].nf, "InventarioSoftware"); + tbfuncionesClient[cf++].fptr = &InventarioSoftware; + + strcpy(tbfuncionesClient[cf].nf, "EjecutaComandosPendientes"); + tbfuncionesClient[cf++].fptr = &EjecutaComandosPendientes; + + /*-------------------------------------------------------------------------------------------------------- + Toma dirección IP del cliente + ---------------------------------------------------------------------------------------------------------*/ + if(!tomaIPlocal()){ // Error al recuperar la IP local + errorLog(modulo,0,FALSE); + exit(EXIT_FAILURE); + } + /*-------------------------------------------------------------------------------------------------------- + Inicio de sesión + ---------------------------------------------------------------------------------------------------------*/ + infoLog(1); // Inicio de sesión + infoLog(3); // Abriendo sesión en el servidor de Administración; + /*-------------------------------------------------------------------------------------------------------- + Inclusión del cliente en el sistema + ---------------------------------------------------------------------------------------------------------*/ + if(!inclusionCliente(ptrTrama)){ // Ha habido algún problema al abrir sesión + errorLog(modulo,0,FALSE); + exit(EXIT_FAILURE); + } + infoLog(4); // Cliente iniciado + + /*-------------------------------------------------------------------------------------------------------- + Procesamiento de la cache + ---------------------------------------------------------------------------------------------------------*/ + infoLog(23); // Abriendo sesión en el servidor de Administración; + if(!cuestionCache(cache)){ + errorLog(modulo,0,FALSE); + exit(EXIT_FAILURE); + } + /*-------------------------------------------------------------------------------------------------------- + Ejecución del autoexec + ---------------------------------------------------------------------------------------------------------*/ + if(atoi(idproautoexec)>0){ // Ejecución de procedimiento Autoexec + infoLog(5); + if(!autoexecCliente(ptrTrama)){ // Ejecución fichero autoexec + errorLog(modulo,0,FALSE); + exit(EXIT_FAILURE); + } + } + /*-------------------------------------------------------------------------------------------------------- + Comandos pendientes + ---------------------------------------------------------------------------------------------------------*/ + infoLog(6); // Procesa comandos pendientes + if(!comandosPendientes(ptrTrama)){ // Ejecución de acciones pendientes + errorLog(modulo,0,FALSE); + exit(EXIT_FAILURE); + } + infoLog(7); // Acciones pendientes procesadas + /*-------------------------------------------------------------------------------------------------------- + Bucle de recepción de comandos + ---------------------------------------------------------------------------------------------------------*/ + muestraMenu(); + procesaComandos(ptrTrama); // Bucle para procesar comandos interactivos + /*-------------------------------------------------------------------------------------------------------- + Fin de la sesión + ---------------------------------------------------------------------------------------------------------*/ + exit(EXIT_SUCCESS); +} diff --git a/sources/clients/ogAdmClient/sources/ogAdmClient.h b/sources/clients/ogAdmClient/sources/ogAdmClient.h new file mode 100644 index 0000000..da0a5c3 --- /dev/null +++ b/sources/clients/ogAdmClient/sources/ogAdmClient.h @@ -0,0 +1,183 @@ +// ******************************************************************************************************** +// Cliernte: ogAdmClient +// Autor: José Manuel Alonso (E.T.S.I.I.) Universidad de Sevilla +// Fecha Creación: Marzo-2010 +// Fecha Última modificación: Marzo-2010 +// Nombre del fichero: ogAdmClient.h +// Descripción :Este fichero implementa el cliente general del sistema +// ******************************************************************************************************** +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ogAdmLib.h" +// ________________________________________________________________________________________________________ +// Variables globales +// ________________________________________________________________________________________________________ +char *idordenador; // Identificador del ordenador +char *nombreordenador; // Nombre del ordenador +char *cache; // Tamaño de la caché +char *idproautoexec; // Identificador del procedimiento de autoexec +char *idcentro; // Identificador de la Unidad Organizativa +char *idaula; // Identificador del aula +char IPlocal[LONIP]; // Ip local + +char servidoradm[LONPRM]; // Dirección IP del servidor de administración +char puerto[LONPRM]; // Puerto de comunicación +char pathinterface[LONPRM]; // Path donde está la interface entre la administración y el módulo de clonación + +char interface[LONFUN]; // Nombre del módulo,función o script de la interface con el módulo de administración +char parametros[LONSTD]; // Parámetros para la llamada +int herror; + +BOOLEAN CMDPTES; // Para bucle de comandos pendientes + + +char urlmenu[MAXLONURL]; // Url de la pagina de menu para el browser +char urlmsg[MAXLONURL]; // Url de la página de mensajed para el browser + + +typedef struct{ // Estructura usada para referenciar las funciones que procesan las tramas + char nf[LONFUN]; // Nombre de la función + BOOLEAN (*fptr)(TRAMA*); // Puntero a la función que procesa la trama +}MSGFUN; +MSGFUN tbfuncionesClient[MAXIMAS_FUNCIONES]; +// ________________________________________________________________________________________________________ +// Tabla de errores de la ejecución de los scripts +// ________________________________________________________________________________________________________ +char* tbErroresScripts[]={"Se han generado errores desconocidos. No se puede continuar la ejecución de este módulo",\ + "001-Formato de ejecución incorrecto.",\ + "002-Fichero o dispositivo no encontrado",\ + "003-Error en partición de disco",\ + "004-Partición o fichero bloqueado",\ + "005-Error al crear o restaurar una imagen",\ + "006-Sin sistema operativo",\ + "007-Programa o función BOOLEAN no ejecutable",\ + "008-Error en la creación del archivo de eco para consola remota",\ + "009-Error en la lectura del archivo temporal de intercambio",\ + "010-Error al ejecutar la llamada a la interface de administración",\ + "011-La información retornada por la interface de administración excede de la longitud permitida",\ + "012-Error en el envío de fichero por la red",\ + "013-Error en la creación del proceso hijo",\ + "014-Error de escritura en destino",\ + "015-Sin Cache en el Cliente",\ + "016-No hay espacio en la cache para almacenar fichero-imagen",\ + "017-Error al Reducir el Sistema Archivos",\ + "018-Error al Expandir el Sistema Archivos",\ + "019-Valor fuera de rango o no válido.",\ + "020-Sistema de archivos desconocido o no se puede montar",\ + "021-Error en partición de caché local",\ + "022-El disco indicado no contiene una particion GPT",\ + "023-Error no definido",\ + "024-Error no definido",\ + "025-Error no definido",\ + "026-Error no definido",\ + "027-Error no definido",\ + "028-Error no definido",\ + "029-Error no definido",\ + "030-Error al restaurar imagen - Imagen mas grande que particion",\ + "031-Error al realizar el comando updateCache",\ + "032-Error al formatear",\ + "033-Archivo de imagen corrupto o de otra versión de partclone",\ + "034-Error no definido",\ + "035-Error no definido",\ + "036-Error no definido",\ + "037-Error no definido",\ + "038-Error no definido",\ + "039-Error no definido",\ + "040-Error imprevisto no definido",\ + "041-Error no definido",\ + "042-Error no definido",\ + "043-Error no definido",\ + "044-Error no definido",\ + "045-Error no definido",\ + "046-Error no definido",\ + "047-Error no definido",\ + "048-Error no definido",\ + "049-Error no definido",\ + "050-Error en la generación de sintaxis de transferenica unicast",\ + "051-Error en envio UNICAST de una particion",\ + "052-Error en envio UNICAST de un fichero",\ + "053-Error en la recepcion UNICAST de una particion",\ + "054-Error en la recepcion UNICAST de un fichero",\ + "055-Error en la generacion de sintaxis de transferenica Multicast",\ + "056-Error en envio MULTICAST de un fichero",\ + "057-Error en la recepcion MULTICAST de un fichero",\ + "058-Error en envio MULTICAST de una particion",\ + "059-Error en la recepcion MULTICAST de una particion",\ + "060-Error en la conexion de una sesion UNICAST|MULTICAST con el MASTER",\ + "061-Error no definido",\ + "062-Error no definido",\ + "063-Error no definido",\ + "064-Error no definido",\ + "065-Error no definido",\ + "066-Error no definido",\ + "067-Error no definido",\ + "068-Error no definido",\ + "069-Error no definido",\ + "070-Error al montar una imagen sincronizada.",\ + "071-Imagen no sincronizable (es monolitica).",\ + "072-Error al desmontar la imagen.",\ + "073-No se detectan diferencias entre la imagen basica y la particion.",\ + "074-Error al sincronizar, puede afectar la creacion/restauracion de la imagen.",\ + "Error desconocido " + }; + #define MAXERRORSCRIPT 74 // Error máximo cometido +// ________________________________________________________________________________________________________ +// Prototipo de funciones +// ________________________________________________________________________________________________________ +BOOLEAN autoexecCliente(TRAMA*); +BOOLEAN RESPUESTA_AutoexecCliente(TRAMA*); +void procesaComandos(TRAMA*); + +BOOLEAN tomaConfiguracion(char*); +BOOLEAN tomaIPlocal(void); +void scriptLog(const char *,int ); + +BOOLEAN gestionaTrama(TRAMA *); +BOOLEAN inclusionCliente(); +char* LeeConfiguracion(); +BOOLEAN RESPUESTA_InclusionCliente(TRAMA *); + +BOOLEAN comandosPendientes(TRAMA*); +BOOLEAN NoComandosPtes(TRAMA *); + +BOOLEAN respuestaEjecucionComando(TRAMA *,int,char*); +BOOLEAN Sondeo(TRAMA *); +BOOLEAN Actualizar(TRAMA *); +int Purgar(TRAMA* ); + +BOOLEAN ConsolaRemota(TRAMA*); + +BOOLEAN Arrancar(TRAMA *); +BOOLEAN Apagar(TRAMA *); +BOOLEAN Reiniciar(TRAMA *); +BOOLEAN IniciarSesion(TRAMA *); +BOOLEAN CrearImagen(TRAMA *); +BOOLEAN CrearImagenBasica(TRAMA *); +BOOLEAN CrearSoftIncremental(TRAMA*); + +BOOLEAN InventarioHardware(TRAMA *); +BOOLEAN InventariandoSoftware(TRAMA *,BOOLEAN,char*); +BOOLEAN EjecutarScript(TRAMA *); +BOOLEAN ejecutaArchivo(char*,TRAMA*); + +BOOLEAN cuestionCache(char*); +int cargaPaginaWeb(char *); +void muestraMenu(void); +void muestraMensaje(int idx,char*); + +BOOLEAN enviaMensajeServidor(SOCKET *,TRAMA *,char); + + + + diff --git a/sources/clients/ogAdmClient/sources/ogAdmClient.o b/sources/clients/ogAdmClient/sources/ogAdmClient.o new file mode 100644 index 0000000000000000000000000000000000000000..e8bec648fc91775dbf0b298384526615646aa621 GIT binary patch literal 108604 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