Você pode alterar o que um link simbólico aponta depois que ele é criado?

122

Algum sistema operacional fornece um mecanismo (chamada do sistema - não programa de linha de comando) para alterar o nome do caminho referenciado por um link simbólico (link simbólico) - além de desvincular o antigo e criar um novo?

O padrão POSIX não. O Solaris 10 não. O MacOS X 10.5 (Leopard) não. (Estou toleravelmente certo de que nem o AIX nem o HP-UX também. A julgar pela lista de chamadas do sistema Linux, o Linux também não possui essa chamada.)

Existe alguma coisa que faz?

(Espero que a resposta seja "Não".)


Como provar que é negativo é difícil, vamos reorganizar a questão.

Se você souber que algum sistema operacional (semelhante ao Unix) ainda não listado não possui nenhuma chamada de sistema para reescrever o valor de um link simbólico (a string retornada por readlink()) sem remover o link simbólico antigo e criar um novo, adicione-o - ou eles - em uma resposta.

Jonathan Leffler
fonte
O que há de errado em simplesmente religar? Por que não apenas emitir o lncomando (ou a API equiavalente) substituindo o link antigo? Qual problema você está tendo?
S.Lott
9
Engraçado - estou perguntando se há uma chamada do sistema para realizar um trabalho de programação, e a pergunta está sendo marcada como 'pertence a outro site'.
23611 Jonathan Leffler
3
Engraçado - não estava absolutamente claro que você estava procurando uma chamada do sistema e acabou de editar a pergunta para adicionar esse detalhe. Então, como você pode esperar que as pessoas deduzam algo antes mesmo de escrever?
Pascal Thivent 23/09/09
2
@ S.Lott: Estou escrevendo um artigo sobre segurança e links simbólicos. A certa altura, faço a afirmação "o proprietário, o grupo, as permissões no link simbólico são irrelevantes" e o raciocínio é que o proprietário do link simbólico pode apenas removê-lo e não alterar o valor. Estou verificando novamente que não há outra maneira senão removendo o link simbólico de obter o efeito de 'reescrever o valor do link simbólico'. Estou ignorando o acesso direto ao disco bruto e hackeando o FS dessa maneira - requer privilégios de root e minhas preocupações são com usuários não root, não com o que o root pode fazer.
23611 Jonathan Leffler
4
@ Pascal: me desculpe - eu não percebi que não estava claro que eu estava falando sobre chamadas de sistema até que as pessoas tocaram uma tangente do que eu pretendia (o que era evidentemente diferente do que eu disse). Sinto muito por ter enganado; não foi intencional.
23611 Jonathan Leffler

Respostas:

106

AFAIK, não, você não pode. Você precisa removê-lo e recriá-lo. Na verdade, você pode sobrescrever um link simbólico e, assim, atualizar o nome do caminho mencionado por ele:

$ ln -s .bashrc test
$ ls -al test
lrwxrwxrwx 1 pascal pascal 7 2009-09-23 17:12 test -> .bashrc
$ ln -s .profile test
ln: creating symbolic link `test': File exists
$ ln -s -f .profile test
$ ls -al test
lrwxrwxrwx 1 pascal pascal 8 2009-09-23 17:12 test -> .profile

EDIT : Como o OP apontou em um comentário, o uso da --forceopção fará lnuma chamada de sistema para unlink()antes symlink(). Abaixo, a saída da straceminha caixa linux provando:

$ strace -o /tmp/output.txt ln -s -f .bash_aliases test
$ grep -C3 ^unlink /tmp/output.txt 
lstat64("test", {st_mode=S_IFLNK|0777, st_size=7, ...}) = 0
stat64(".bash_aliases", {st_mode=S_IFREG|0644, st_size=2043, ...}) = 0
symlink(".bash_aliases", "test")        = -1 EEXIST (File exists)
unlink("test")                          = 0
symlink(".bash_aliases", "test")        = 0
close(0)                                = 0
close(1)                                = 0

Então eu acho que a resposta final é "não".

EDIT : O seguinte é copiado da resposta de Arto Bendiken em unix.stackexchange.com, por volta de 2016.

Na verdade, isso pode ser feito atomicamente rename(2), criando primeiro o novo link simbólico com um nome temporário e depois substituindo de maneira limpa o link simbólico antigo de uma só vez. Como a página do manual afirma:

Se newpath se referir a um link simbólico, o link será substituído.

No shell, você faria isso da mv -Tseguinte maneira:

$ mkdir a b
$ ln -s a z
$ ln -s b z.new
$ mv -T z.new z

Você pode straceexecutar esse último comando para garantir que ele esteja realmente sendo usado por rename(2)baixo do capô:

$ strace mv -T z.new z
lstat64("z.new", {st_mode=S_IFLNK|0777, st_size=1, ...}) = 0
lstat64("z", {st_mode=S_IFLNK|0777, st_size=1, ...}) = 0
rename("z.new", "z")                    = 0

Observe que, acima, ambos mv -Te stracesão específicos do Linux.

No FreeBSD, use mv -halternadamente.

Nota do editor: É assim que Capistrano faz isso há anos, desde ~ 2.15. Veja esta solicitação de recebimento .

Pascal Thivent
fonte
2
A opção '-f' força 'ln' a fazer as chamadas do sistema unlink () e symlink ()?
23611 Jonathan Leffler
1
Faz. Mas a pergunta pode ter sido percebida como "como faço isso em uma única etapa" e depois se resume à definição de "etapa" - linha de comando? syscall?
Michael Krelin - hacker 23/09/09
1
Eu só notei que você adicionou texto syscall à sua pergunta ;-)
Michael Krelin - hacker de
2
@ Pascal: faz. No Solaris, a saída de 'truss ln -spx' e 'truss ln -s -fpx' mostra uma chamada unlink () antes da chamada symlink () no segundo caso (e uma chamada symlink () com falha no primeiro). Eu esperaria que isso se aplicasse à maioria, senão a todas as variantes do Unix.
23611 Jonathan Leffler
12
Marcar como +1 no comentário do @Taai - se estiver lidando com um link simbólico que desreferencia (aponta para) um diretório, você precisa especificar "-n" para garantir que esse truque funcione.
wally
161

Sim você pode!

$ ln -sfn source_file_or_directory_name softlink_name
Taai
fonte
9
Obrigado por responder. A -fopção significa 'remover o destino existente' antes de criar o novo. Portanto, esse comando alcança o resultado, mas unlink(2)seguindo seguido por symlink(2). Não era disso que se tratava a pergunta original. Observe também que a resposta aceita e a próxima resposta mais votada usam ln -sfpara fazer o trabalho, mas, como stracemostra a saída, sim unlink()e symlink()porque não há uma chamada de sistema para modificar um link simbólico.
31416 Jonathan Leffler
17
O -n parece ser necessário quando o link original vai para um diretório em vez de um arquivo.
precisa
11
O interruptor 'n' é importante. Lutei com o problema de que o link simbólico não era atualizado, mas o comando criou outro link dentro do existente, porque a opção 'no drefencing' não estava definida.
Jonathan Gruber
14

Não é necessário desvincular explicitamente o link simbólico antigo. Você consegue fazer isso:

ln -s newtarget temp
mv temp mylink

(ou use o link simbólico equivalente e renomeie as chamadas). Isso é melhor do que desvincular explicitamente porque a renomeação é atômica, portanto, você pode ter certeza de que o link sempre apontará para o destino antigo ou novo. No entanto, isso não reutilizará o inode original.

Em alguns sistemas de arquivos, o destino do link simbólico é armazenado no próprio inode (no lugar da lista de bloqueios), se for curto o suficiente; isso é determinado no momento em que é criado.

Com relação à afirmação de que o proprietário e o grupo são irrelevantes, o link simbólico (7) no Linux diz que há um caso em que é significativo:

O proprietário e o grupo de um link simbólico existente podem ser alterados usando lchown (2). O único momento em que a propriedade de um link simbólico é importante é quando o link está sendo removido ou renomeado em um diretório com o bit fixo definido (consulte stat (2)).

Os carimbos de data e hora do último acesso e da última modificação de um link simbólico podem ser alterados usando utimensat (2) ou lutimes (3).

No Linux, as permissões de um link simbólico não são usadas em nenhuma operação; as permissões são sempre 0777 (leitura, gravação e execução para todas as categorias de usuário) e não podem ser alteradas.

mark4o
fonte
@ mark4o: The Good - A referência a lchown () e propriedade em um diretório pegajoso é útil - obrigado. Eu conhecia lchown () e não era material para minha tese. Eu também conhecia diretórios de bits fixos; Eu acho que a propriedade é quase uma conseqüência padrão das regras - a diferença e, presumivelmente, por que é chamada, é que normalmente você pode remover um arquivo se puder escrever nele e, nominalmente, qualquer um pode escrever em um link simbólico, porque das 777 permissões, mas, neste caso, as regras são ligeiramente diferentes.
24611 Jonathan Leffler
1
@ mark4o: The Not So Good - a sequência de comandos mostrada não faz o que você pensa que faz (pelo menos no cenário:) set -x -e; mkdir junk; ( cd junk; mkdir olddir newdir; ln -s olddir mylink; ls -ilR; ln -s newdir temp; ls -ilR; mv temp mylink; ls -ilR; ); rm -fr junk. Se você criar arquivos oldfile e newfile em vez de diretórios e executar o script equivalente (principalmente alterando olddir para oldfile, newdir para newfile), obterá o efeito esperado. Apenas uma complexidade extra! Obrigado pela resposta.
24611 Jonathan Leffler
2

Apenas um aviso para as respostas corretas acima:

O uso do método -f / --force oferece risco de perda do arquivo se você misturar origem e destino:

mbucher@server2:~/test$ ls -la
total 11448
drwxr-xr-x  2 mbucher www-data    4096 May 25 15:27 .
drwxr-xr-x 18 mbucher www-data    4096 May 25 15:13 ..
-rw-r--r--  1 mbucher www-data 4109466 May 25 15:26 data.tar.gz
-rw-r--r--  1 mbucher www-data 7582480 May 25 15:27 otherdata.tar.gz
lrwxrwxrwx  1 mbucher www-data      11 May 25 15:26 thesymlink -> data.tar.gz
mbucher@server2:~/test$ 
mbucher@server2:~/test$ ln -s -f thesymlink otherdata.tar.gz 
mbucher@server2:~/test$ 
mbucher@server2:~/test$ ls -la
total 4028
drwxr-xr-x  2 mbucher www-data    4096 May 25 15:28 .
drwxr-xr-x 18 mbucher www-data    4096 May 25 15:13 ..
-rw-r--r--  1 mbucher www-data 4109466 May 25 15:26 data.tar.gz
lrwxrwxrwx  1 mbucher www-data      10 May 25 15:28 otherdata.tar.gz -> thesymlink
lrwxrwxrwx  1 mbucher www-data      11 May 25 15:26 thesymlink -> data.tar.gz

Claro que isso é intencional, mas geralmente ocorrem erros. Portanto, excluir e recriar o link simbólico é um pouco mais trabalhoso, mas também um pouco mais econômico:

mbucher@server2:~/test$ rm thesymlink && ln -s thesymlink otherdata.tar.gz 
ln: creating symbolic link `otherdata.tar.gz': File exists

que pelo menos mantém meu arquivo.

Markus Bucher
fonte
Usar uma opção -fou --forceé sempre um pouco perigoso; presume que o usuário saiba do que se trata. É duplamente letal se você usá-lo habitualmente ( rm -fr …toda vez que é perigoso).
Jonathan Leffler
1

Não desvinculá-lo e criar o novo faria a mesma coisa no final?

matt b
fonte
2
Por que desvincular em primeiro lugar? Por que não simplesmente substituí-lo?
S.Lott
5
O resultado líquido é aproximadamente o mesmo - mas o proprietário e o grupo e os últimos tempos de modificação (e provavelmente o número do inode) seriam todos diferentes, em geral.
23611 Jonathan Leffler
2
@ S.Lott: qual chamada de sistema 'sobrescreve'? No POSIX, não existe essa chamada. No Solaris e no MacOS X, não existe essa ligação. Existe uma chamada para fazer isso no ... Linux, AIX, HP-UX, qualquer outra coisa que se pareça com o Unix? O Windows realmente não possui links simbólicos da mesma maneira, AFAICT, portanto não é crítico para minha análise - mas informações sobre a API equivalente do Windows seriam úteis.
23611 Jonathan Leffler
@ Jonathan Leffler: Ummm .... o ln --forcecomando substituirá absolutamente um link existente.
S.Lott
Gente, acho que você está falando com propósitos diferentes. S.Lott está discutindo um executável ln (1), enquanto mate b. está discutindo o fato de que symlink (2)se não apoiar a substituição. Vocês dois estão certos, e eu sugeriria que analisar a implementação ln (1)daria a maneira mais idiomática de realizar o procedimento de desassociação / desassociação.
dmckee --- ex-moderador gatinho
0

Caso isso ajude: existe uma maneira de editar um link simbólico com o comandante da meia-noite (mc). O comando do menu é (em francês na minha interface mc):

Fichier / Éditer le lien symbolique

que pode ser traduzido para:

File / Edit symbolic link

O atalho é Cx Cs

Talvez ele use internamente o ln --forcecomando, não sei.

Agora, estou tentando encontrar uma maneira de editar vários links simbólicos de uma só vez (foi assim que cheguei aqui).

Pierre
fonte
1
Você verificou o que MC faz nos bastidores? Eu colocaria chances de que, na verdade, ele faz um unlink()seguido de um symlink(), simplesmente porque é isso que os sistemas semelhantes ao Unix fornecem.
Jonathan Leffler 07/07
Não, eu não verifiquei. E sim, é bem provável que o faça como você diz, de fato. O fato de eu editar uma caixa de texto dá a sensação de que estou realmente editando o destino do link simbólico, mas provavelmente fui enganado ...
Pierre
0

Tecnicamente, não há comando interno para editar um link simbólico existente. Pode ser facilmente alcançado com alguns comandos curtos.

Aqui está uma pequena função bash / zsh que escrevi para atualizar um link simbólico existente:

# -----------------------------------------
# Edit an existing symbolic link
#
# @1 = Name of symbolic link to edit
# @2 = Full destination path to update existing symlink with 
# -----------------------------------------
function edit-symlink () {
    if [ -z "$1" ]; then
        echo "Name of symbolic link you would like to edit:"
        read LINK
    else
        LINK="$1"
    fi
    LINKTMP="$LINK-tmp"
    if [ -z "$2" ]; then
        echo "Full destination path to update existing symlink with:"
        read DEST
    else
        DEST="$2"
    fi
    ln -s $DEST $LINKTMP
    rm $LINK
    mv $LINKTMP $LINK
    printf "Updated $LINK to point to new destination -> $DEST"
}
blizzrdof77
fonte
2
Obrigado pelo esforço. Isso não atende ao meu requisito de ser uma chamada do sistema em linguagem C. Existem várias maneiras de alterar um link, desde que você tenha permissão de gravação no diretório que contém o link (o que isso exige). Ainda não há maneiras que eu saiba de alterar o valor de um link simbólico sem fazer unlink()e symlink()com o novo valor, que é o que acontece nos bastidores com seu código. Pessoalmente, eu teria a função insistir em exatamente dois (ou talvez um múltiplo de dois) argumentos e fiança se a invocação não estivesse correta. Essa é uma perspectiva particular, no entanto.
27617 Jonathan