diff --git a/Makefile b/Makefile
index da4d0d0..511b89b 100644
--- a/Makefile
+++ b/Makefile
@@ -37,6 +37,7 @@ SRC = \
 	comm.c     \
 	cp.c       \
 	date.c     \
+	df.c       \
 	dirname.c  \
 	echo.c     \
 	env.c      \
diff --git a/df.c b/df.c
index e69de29..96da1e6 100644
--- a/df.c
+++ b/df.c
@@ -0,0 +1,73 @@
+#ifdef __OpenBSD__
+#include <sys/param.h>
+#include <sys/mount.h>
+#else
+#include <mntent.h>
+#endif
+
+#include <sys/statvfs.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "util.h"
+
+static void mnt_show(const struct statvfs *s, const char *fromname, const char *onname);
+
+int
+main(void)
+{
+	struct statvfs s;
+#ifdef __OpenBSD__
+	struct statfs *mntbuf;
+	int len, i;
+#else
+	FILE *fp;
+	struct mntent *me;
+#endif
+
+	printf("Filesystem  512-blocks      Used     Avail Capacity  Mounted on\n");
+#ifdef __OpenBSD__
+	len = getmntinfo(&mntbuf, MNT_WAIT);
+	if (len == 0) {
+		eprintf("getmntinfo:");
+	}
+
+	for (i = 0; i < len; i++) {
+		statvfs(mntbuf[i].f_mntonname, &s);
+		mnt_show(&s, mntbuf[i].f_mntfromname, mntbuf[i].f_mntonname);
+	}
+#else
+	fp = setmntent("/proc/mounts", "r");
+	if (!fp)
+		eprintf("fopen /proc/mounts:");
+
+	while ((me = getmntent(fp))) {
+		statvfs(me->mnt_dir, &s);
+		mnt_show(&s, me->mnt_fsname, me->mnt_dir);
+	}
+	endmntent(fp);
+#endif
+	return 0;
+}
+
+static void
+mnt_show(const struct statvfs *s, const char *fromname, const char *onname)
+{
+	u_int64_t total, used, avail;
+	int capacity = 0;
+	int bs;
+
+	bs = s->f_frsize / 512;
+
+	total = s->f_blocks * bs;
+	avail = s->f_bfree * bs;
+	used = total - avail;
+
+	if (used + avail) {
+		capacity = (used * 100) / (used + avail);
+		if (used * 100 != capacity * (used + avail))
+			capacity++;
+	}
+
+	printf("%-12s %9llu %9llu %9llu %7d%%  %s\n",
+	       fromname, total, used, avail, capacity, onname);
+}
