Que recurso se tem para isso?
O fato de o GLIBC não ter muito a #define USE_FCNTL_NOT_FCNTL64
dizer diz muito. Seja certo ou errado, a maioria dos fabricantes de cadeias de ferramentas do OS + parece ter decidido que direcionar binários para versões mais antigas de seus sistemas a partir de uma mais nova não é uma alta prioridade.
O caminho de menor resistência é manter uma máquina virtual em torno da cadeia de ferramentas OS + mais antiga que cria seu projeto. Use isso para criar binários sempre que achar que o binário será executado em um sistema antigo.
Mas...
- Se você acredita que seus usos estão no subconjunto de chamadas fcntl () que não são afetadas pela alteração do tamanho do deslocamento (ou seja, você não usa bloqueios de intervalo de bytes)
- OU estão dispostos a verificar seu código nos casos de compensação para usar uma definição de estrutura compatível com versões anteriores
- E não têm medo de vodu
... então continue lendo.
O nome é diferente e fcntl é variável sem um vffcntl que leva uma va_list. Em tais situações, você não pode encaminhar uma invocação de uma função variável.
... para aplicar o truque de empacotamento mencionado , você deve passar linha por linha pela documentação da interface de fcntl (), descompactar a variável como seria e, em seguida, chamar a versão empacotada com uma nova chamada variável.
Felizmente, não é um caso tão difícil (fcntl recebe 0 ou 1 argumentos com tipos documentados). Para tentar poupar a alguém mais problemas, aqui está o código para isso. Certifique-se de passar --wrap = fcntl64 para o vinculador ( -Wl, - wrap = fcntl64 se não estiver chamando ld diretamente):
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;
}
Observe que, dependendo da versão em que você está realmente construindo, talvez seja necessário #ifdef algumas dessas seções de sinalizador, se não estiverem disponíveis.
Isso afeta diversas aplicações ... a página de manual do fcntl () mostra que é o ponto de entrada para um pequeno universo de sub-funções
... e provavelmente deve ser uma lição para as pessoas: evite criar essas funções de "pia da cozinha" por meio de abusos variados.
fcntl64()
, agora haverá erros introduzidos ao acessar arquivos maiores que 2 GB? A única maneira de saber é fazer um teste de regressão completo de todos osfcntl()
usos. manter uma máquina virtual em torno dos mais antigos OS + toolchain que constrói seu projeto QUE é a resposta real e IMO deve estar na frente.Compile em uma versão mais antiga do
libc
. Período.Como o glibc não é compatível com versões anteriores , é apenas compatível com versões anteriores :
Sem garantias de compatibilidade com a frente, você não sabe o que mais não funcionará corretamente .
fonte