obtener posicion en un file descriptor??

Daniel Serpell dserpell en gmail.com
Sab Ene 31 21:44:58 CLST 2009


Hola!

El Sat, Jan 31, 2009 at 07:26:51PM -0300, Rodrigo Ahumada escribio:
> Daniel Serpell escribió:
>>
>> Lo que yo hago normalmente es utilizar 'dd' en medio, de la siguiente
>> manera:
>>
>>  cat /mi/archivo/grande | dd | algoQueHacer
>>
>> Luego, le puedes mandar una señal SIGUSR1 al dd para que muestre el estado
>> de la copia (por ejemplo, con "kill -USR1 $(pgrep dd)".)
>
> No se si será posible: si el programa que se quiere monitorear usa  
> fwrite o write para escribir, se tiene el código fuente como para estar  
> seguro de eso, se podría hacer una .so con la función fwrite o write  
> reescrita para que tire cada cierto avance, la posicion en el archivo, a  
> un archivo en /tmp..., y luego lanzar el programa haciendo que cargue el  
> .so antes que las libc....

Oh, claro que es posible, mira este ejemplo, compila con
  gcc -shared -fPIC -O2 -Wall -o dwrite.so dwrite.c

Y luego lo usas como:
  LD_PRELOAD=./dwrite.so:/lib/libdl.so.2 cat /some/big/file > /dev/null

El problema es que no resuelve la pregunta original, ya que el parche de
biblioteca se debe aplicar *antes* de iniciar el programa.

Claro, uno podría mediante GDB inyectar código adicional en tiempo de
ejecución, pero eso es bastante complejo.

    Daniel.

//---------- dwrite.c -----------
#define _GNU_SOURCE
#include <unistd.h>
#include <errno.h>
#include <dlfcn.h>
#include <string.h>
#include <stdio.h>

ssize_t write(int fd, const void *buf, size_t count)
{
    static ssize_t (*libc_write)(int, const void *, size_t) = 0;
    static ssize_t write_pos = 0, pos = 0;
    ssize_t r;

    // Get libc write function address.
    if( !libc_write )
        libc_write = dlsym(RTLD_NEXT, "write");

    // Call libc write.
    r = libc_write(fd,buf,count);

    // If FD == 1 (stdout), output to FD 2 (stderr) the current position
    if( fd == 1 )
    {
        // store errno
        int saved_errno = errno;
        if( r == -1 )
            write(2,"Error\n",6);
        else
        {
            pos += r;
            if( pos > write_pos )
            {
                char buf[48];
                snprintf(buf,48,"stdout:%ld\n",pos);
                write(2,buf,strlen(buf));
                // Write only after 1000000 bytes
                write_pos = pos + 1000000;
            }
        }
        errno = saved_errno;
    }
    return r;
}
// ------------ end -----------




Más información sobre la lista de distribución Linux