Por que useradd se recusa a abrir um link simbólico /etc/passwd ?
Para responder a pergunta, precisamos dar uma olhada no código-fonte de useradd (eu fiz isso no Ubuntu 12.04, no Debian ele pode ser um pouco diferente):
-
Descubra qual pacote possui
/usr/sbin/useradd:$ dpkg-query -S /usr/sbin/useradd passwd: /usr/sbin/useradd -
Instale a fonte:
$ apt-get source passwd Reading package lists... Done Building dependency tree Reading state information... Done Picking 'shadow' as source package instead of 'passwd' (...) dpkg-source: info: extracting shadow in shadow-4.1.4.2+svn3283 dpkg-source: info: unpacking shadow_4.1.4.2+svn3283.orig.tar.gz dpkg-source: info: applying shadow_4.1.4.2+svn3283-3ubuntu5.1.diff.gz (...) -
cdno diretório de origem:$ cd shadow-4.1.4.2+svn3283/ -
Pesquise no diretório o arquivo de origem de
useradd, que idealmente deve ser chamado deuseradd.c:$ find . -name useradd.c ./src/useradd.cBingo!
-
Procure a mensagem de erro
cannot open /etc/passwd(na verdade, só pesquisocannot open, pois a string inteira não retorna nenhum resultado):$ grep -B 1 'cannot open' src/useradd.c (...) if (pw_open (O_RDWR) == 0) { fprintf (stderr, _("%s: cannot open %s\n"), Prog, pw_dbname ()); (...)-B 1significa imprimir 1 linha do contexto principal antes da linha correspondente.Aqui é onde a mensagem de erro que você vê está sendo gerada. A função
pw_opencontrola se/etc/passwdpode ser aberto ou se deve ser gerado um erro.pw_opennão é um syscall do Linux (apropos pw_opennão retorna nenhum resultado), então é provavelmente implementado dentro deste pacote. Vamos procurar por isso. -
Rastrear
pw_openleva a:$ grep -R pw_open * (...) lib/pwio.c:int pw_open (int mode) (...)A implementação
pw_opené:$ grep -A 3 'int pw_open (int mode)' lib/pwio.c int pw_open (int mode) { return commonio_open (&passwd_db, mode); }Chegando mais perto, mas ainda não chegamos lá.
commonio_opené o nosso novo objetivo. -
Pesquise
commonio_open:$ grep -R commonio_open * (...) lib/commonio.c:int commonio_open (struct commonio_db *db, int mode) -
Abra
lib/commonio.ce role para a funçãocommonio_open:int commonio_open (struct commonio_db *db, int mode) { (...) fd = open (db->filename, (db->readonly ? O_RDONLY : O_RDWR) | O_NOCTTY | O_NONBLOCK | O_NOFOLLOW);Você vê
O_NOFOLLOW? Este é o culpado (deman 2 open):O_NOFOLLOW If pathname is a symbolic link, then the open fails.
Resumindo, useradd.c usa pw_open , que por sua vez usa commonio_open , que abre /etc/passwd usando syscall open com a opção O_NOFOLLOW , que rejeita links simbólicos.
Embora um symlink possa ser usado como um substituto de um arquivo em muitas (eu diria a maioria) situações, useradd é bastante exigente e o rejeita, provavelmente porque um /etc/passwd com link simbólico sugere strongmente que /etc tem foi adulterado.
Por que devo deixar o passwd em /etc ?
Existem vários arquivos em /etc necessários para inicializar e fazer login, por exemplo (mas não limitados a): fstab , inittab , passwd , shadow e os scripts de inicialização em init.d/ . Qualquer sysadmin espera que esses arquivos estejam lá, não ligados simbolicamente a /home ou a qualquer lugar.
Então, mesmo que você pudesse, você deveria deixar passwd em /etc .
Além disso, a estrutura do sistema de arquivos no Linux é bem definida, dê uma olhada aqui: link . Há também um capítulo para /etc . Não é recomendável mudar as coisas.