みなさん、「cd」コマンドって具体的になにやってるか分かりますか?ぼくはわかりません!!!……というわけでソースを読んでみます。※FreeBSDのshの中の"cd.c"を読みます。

##### bin/sh/cd.c
#### ざっくりと読む エントリポイントは「cdcmd」関数と思われるので、そこから徐々に下っていきます。
  • cdcmd ※エントリポイント、引数のパース
    • docd ※「cdlogical」と「cdphysical」を呼び出す。どちらかが成功すればおk
      • cdlogical
        • chdir(2) システムコール
        • updatepwd
      • cdphysical
        • chdir(2) システムコール
        • updatepwd
どうやら「cdlogical」と「cdphysical」がキモのようです。
辿ってみると、変数「pflag」の値によってどちらを呼び出すのか変わるみたいですが、中身はだいたい似ている感じなので一旦この違いは無視します。続いて、
  • chdir(2)
  • updatepwd
の中身を見ていきます。

#### chdir(2) とりあえず man 2 chdir します。 ``` CHDIR(2) FreeBSD System Calls Manual CHDIR(2)

NAME chdir, fchdir – change current working directory

LIBRARY Standard C Library (libc, -lc)

SYNOPSIS #include <unistd.h>

 int
 chdir(const char *path);

 int
 fchdir(int fd);
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
読んでみましたが具体的に何をやっているのかは正直良くわかりませんorz
```c
/*
 * Change current working directory (``.&#39;&#39;).
 */
#ifndef _SYS_SYSPROTO_H_
struct chdir_args {
	char	*path;
};
#endif
int
sys_chdir(td, uap)
	struct thread *td;
	struct chdir_args /* {
		char *path;
	} */ *uap;
{

	return (kern_chdir(td, uap->path, UIO_USERSPACE));
}

int
kern_chdir(struct thread *td, char *path, enum uio_seg pathseg)
{
	struct nameidata nd;
	int error;

	NDINIT(&amp;nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF | AUDITVNODE1,
	    pathseg, path, td);
	if ((error = namei(&amp;nd)) != 0)
		return (error);
	if ((error = change_dir(nd.ni_vp, td)) != 0) {
		vput(nd.ni_vp);
		NDFREE(&amp;nd, NDF_ONLY_PNBUF);
		return (error);
	}
	VOP_UNLOCK(nd.ni_vp, 0);
	NDFREE(&amp;nd, NDF_ONLY_PNBUF);
	pwd_chdir(td, nd.ni_vp);
	return (0);
}

/*
 * Change notion of root (``/&#39;&#39;) directory.
 */
#ifndef _SYS_SYSPROTO_H_
struct chroot_args {
	char	*path;
};
#endif

```<br/>
 

</div>
<div class="section">
    #### updatepwd
    ※該当箇所抜き出し
```c
/*
 * Update curdir (the name of the current directory) in response to a
 * cd command.  We also call hashcd to let the routines in exec.c know
 * that the current directory has changed.
 */
static void
updatepwd(char *dir)
{
	char *prevdir;

	hashcd();				/* update command hash table */

	setvar("PWD", dir, VEXPORT);
	setvar("OLDPWD", curdir, VEXPORT);
	prevdir = curdir;
	curdir = dir ? savestr(dir) : NULL;
	ckfree(prevdir);
}

```やっていることは

<ul>
<li>hashcdの呼び出し
<ul>
<li>exec.cに定義されている。コメントによると、カレントディレクトリを変更したタイミングで呼ばないといけないらしい。</li>
</ul></li>
<li>環境変数 PWD の更新</li>
<li>環境変数 OLDPWD の更新</li>
<li>いろいろ後処理</li>
</ul>
</div>
<div class="section">
    #### まとめ
    とてもざっくり言うと、

<ul>
<li>システムコールを呼び出してカレントディレクトリを変更</li>
<li>環境変数 PWD の更新</li>
<li>環境変数 OLDPWD の更新</li>
</ul>をそれぞれ個別にやってるみたいでした!!

</div>