Algunas dudas con las llamadas al sistema

Imagen de thepunishercadiz
0 puntos

Estoy un poco desesperado. Debo entregar una práctica de llamadas al sistema y manejo de señales en C y no se por donde tirar. Y he encontrado este foro que espero me sirva de ayuda.

Únicamente me faltan dos cosillas:

1. ¿Cómo leer un fichero binario hacia atrás con read?
con lseek me posiciono al final pero ¿qué debo hacer para ir leyendo del final al principio?

2.Tengo que abrir un fichero para escritura, pero antes debo hacer la comprobación de que exista previamente:

int f_resultado;

if (resultado = (open("resultado.dat",O_WRONLY|O_CREAT,0600)) < 0)

/*el fichero ya existe*/
/*mostrar por la salida estandar "el fichero ya existe*/
perror ("fichero existente");

/*bloquear el programa*/
pause();

/*el programa debe desbloquearse con SIGUSR1 Y SIGUSR2*/
/*si se recibe SIGUSR1 se ejecuta el programa y se reescribe el fichero con datos nuevos*/
/*mostrar por la salida estandar "se ha reescrito". */
/*y se acaba el programa*/

/*si se recibe SIGUSR2 no se modifica el fichero*/
/*y salida estandar "no se ha hecho nada". */
/*y se acaba el programa*/

Debo enviar las señales con kill desde la consola, ¿de qué manera puedo hacer el manejo de señales?

Os agradezco por adelantado vuestra atención.
Un cordial saludo.

Imagen de chatuser
+1
0
-1

1. usa lseek() con un valor negativo en el desplazamiento. 

2. man kill 

----------
unzip, strip, touch, finger, mount, fsck, more, yes, unmount, sleep - my daily Unix command list

Sólo los peces muertos van a favor de la corriente
<º ))))><

+1
0
-1

----------
La ignorancia es el mejor negocio
Sólo los peces muertos van a favor de la corriente
<º)))<

Imagen de Bonzai
+1
0
-1

Para interceptar señales con un programa deberias usar trap, las más comunes so:

0 - Salida del Shell (por cualquier razón, incluido fin de archivo).

1 - Colgar.

2 - Interrupción.

3 - Quit (causa que el programa produzca un core dump).

9 - Kill (no puede ser parada ni ignorada).

15 - Terminate (señal por defecto generada por Kill)

+1
0
-1
Imagen de slap
+1
0
-1

Mira este post, ahí podrás ver cómo manejar señales desde c.

Saludos.
slap

+1
0
-1

Saludos.

0000 start out (+FD),A
           ld  BC, +7FFF
           jp 03CB, RAM-CHECK

http://www.injiniero.es

Imagen de thepunishercadiz
+1
0
-1

Estimado Slap.

No tengo manera de sacar la práctica, dejo aquí el código por si pudieras echarle un vistazo:

#include<fcntl.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<signal.h>
#include<string.h>
#include<stdio.h>
#include<stdlib.h>

void error (char *m) {
    write(2,m,strlen(m));
    write(2,"\n",1);
    write(2,strerror(errno),strlen(strerror(errno)));
    exit(1);
}
 
void quehagosigusr2 (int sig2){ /*gestor para determinar qué hacer en caso de que la señal recibida sea sigusr2*/

    printf("No voy a hacer nada con el fichero\n");
    fflush(stdout); /*limpio los restos que pudiera haber en el buffer de salida*/
}

void quehagosigusr1 (int sig1){ /*gestor para determinar qué hacer en caso de que la señal recibida sea sigusr1*/

    int data1, data2, resultado; /*punteros para tratar los ficheros*/
    int dato1, dato2,resul; /*los datos que leeré y escribiré en los ficheros*/
    int contamulti; /*aquí guardaré el número de multiplicaciones realizadas*/
    long index1, index2; /*me ayudarán a moverme por los ficheros, index1 hacia adelante, index2 hacia atrás*/
    char s [80]; /*cadena para formatear y mostrar posteriormente el número de operaciones realizadas*/

    /*compruebo que no hay problemas en los ficheros de lectura*/
    if ((data1 = open("data1.dat",O_RDONLY)) < 0)
        error("Fallo al abrir data1.dat");
    if ((data2= open("data2.dat",O_RDONLY)) < 0)
        error("Fallo al abrir data2.dat");
    /*voy a sobreescribir el fichero resultado.dat*/
    if((resultado=open("resultado.dat",O_WRONLY|O_CREAT|O_TRUNC,0600)) < 0)
        error("Hubo un problema al abrir el fichero para escribir");

        index1=lseek(data1,1,SEEK_SET); /*me posiciono al principio del primer fichero*/
            read(data1,&dato1,sizeof(dato1));
        index1 ++;
        index2 = lseek(data2,0,SEEK_END); /*me posiciono al final del segundo fichero para leerlo*/                                         /*al revés*/
        read(data2,&dato2,sizeof(dato2));
        index2 --;

        while ((index1 >=1) && (index2 >=0)) {
            resul = dato1*dato2;
            contamulti ++;
            write(resultado,&resul,sizeof(resul));
            read(data1,&dato1,sizeof(dato1));
            index1 ++;
            read(data2,&dato2,sizeof(dato2));
            index2 --;
        } /*while*/

        /*formateo la cadena previamente para mostrarla después por la salida estándar*/
        sprintf(s,"El número de multiplicaciones es: %d \n",contamulti);
        /*muestro el resultado por la salida estandar*/
        write(2,s,strlen(s));
        fflush(stdout); /*limpio el buffer de salida*/
        /*cierro todos los ficheros*/
        close(data1);
        close(data2);
        close(resultado);
               
}

int main() {

    int result;

    /*debo preguntar si el fichero de resultado existe previamente*/

    if ((result= open("resultado.dat",O_RDONLY)) > 0 ){ /*existe y no hago nada*/       
        error("fichero existente");   
        signal(SIGUSR2,quehagosigusr2); /*si mando sigusr2 no debo hacer nada*/
        pause();
        close(result);   
        exit(1);
    }
    else {
        signal(SIGUSR1,quehagosigusr1);    /*si mando sigusr1 tengo que sobreescribir el fichero*/   
        error("Voy a sobreescribir el fichero");
        pause();
    }
       
}   
 

+1
0
-1
Imagen de slap
+1
0
-1

Hola.
Me facilitaría las cosas que me indicaras qué es lo que te falla o funciona mal.

Saludos.
slap

+1
0
-1

Saludos.

0000 start out (+FD),A
           ld  BC, +7FFF
           jp 03CB, RAM-CHECK

http://www.injiniero.es

Imagen de slap
+1
0
-1

Lo que veo es que la lectura de los ficheros la haces mal.
Te dejo un ejemplo de como leer hacia atrás.

Ten en cuenta que depende de cómo estén grabados los datos en los ficheros se debe leer de una manera o de otra.

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(void){
    int d1, d2, r;
    int i;
    int dato1, dato2, res;

    if ((d1 = open("data1.dat",O_WRONLY|O_CREAT))<0){
        printf("Error al abrir data1.dat\n");
        exit(1);
    }
    else
        printf("Escribiendo en data1.dat\n");

    for (i=1;i<10;i++)
        write(d1,&i,sizeof(i));

    close(d1);

    if ((d2 = open("data2.dat",O_WRONLY|O_CREAT))<0){
        printf("Error al abrir data2.dat\n");
        exit(1);
    }
    else
        printf("Escribiendo en data2.dat\n");

    for (i=10;i<100;i+=10)
        write(d1,&i,sizeof(i));

    close(d2);

    if ((d1 = open("data1.dat",O_RDONLY))<0){
        printf("Error al abrir data1.dat\n");
        exit(1);
    }
    
    if ((d2 = open("data2.dat",O_RDONLY))<0){
        printf("Error al abrir data2.dat\n");
        exit(1);
    }

    if ((r = open("resultado.dat",O_WRONLY|O_CREAT))<0){
        printf("Error al abrir resultado.dat\n");
        exit(1);
    }

    // Nos posicionamos al principio del fichero data1.dat
    lseek(d1,0,SEEK_SET);

    // Nos posicionamos al final del fichero data2.dat
    lseek(d2,(-1)*sizeof(i),SEEK_END);

    while (read(d1,&dato1,sizeof(dato1))>0){
        read(d2,&dato2,sizeof(dato2));
        res=dato1*dato2;
        write(r,&res,sizeof(res));
        printf("Leo dato1: %d y dato2: %d y escribo res: %d\n",dato1,dato2,res);
        lseek(d2,(-2)*sizeof(i),SEEK_CUR);
    }
    close(r);
    close(d2);
    close(d1);
    exit (0);
}

Observa que después de leer d1, no es necesario hacer nada porque el puntero avanza automáticamente al siguiente dato. Pero al leer hacia atrás en d2 hay que reposicionar el puntero 2 enteros atrás (1: el que acabamos de leer y 2: el que vamos a leer).

Saludos.
slap

+1
0
-1

Saludos.

0000 start out (+FD),A
           ld  BC, +7FFF
           jp 03CB, RAM-CHECK

http://www.injiniero.es

Imagen de thepunishercadiz
+1
0
-1

 

 

Mira lo que me falla es lo siguiente. Resulta que debo comprobar que el fichero en donde almacenar el resultado debe existir previamente; si existe el programa debe mostrar "fichero existente", bloquearse con pause y esperar una señal:

si se recibe SIGUSR2, no se modifica nada y se acaba el programa

si se recibe SIGUSR1, se machaca el fichero existente con los datos nuevos y se acaba el programa mostrando el número de operaciones.

Las señales deben enviarse con kill desde la consola, precisamente esto es lo que no entiendo!!!

De nuevo muchisimas gracias por tu mensaje.

+1
0
-1
Imagen de thepunishercadiz
+1
0
-1

Mira slap, este es el asunto que te comentaba, de qué manera capturar las señales desde el teclado:

Aquí va el código con tu corrección de lectura de ficheros:

 

#include<fcntl.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<signal.h>
#include<string.h>
#include<stdio.h>
#include<stdlib.h>

void error (char *m) {
    write(2,m,strlen(m));
    write(2,"\n",1);
    write(2,strerror(errno),strlen(strerror(errno)));
    exit(1);
}
 
void quehagosigusr2 (int sig2){ /*gestor para determinar qué hacer en caso de que la señal recibida sea sigusr2*/
    char m [80];
    sprintf(m,"He recibido la señal: %d SIGUSR2, no voy a hacer nada con el fichero \n",sig2); /*formateo de cadena*/
    write(2,m,strlen(m)); /*muestro mensaje por la salida estándar*/
    fflush(stdout); /*limpio los restos que pudiera haber en el buffer de salida*/
}

void quehagosigusr1 (int sig1){ /*gestor para determinar qué hacer en caso de que la señal recibida sea sigusr1*/

    int data1, data2, resultado; /*punteros para tratar los ficheros*/
    int dato1, dato2,resul; /*los datos que leeré y escribiré en los ficheros*/
    int contamulti; /*aquí guardaré el número de multiplicaciones realizadas*/
    long index1, index2; /*me ayudarán a moverme por los ficheros, index1 hacia adelante, index2 hacia atrás*/
    char s [80]; /*cadena para formatear y mostrar posteriormente el número de operaciones realizadas*/

    /*aviso al usuario que voy a reescribir el fichero*/
    sprintf(s,"He recibido la señal: %d SIGUSR1, voy a reescribir el fichero \n",sig1); /*formateo de cadena*/
    write(2,s,strlen(s)); /*muestro mensaje por la salida estándar*/

    /*compruebo que no hay problemas en los ficheros de lectura*/
    if ((data1 = open("data1.dat",O_RDONLY)) < 0)
        error("Fallo al leer data1.dat");

    if ((data2= open("data2.dat",O_RDONLY)) < 0)
        error("Fallo al leer data2.dat");

    /*voy a sobreescribir el fichero resultado.dat*/
    if((resultado=open("resultado.dat",O_WRONLY|O_CREAT|O_TRUNC,0600)) < 0)
        error("Hubo un problema al abrir el fichero para escribir");

        lseek(data1,0,SEEK_SET); /*me posiciono al principio del primer fichero*/
            lseek(data2,(-1)*sizeof(int),SEEK_END); /*me posiciono al final del segundo fichero*/

        while (read(data1,&dato1,sizeof(dato1))>0){ /*leeré del data1 mientras no encuentre la marca de fin*/
                read(data2,&dato2,sizeof(dato2)); /*leo el dato del data 2*/
                resul=dato1*dato2;
            contamulti++; /*almaceno el número de operaciones realizadas*/
                write(resultado,&resul,sizeof(resul)); /*escribo el resultado en el fichero destino*/
               
            lseek(data2,(-2)*sizeof(int),SEEK_CUR);
            /*al leer hacia atrás en d2 hay que reposicionar el puntero*/                
            /*2 enteros atrás (1 por el que acabamos de leer y 2 por el que vamos a leer).*/
            }

        /*formateo la cadena previamente para mostrarla después por la salida estándar*/
        sprintf(s,"El número de operaciones realizadas es: %d \n",contamulti);
        /*muestro el resultado por la salida estandar*/
        write(2,s,strlen(s));
        fflush(stdout); /*limpio el buffer de salida*/
        /*cierro todos los ficheros*/
        close(data1);
        close(data2);
        close(resultado);
        exit(0);
               
}

int main(int argc, char * argv[]) {

    int result;
    int sig;

    if(argc == 2){
        /*debo preguntar si el fichero de resultado existe previamente*/
        if((result=open("resultado.dat",O_RDONLY)) >= 0 ){
            sig=atoi(argv[1]);
            close (result);
            if (sig == 12){
                signal(sig,quehagosigusr2); /*sigusr2 no debo hacer nada*/
                kill(getpid(),sig);
                exit(0);}
            if (sig == 10){
                signal(sig,quehagosigusr1);    /*sigusr1 tengo sobreescribir fichero*/                

                kill(getpid(),sig);
                exit(0);}
       
        }
       
    }   
    else
        error("La sintaxis del programa es ./programa 12 ó 10");   
   
}

 

El programa asume que el fichero ya existe, pero qué ocurre cuando no?

 

Gracias de nuevo. 

+1
0
-1
Imagen de pichon8
+1
0
-1

Hola:

   Soy nueva en esto de UNIX tengo que entregar una practica igual a la que he visto en el foro. Pero todavia no se como se hace las llamadas al sistema.

+1
0
-1
Imagen de slap
+1
0
-1

A ver...

El programa debe detectar si existe o no el fichero y enganchar con signal() la señal correspondiente al manejador que la gestiona.

Después debe quedar a la espera con pause()

Desde otro terminal tendrás que averiguar el (pid) del programa y enviarle la señal que quieras con:

kill -SIGUSR1 (pid)
ó
kill -SIGUSR2 (pid)

Editado: No salían bien los caracteres < y >

Saludos.
slap

+1
0
-1

Saludos.

0000 start out (+FD),A
           ld  BC, +7FFF
           jp 03CB, RAM-CHECK

http://www.injiniero.es