¿Qué recurso tiene uno para esto?
El hecho de que GLIBC no tuviera forma de #define USE_FCNTL_NOT_FCNTL64
decir mucho. Sea correcto o incorrecto, la mayoría de los fabricantes de cadenas de herramientas de OS + parecen haber decidido que apuntar a los archivos binarios para versiones anteriores de sus sistemas desde uno nuevo no es una alta prioridad.
El camino de menor resistencia es mantener una máquina virtual alrededor de la cadena de herramientas OS + más antigua que construye su proyecto. Use eso para hacer binarios cada vez que piense que los binarios se ejecutarán en un sistema antiguo.
Pero...
- Si cree que sus usos están en el subconjunto de llamadas fcntl () que no se ven afectadas por el cambio de tamaño de desplazamiento (es decir, no utiliza bloqueos de rango de bytes)
- O están dispuestos a examinar su código para que los casos de desplazamiento utilicen una definición de estructura compatible con versiones anteriores
- Y no tienen miedo al vudú
... entonces sigue leyendo.
El nombre es diferente, y fcntl es variable sin un vffcntl que toma una va_list. En tales situaciones, no puede reenviar una invocación de una función variadic.
... luego, para aplicar el truco de ajuste mencionado , debe ir línea por línea a través de la documentación de la interfaz de fcntl (), desempaquetar la variadic como lo haría y luego llamar a la versión envuelta con una nueva invocación variadic.
Afortunadamente, no es un caso tan difícil (fcntl toma 0 o 1 argumentos con tipos documentados). Para intentar salvar a alguien más de algún problema, aquí hay un código para eso. Asegúrese de pasar --wrap = fcntl64 al enlazador ( -Wl, - wrap = fcntl64 si no está llamando a ld directamente):
asm (".symver fcntl64, fcntl@GLIBC_2.2.5");
extern "C" int __wrap_fcntl64(int fd, int cmd, ...)
{
int result;
va_list va;
va_start(va, cmd);
switch (cmd) {
//
// File descriptor flags
//
case F_GETFD: goto takes_void;
case F_SETFD: goto takes_int;
// File status flags
//
case F_GETFL: goto takes_void;
case F_SETFL: goto takes_int;
// File byte range locking, not held across fork() or clone()
//
case F_SETLK: goto takes_flock_ptr_INCOMPATIBLE;
case F_SETLKW: goto takes_flock_ptr_INCOMPATIBLE;
case F_GETLK: goto takes_flock_ptr_INCOMPATIBLE;
// File byte range locking, held across fork()/clone() -- Not POSIX
//
case F_OFD_SETLK: goto takes_flock_ptr_INCOMPATIBLE;
case F_OFD_SETLKW: goto takes_flock_ptr_INCOMPATIBLE;
case F_OFD_GETLK: goto takes_flock_ptr_INCOMPATIBLE;
// Managing I/O availability signals
//
case F_GETOWN: goto takes_void;
case F_SETOWN: goto takes_int;
case F_GETOWN_EX: goto takes_f_owner_ex_ptr;
case F_SETOWN_EX: goto takes_f_owner_ex_ptr;
case F_GETSIG: goto takes_void;
case F_SETSIG: goto takes_int;
// Notified when process tries to open or truncate file (Linux 2.4+)
//
case F_SETLEASE: goto takes_int;
case F_GETLEASE: goto takes_void;
// File and directory change notification
//
case F_NOTIFY: goto takes_int;
// Changing pipe capacity (Linux 2.6.35+)
//
case F_SETPIPE_SZ: goto takes_int;
case F_GETPIPE_SZ: goto takes_void;
// File sealing (Linux 3.17+)
//
case F_ADD_SEALS: goto takes_int;
case F_GET_SEALS: goto takes_void;
// File read/write hints (Linux 4.13+)
//
case F_GET_RW_HINT: goto takes_uint64_t_ptr;
case F_SET_RW_HINT: goto takes_uint64_t_ptr;
case F_GET_FILE_RW_HINT: goto takes_uint64_t_ptr;
case F_SET_FILE_RW_HINT: goto takes_uint64_t_ptr;
default:
fprintf(stderr, "fcntl64 workaround got unknown F_XXX constant")
}
takes_void:
va_end(va);
return fcntl64(fd, cmd);
takes_int:
result = fcntl64(fd, cmd, va_arg(va, int));
va_end(va);
return result;
takes_flock_ptr_INCOMPATIBLE:
//
// !!! This is the breaking case: the size of the flock
// structure changed to accommodate larger files. If you
// need this, you'll have to define a compatibility struct
// with the older glibc and make your own entry point using it,
// then call fcntl64() with it directly (bear in mind that has
// been remapped to the old fcntl())
//
fprintf(stderr, "fcntl64 hack can't use glibc flock directly");
exit(1);
takes_f_owner_ex_ptr:
result = fcntl64(fd, cmd, va_arg(va, struct f_owner_ex*));
va_end(va);
return result;
takes_uint64_t_ptr:
result = fcntl64(fd, cmd, va_arg(va, uint64_t*));
va_end(va);
return result;
}
Tenga en cuenta que, dependiendo de la versión en la que esté desarrollando, es posible que tenga que #desdefinir algunas de esas secciones de bandera si no están disponibles.
Esto afecta a una gran variedad de aplicaciones ... la página del manual para fcntl () muestra que es el punto de entrada para un pequeño universo de subfunciones
... y probablemente debería ser una lección para las personas: evite crear tales funciones de "fregadero de la cocina" a través del abuso variable.
fcntl64()
, ¿se introducirán errores al acceder a archivos de más de 2 GB? La única forma de saber es hacer una prueba de regresión completa de todos losfcntl()
usos. mantenga una máquina virtual alrededor de la cadena de herramientas OS + más antigua que construya su proyecto ESA es la respuesta real y la OMI debe estar al frente.Compilar contra una versión anterior de
libc
. Período.Debido a que glibc no es compatible con versiones anteriores , solo es compatible con versiones anteriores :
Sin ninguna garantía de compatibilidad hacia adelante, no sabes qué más no funcionará correctamente .
fuente