Index: uspace/lib/posix/Makefile
===================================================================
--- uspace/lib/posix/Makefile	(revision f5b25224f3b95c0a700f5f9f6c8bb2ecad2c28f0)
+++ uspace/lib/posix/Makefile	(revision 8cd8bf61fa7549be36c3193a2eff646b2c0f84ec)
@@ -40,9 +40,13 @@
 SOURCES = \
 	ctype.c \
+	errno.c \
 	fcntl.c \
 	fnmatch.c \
+	locale.c \
 	math.c \
 	pwd.c \
+	signal.c \
 	stdio.c \
+	stdio/scanf.c \
 	stdlib.c \
 	stdlib/strtol.c \
Index: uspace/lib/posix/assert.h
===================================================================
--- uspace/lib/posix/assert.h	(revision 8cd8bf61fa7549be36c3193a2eff646b2c0f84ec)
+++ uspace/lib/posix/assert.h	(revision 8cd8bf61fa7549be36c3193a2eff646b2c0f84ec)
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2011 Jiri Zarevucky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libposix
+ * @{
+ */
+/** @file
+ */
+
+/* NO include guard on purpose. */
+
+#include "libc/assert.h"
+
+#undef assert
+
+#ifndef NDEBUG
+	#define assert(expr) \
+		do { \
+			if (!(expr)) { \
+				assert_abort(#expr, __FILE__, __LINE__); \
+			} \
+		} while (0)
+#else
+	#define assert(expr) ((void) 0)
+#endif
+
+/** @}
+ */
+
Index: uspace/lib/posix/ctype.c
===================================================================
--- uspace/lib/posix/ctype.c	(revision f5b25224f3b95c0a700f5f9f6c8bb2ecad2c28f0)
+++ uspace/lib/posix/ctype.c	(revision 8cd8bf61fa7549be36c3193a2eff646b2c0f84ec)
@@ -108,4 +108,26 @@
 }
 
+/**
+ * Checks whether character is ASCII. (obsolete)
+ *
+ * @param c
+ * @return
+ */
+extern int posix_isascii(int c)
+{
+	return c >= 0 && c < 128;
+}
+
+/**
+ * Converts argument to a 7-bit ASCII character. (obsolete)
+ *
+ * @param c
+ * @return
+ */
+extern int posix_toascii(int c)
+{
+	return c & 0x7F;
+}
+
 /** @}
  */
Index: uspace/lib/posix/ctype.h
===================================================================
--- uspace/lib/posix/ctype.h	(revision f5b25224f3b95c0a700f5f9f6c8bb2ecad2c28f0)
+++ uspace/lib/posix/ctype.h	(revision 8cd8bf61fa7549be36c3193a2eff646b2c0f84ec)
@@ -47,4 +47,13 @@
 extern int posix_ispunct(int c);
 
+/* Obsolete Functions and Macros */
+extern int posix_isascii(int c);
+extern int posix_toascii(int c);
+#undef _tolower
+#define _tolower(c) ((c) - 'A' + 'a')
+#undef _toupper
+#define _toupper(c) ((c) - 'a' + 'A')
+
+
 #ifndef LIBPOSIX_INTERNAL
 	#define isxdigit posix_isxdigit
@@ -54,4 +63,7 @@
 	#define isprint posix_isprint
 	#define ispunct posix_ispunct
+	
+	#define isascii posix_isascii
+	#define toascii posix_toascii
 #endif
 
Index: uspace/lib/posix/errno.c
===================================================================
--- uspace/lib/posix/errno.c	(revision 8cd8bf61fa7549be36c3193a2eff646b2c0f84ec)
+++ uspace/lib/posix/errno.c	(revision 8cd8bf61fa7549be36c3193a2eff646b2c0f84ec)
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2011 Jiri Zarevucky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libposix
+ * @{
+ */
+/** @file
+ */
+
+#include "errno.h"
+
+#include "stdlib.h"
+#include "libc/fibril.h"
+
+static fibril_local int _posix_errno;
+
+int *__posix_errno(void)
+{
+	if (*__errno() != 0) {
+		_posix_errno = abs(*__errno());
+		*__errno() = 0;
+	}
+	return &_posix_errno;
+}
+
+/** @}
+ */
+
Index: uspace/lib/posix/errno.h
===================================================================
--- uspace/lib/posix/errno.h	(revision 8cd8bf61fa7549be36c3193a2eff646b2c0f84ec)
+++ uspace/lib/posix/errno.h	(revision 8cd8bf61fa7549be36c3193a2eff646b2c0f84ec)
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 2011 Jiri Zarevucky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libposix
+ * @{
+ */
+/** @file
+ */
+
+#ifndef POSIX_ERRNO_H_
+#define POSIX_ERRNO_H_
+
+#include "libc/errno.h"
+
+/* IMPORTANT:
+ * Since libc uses negative errorcodes, some sort of conversion is necessary to
+ * keep POSIX programs and libraries from breaking. This file maps POSIX error
+ * codes to absolute values of corresponding libc codes where available, and
+ * assigns new code where there is no prior definition in libc.
+ *
+ * A new errno variable is defined. When accessed, the function first looks at
+ * libc errno and iff it is != 0, sets the POSIX errno to absolute value of
+ * libc errno. Given that no library function sets errno to 0 and that all
+ * POSIX libraries will be used solely by POSIX programs (thus, there only needs
+ * to be one way correspondence between errno and posix_errno), this approach
+ * should work as expected in most cases and does not require any wrappers for
+ * libc routines that would just change errno values.
+ *
+ * There is no conditioning by LIBPOSIX_INTERNAL for redefinitions of macros.
+ * If there is a need to check errno for a value not defined by POSIX, it's
+ * necessary to compare errno against abs(ECODE), because there is no
+ * redefinition for such error codes.
+ *
+ * FIXME: maybe all HOS error codes should be redefined
+ *
+ * NOTE: This redefinition is slightly POSIX incompatible, since the
+ *  specification requires the macro values to be usable in preprocessing
+ *  directives. I don't think that's very important, though.
+ */
+
+#undef errno
+#define errno (*__posix_errno())
+
+extern int *__posix_errno(void);
+
+#define __TOP_ERRNO (-NO_DATA)
+
+enum {
+	POSIX_E2BIG = __TOP_ERRNO + 1,
+	POSIX_EACCES = __TOP_ERRNO + 2,
+	POSIX_EADDRINUSE = -EADDRINUSE,
+	POSIX_EADDRNOTAVAIL = -EADDRNOTAVAIL,
+	POSIX_EAFNOSUPPORT = -EAFNOSUPPORT,
+	POSIX_EAGAIN = -EAGAIN,
+	POSIX_EALREADY = __TOP_ERRNO + 3,
+	POSIX_EBADF = -EBADF,
+	POSIX_EBADMSG = __TOP_ERRNO + 4,
+	POSIX_EBUSY = -EBUSY,
+	POSIX_ECANCELED = __TOP_ERRNO + 5,
+	POSIX_ECHILD = __TOP_ERRNO + 6,
+	POSIX_ECONNABORTED = __TOP_ERRNO + 7,
+	POSIX_ECONNREFUSED = __TOP_ERRNO + 8,
+	POSIX_ECONNRESET = __TOP_ERRNO + 9,
+	POSIX_EDEADLK = __TOP_ERRNO + 10,
+	POSIX_EDESTADDRREQ = -EDESTADDRREQ,
+	POSIX_EDOM = __TOP_ERRNO + 11,
+	POSIX_EDQUOT = __TOP_ERRNO + 12,
+	POSIX_EEXIST = -EEXIST,
+	POSIX_EFAULT = __TOP_ERRNO + 13,
+	POSIX_EFBIG = __TOP_ERRNO + 14,
+	POSIX_EHOSTUNREACH = __TOP_ERRNO + 15,
+	POSIX_EIDRM = __TOP_ERRNO + 16,
+	POSIX_EILSEQ = __TOP_ERRNO + 17,
+	POSIX_EINPROGRESS = -EINPROGRESS,
+	POSIX_EINTR = -EINTR,
+	POSIX_EINVAL = -EINVAL,
+	POSIX_EIO = -EIO,
+	POSIX_EISCONN = __TOP_ERRNO + 18,
+	POSIX_EISDIR = -EISDIR,
+	POSIX_ELOOP = __TOP_ERRNO + 19,
+	POSIX_EMFILE = -EMFILE,
+	POSIX_EMLINK = -EMLINK,
+	POSIX_EMSGSIZE = __TOP_ERRNO + 20,
+	POSIX_EMULTIHOP = __TOP_ERRNO + 21,
+	POSIX_ENAMETOOLONG = -ENAMETOOLONG,
+	POSIX_ENETDOWN = __TOP_ERRNO + 22,
+	POSIX_ENETRESET = __TOP_ERRNO + 23,
+	POSIX_ENETUNREACH = __TOP_ERRNO + 24,
+	POSIX_ENFILE = __TOP_ERRNO + 25,
+	POSIX_ENOBUFS = __TOP_ERRNO + 26,
+	POSIX_ENODATA = -NO_DATA,
+	POSIX_ENODEV = __TOP_ERRNO + 27,
+	POSIX_ENOENT = -ENOENT,
+	POSIX_ENOEXEC = __TOP_ERRNO + 28,
+	POSIX_ENOLCK = __TOP_ERRNO + 29,
+	POSIX_ENOLINK = __TOP_ERRNO + 30,
+	POSIX_ENOMEM = -ENOMEM,
+	POSIX_ENOMSG = __TOP_ERRNO + 31,
+	POSIX_ENOPROTOOPT = __TOP_ERRNO + 32,
+	POSIX_ENOSPC = -ENOSPC,
+	POSIX_ENOSR = __TOP_ERRNO + 33,
+	POSIX_ENOSTR = __TOP_ERRNO + 34,
+	POSIX_ENOSYS = __TOP_ERRNO + 35,
+	POSIX_ENOTCONN = -ENOTCONN,
+	POSIX_ENOTDIR = -ENOTDIR,
+	POSIX_ENOTEMPTY = -ENOTEMPTY,
+	POSIX_ENOTRECOVERABLE = __TOP_ERRNO + 36,
+	POSIX_ENOTSOCK = -ENOTSOCK,
+	POSIX_ENOTSUP = -ENOTSUP,
+	POSIX_ENOTTY = __TOP_ERRNO + 37,
+	POSIX_ENXIO = __TOP_ERRNO + 38,
+	POSIX_EOPNOTSUPP = POSIX_ENOTSUP,
+	POSIX_EOVERFLOW = -EOVERFLOW,
+	POSIX_EOWNERDEAD = __TOP_ERRNO + 39,
+	POSIX_EPERM = -EPERM,
+	POSIX_EPIPE = __TOP_ERRNO + 40,
+	POSIX_EPROTO = __TOP_ERRNO + 41,
+	POSIX_EPROTONOSUPPORT = -EPROTONOSUPPORT,
+	POSIX_EPROTOTYPE = __TOP_ERRNO + 42,
+	POSIX_ERANGE = -ERANGE,
+	POSIX_EROFS = __TOP_ERRNO + 43,
+	POSIX_ESPIPE = __TOP_ERRNO + 44,
+	POSIX_ESRCH = __TOP_ERRNO + 45,
+	POSIX_ESTALE = __TOP_ERRNO + 46,
+	POSIX_ETIME = __TOP_ERRNO + 47,
+	POSIX_ETIMEDOUT = __TOP_ERRNO + 48,
+	POSIX_ETXTBSY = __TOP_ERRNO + 49,
+	POSIX_EWOULDBLOCK = POSIX_EAGAIN,
+	POSIX_EXDEV = -EXDEV,
+};
+
+#undef __TOP_ERRNO
+
+#undef E2BIG
+#undef EACCES
+#undef EADDRINUSE
+#undef EADDRNOTAVAIL
+#undef EAFNOSUPPORT
+#undef EAGAIN
+#undef EALREADY
+#undef EBADF
+#undef EBADMSG
+#undef EBUSY
+#undef ECANCELED
+#undef ECHILD
+#undef ECONNABORTED
+#undef ECONNREFUSED
+#undef ECONNRESET
+#undef EDEADLK
+#undef EDESTADDRREQ
+#undef EDOM
+#undef EDQUOT
+#undef EEXIST
+#undef EFAULT
+#undef EFBIG
+#undef EHOSTUNREACH
+#undef EIDRM
+#undef EILSEQ
+#undef EINPROGRESS
+#undef EINTR
+#undef EINVAL
+#undef EIO
+#undef EISCONN
+#undef EISDIR
+#undef ELOOP
+#undef EMFILE
+#undef EMLINK
+#undef EMSGSIZE
+#undef EMULTIHOP
+#undef ENAMETOOLONG
+#undef ENETDOWN
+#undef ENETRESET
+#undef ENETUNREACH
+#undef ENFILE
+#undef ENOBUFS
+#undef ENODATA
+#undef ENODEV
+#undef ENOENT
+#undef ENOEXEC
+#undef ENOLCK
+#undef ENOLINK
+#undef ENOMEM
+#undef ENOMSG
+#undef ENOPROTOOPT
+#undef ENOSPC
+#undef ENOSR
+#undef ENOSTR
+#undef ENOSYS
+#undef ENOTCONN
+#undef ENOTDIR
+#undef ENOTEMPTY
+#undef ENOTRECOVERABLE
+#undef ENOTSOCK
+#undef ENOTSUP
+#undef ENOTTY
+#undef ENXIO
+#undef EOPNOTSUPP
+#undef EOVERFLOW
+#undef EOWNERDEAD
+#undef EPERM
+#undef EPIPE
+#undef EPROTO
+#undef EPROTONOSUPPORT
+#undef EPROTOTYPE
+#undef ERANGE
+#undef EROFS
+#undef ESPIPE
+#undef ESRCH
+#undef ESTALE
+#undef ETIME
+#undef ETIMEDOUT
+#undef ETXTBSY
+#undef EWOULDBLOCK
+#undef EXDEV
+
+#define E2BIG POSIX_E2BIG
+#define EACCES POSIX_EACCES
+#define EADDRINUSE POSIX_EADDRINUSE
+#define EADDRNOTAVAIL POSIX_EADDRNOTAVAIL
+#define EAFNOSUPPORT POSIX_EAFNOSUPPORT
+#define EAGAIN POSIX_EAGAIN
+#define EALREADY POSIX_EALREADY
+#define EBADF POSIX_EBADF
+#define EBADMSG POSIX_EBADMSG
+#define EBUSY POSIX_EBUSY
+#define ECANCELED POSIX_ECANCELED
+#define ECHILD POSIX_ECHILD
+#define ECONNABORTED POSIX_ECONNABORTED
+#define ECONNREFUSED POSIX_ECONNREFUSED
+#define ECONNRESET POSIX_ECONNRESET
+#define EDEADLK POSIX_EDEADLK
+#define EDESTADDRREQ POSIX_EDESTADDRREQ
+#define EDOM POSIX_EDOM
+#define EDQUOT POSIX_EDQUOT
+#define EEXIST POSIX_EEXIST
+#define EFAULT POSIX_EFAULT
+#define EFBIG POSIX_EFBIG
+#define EHOSTUNREACH POSIX_EHOSTUNREACH
+#define EIDRM POSIX_EIDRM
+#define EILSEQ POSIX_EILSEQ
+#define EINPROGRESS POSIX_EINPROGRESS
+#define EINTR POSIX_EINTR
+#define EINVAL POSIX_EINVAL
+#define EIO POSIX_EIO
+#define EISCONN POSIX_EISCONN
+#define EISDIR POSIX_EISDIR
+#define ELOOP POSIX_ELOOP
+#define EMFILE POSIX_EMFILE
+#define EMLINK POSIX_EMLINK
+#define EMSGSIZE POSIX_EMSGSIZE
+#define EMULTIHOP POSIX_EMULTIHOP
+#define ENAMETOOLONG POSIX_ENAMETOOLONG
+#define ENETDOWN POSIX_ENETDOWN
+#define ENETRESET POSIX_ENETRESET
+#define ENETUNREACH POSIX_ENETUNREACH
+#define ENFILE POSIX_ENFILE
+#define ENOBUFS POSIX_ENOBUFS
+#define ENODATA POSIX_ENODATA
+#define ENODEV POSIX_ENODEV
+#define ENOENT POSIX_ENOENT
+#define ENOEXEC POSIX_ENOEXEC
+#define ENOLCK POSIX_ENOLCK
+#define ENOLINK POSIX_ENOLINK
+#define ENOMEM POSIX_ENOMEM
+#define ENOMSG POSIX_ENOMSG
+#define ENOPROTOOPT POSIX_ENOPROTOOPT
+#define ENOSPC POSIX_ENOSPC
+#define ENOSR POSIX_ENOSR
+#define ENOSTR POSIX_ENOSTR
+#define ENOSYS POSIX_ENOSYS
+#define ENOTCONN POSIX_ENOTCONN
+#define ENOTDIR POSIX_ENOTDIR
+#define ENOTEMPTY POSIX_ENOTEMPTY
+#define ENOTRECOVERABLE POSIX_ENOTRECOVERABLE
+#define ENOTSOCK POSIX_ENOTSOCK
+#define ENOTSUP POSIX_ENOTSUP
+#define ENOTTY POSIX_ENOTTY
+#define ENXIO POSIX_ENXIO
+#define EOPNOTSUPP POSIX_EOPNOTSUPP
+#define EOVERFLOW POSIX_EOVERFLOW
+#define EOWNERDEAD POSIX_EOWNERDEAD
+#define EPERM POSIX_EPERM
+#define EPIPE POSIX_EPIPE
+#define EPROTO POSIX_EPROTO
+#define EPROTONOSUPPORT POSIX_EPROTONOSUPPORT
+#define EPROTOTYPE POSIX_EPROTOTYPE
+#define ERANGE POSIX_ERANGE
+#define EROFS POSIX_EROFS
+#define ESPIPE POSIX_ESPIPE
+#define ESRCH POSIX_ESRCH
+#define ESTALE POSIX_ESTALE
+#define ETIME POSIX_ETIME
+#define ETIMEDOUT POSIX_ETIMEDOUT
+#define ETXTBSY POSIX_ETXTBSY
+#define EWOULDBLOCK POSIX_EWOULDBLOCK
+#define EXDEV POSIX_EXDEV
+
+#endif /* POSIX_ERRNO_H_ */
+
+/** @}
+ */
+
Index: uspace/lib/posix/fcntl.c
===================================================================
--- uspace/lib/posix/fcntl.c	(revision f5b25224f3b95c0a700f5f9f6c8bb2ecad2c28f0)
+++ uspace/lib/posix/fcntl.c	(revision 8cd8bf61fa7549be36c3193a2eff646b2c0f84ec)
@@ -38,15 +38,84 @@
 #include "fcntl.h"
 
+#include "libc/unistd.h"
+#include "libc/vfs/vfs.h"
+#include "errno.h"
+
 /**
- * 
- * @param fd
- * @param cmd
- * @param ...
- * @return
+ * Performs set of operations on the opened files.
+ *
+ * @param fd File descriptor of the opened file.
+ * @param cmd Operation to carry out.
+ * @return Non-negative on success. Might have special meaning corresponding
+ *     to the requested operation.
  */
 int posix_fcntl(int fd, int cmd, ...)
 {
-	// TODO
-	not_implemented();
+	int rc;
+	int flags;
+
+	switch (cmd) {
+	case F_DUPFD:
+	case F_DUPFD_CLOEXEC: /* FD_CLOEXEC is not supported. */
+		/* VFS does not provide means to express constraints on the new
+		 * file descriptor so the third argument is ignored. */
+
+		/* Retrieve node triplet corresponding to the file descriptor. */
+		/* Empty statement after label. */;
+		fdi_node_t node;
+		rc = fd_node(fd, &node);
+		if (rc != EOK) {
+			errno = -rc;
+			return -1;
+		}
+
+		/* Reopen the node so the fresh file descriptor is generated. */
+		int newfd = open_node(&node, 0);
+		if (newfd < 0) {
+			errno = -newfd;
+			return -1;
+		}
+
+		/* Associate the newly generated descriptor to the file description
+		 * of the old file descriptor. Just reopened node will be automatically
+		 * closed. */
+		rc = dup2(fd, newfd);
+		if (rc != EOK) {
+			errno = -rc;
+			return -1;
+		}
+
+		return newfd;
+	case F_GETFD:
+		/* FD_CLOEXEC is not supported. There are no other flags. */
+		return 0;
+	case F_SETFD:
+		/* FD_CLOEXEC is not supported. Ignore arguments and report success. */
+		return 0;
+	case F_GETFL:
+		/* File status flags (i.e. O_APPEND) are currently private to the
+		 * VFS server so it cannot be easily retrieved. */
+		flags = 0;
+		/* File access flags are currently not supported for file descriptors.
+		 * Provide full access. */
+		flags |= O_RDWR;
+		return flags;
+	case F_SETFL:
+		/* File access flags are currently not supported for file descriptors.
+		 * Ignore arguments and report success. */
+		return 0;
+	case F_GETOWN:
+	case F_SETOWN:
+	case F_GETLK:
+	case F_SETLK:
+	case F_SETLKW:
+		/* Signals (SIGURG) and file locks are not supported. */
+		errno = ENOTSUP;
+		return -1;
+	default:
+		/* Unknown command */
+		errno = EINVAL;
+		return -1;
+	}
 }
 
Index: uspace/lib/posix/fcntl.h
===================================================================
--- uspace/lib/posix/fcntl.h	(revision f5b25224f3b95c0a700f5f9f6c8bb2ecad2c28f0)
+++ uspace/lib/posix/fcntl.h	(revision 8cd8bf61fa7549be36c3193a2eff646b2c0f84ec)
@@ -36,8 +36,14 @@
 #define POSIX_FCNTL_H_
 
+#include "sys/types.h"
 #include "libc/fcntl.h"
+
+/* Mask for file access modes. */
+#undef O_ACCMODE
+#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
 
 /* fcntl commands */
 #undef F_DUPFD
+#undef F_DUPFD_CLOEXEC
 #undef F_GETFD
 #undef F_SETFD
@@ -46,15 +52,22 @@
 #undef F_GETOWN
 #undef F_SETOWN
-#define	F_DUPFD	  	0	/* Duplicate file descriptor. */
-#define	F_GETFD		1	/* Get file descriptor flags. */
-#define	F_SETFD		2	/* Set file descriptor flags. */
-#define	F_GETFL		3	/* Get file status flags. */
-#define	F_SETFL		4	/* Set file status flags. */
-#define F_GETOWN	5	/* Get owner. */
-#define F_SETOWN	6	/* Set owner. */
+#undef F_GETLK
+#undef F_SETLK
+#undef F_SETLKW
+#define F_DUPFD            0 /* Duplicate file descriptor. */
+#define F_DUPFD_CLOEXEC    1 /* Same as F_DUPFD but with FD_CLOEXEC flag set. */
+#define F_GETFD            2 /* Get file descriptor flags. */
+#define F_SETFD            3 /* Set file descriptor flags. */
+#define F_GETFL            4 /* Get file status and access flags. */
+#define F_SETFL            5 /* Set file status flags. */
+#define F_GETOWN           6 /* Get socket owner. */
+#define F_SETOWN           7 /* Set socket owner. */
+#define F_GETLK            8 /* Get locking information. */
+#define F_SETLK            9 /* Set locking information. */
+#define F_SETLKW          10 /* Set locking information; wait if blocked. */
 
 /* File descriptor flags used with F_GETFD and F_SETFD. */
 #undef FD_CLOEXEC
-#define	FD_CLOEXEC	1	/* Close on exec. */
+#define FD_CLOEXEC         1 /* Close on exec. */
 
 extern int posix_fcntl(int fd, int cmd, ...);
Index: uspace/lib/posix/fnmatch.c
===================================================================
--- uspace/lib/posix/fnmatch.c	(revision f5b25224f3b95c0a700f5f9f6c8bb2ecad2c28f0)
+++ uspace/lib/posix/fnmatch.c	(revision 8cd8bf61fa7549be36c3193a2eff646b2c0f84ec)
@@ -33,8 +33,455 @@
  */
 
+// TODO: clean this up a bit
+
+#include "stdbool.h"
+#include "ctype.h"
+#include "string.h"
+#include "stdlib.h"
+#include "assert.h"
+
 #define LIBPOSIX_INTERNAL
 
 #include "internal/common.h"
 #include "fnmatch.h"
+
+#define INVALID_PATTERN -1
+
+/* Type for collating element, simple identity with characters now,
+ * but may be extended for better locale support.
+ */
+typedef int _coll_elm_t;
+
+#define COLL_ELM_INVALID -1
+
+/** Get collating element matching a string.
+ *
+ * @param str
+ * @return
+ */
+static _coll_elm_t _coll_elm_get(const char* str)
+{
+	if (str[0] == '\0' || str[1] != '\0') {
+		return COLL_ELM_INVALID;
+	}
+	return str[0];
+}
+
+/** Get collating element matching a single character.
+ *
+ * @param c
+ * @return
+ */
+static _coll_elm_t _coll_elm_char(int c)
+{
+	return c;
+}
+
+/** Match collating element with a beginning of a string.
+ *
+ * @param elm
+ * @param str
+ * @return 0 if the element doesn't match, or the number of characters matched.
+ */
+static int _coll_elm_match(_coll_elm_t elm, const char *str)
+{
+	return elm == *str;
+}
+
+static int _coll_elm_between(_coll_elm_t first, _coll_elm_t second,
+    const char *str)
+{
+	return *str >= first && *str <= second;
+}
+
+/** Read a string delimited by [? and ?].
+ *
+ * @param pattern Pointer to the string to read from. Its position is moved
+ *    to the first character after the closing ].
+ * @param seq The character on the inside of brackets.
+ * @param buf Read buffer.
+ * @param buf_sz Read buffer's size. If the buffer is not large enough for
+ *    the entire string, the string is cut with no error indication.
+ * @return
+ */
+static bool _get_delimited(
+    const char **pattern, int seq,
+    char *buf, size_t buf_sz, int flags)
+{
+	const bool noescape = (flags & FNM_NOESCAPE) != 0;
+	const bool pathname = (flags & FNM_PATHNAME) != 0;
+
+	const char *p = *pattern;
+	assert(p[0] == '[' && p[1] == seq /* Caller should ensure this. */);
+	p += 2;
+
+	while (true) {
+		if (*p == seq && *(p + 1) == ']') {
+			/* String properly ended, return. */
+			*pattern = p + 2;
+			*buf = '\0';
+			return true;
+		}
+		if (!noescape && *p == '\\') {
+			p++;
+		}
+		if (*p == '\0') {
+			/* String not ended properly, invalid pattern. */
+			return false;
+		}
+		if (pathname && *p == '/') {
+			/* Slash in a pathname pattern is invalid. */
+			return false;
+		}
+		if (buf_sz > 1) {
+			/* Only add to the buffer if there is space. */
+			*buf = *p;
+			buf++;
+			buf_sz--;
+		}
+		p++;
+	}
+}
+
+/************** CHARACTER CLASSES ****************/
+
+#define MAX_CLASS_OR_COLL_LEN 6
+
+struct _char_class {
+	const char *name;
+	int (*func) (int);
+};
+
+/* List of supported character classes. */
+static const struct _char_class _char_classes[] = {
+	{ "alnum", isalnum },
+	{ "alpha", isalpha },
+	{ "blank", isblank },
+	{ "cntrl", iscntrl },
+	{ "digit", isdigit },
+	{ "graph", isgraph },
+	{ "lower", islower },
+	{ "print", isprint },
+	{ "punct", ispunct },
+	{ "space", isspace },
+	{ "upper", isupper },
+	{ "xdigit", isxdigit }
+};
+
+static int _class_compare(const void *key, const void *elem)
+{
+	const struct _char_class *class = elem;
+	return strcmp((const char *) key, class->name);
+}
+
+static bool _is_in_class (const char *cname, int c)
+{
+	/* Search for class in the array of supported character classes. */
+	const struct _char_class *class = bsearch(cname, _char_classes,
+	    sizeof(_char_classes) / sizeof(struct _char_class),
+	    sizeof(struct _char_class), _class_compare);
+
+	if (class == NULL) {
+		/* No such class supported - treat as an empty class. */
+		return false;
+	} else {
+		/* Class matched. */
+		return class->func(c);
+	}
+}
+
+static int _match_char_class(const char **pattern, const char *str, int flags)
+{
+	char class[MAX_CLASS_OR_COLL_LEN + 1];
+
+	if (!_get_delimited(pattern, ':', class, sizeof(class), flags)) {
+		return INVALID_PATTERN;
+	}
+
+	return _is_in_class(class, *str);
+}
+
+/************** END CHARACTER CLASSES ****************/
+
+static _coll_elm_t _next_coll_elm(const char **pattern, int flags)
+{
+	const char *p = *pattern;
+	const bool noescape = (flags & FNM_NOESCAPE) != 0;
+	const bool pathname = (flags & FNM_PATHNAME) != 0;
+
+	if (*p == '[') {
+		if (*(p + 1) == '.') {
+			char buf[MAX_CLASS_OR_COLL_LEN + 1];
+			if (!_get_delimited(pattern, '.', buf, sizeof(buf), flags)) {
+				return COLL_ELM_INVALID;
+			}
+			return _coll_elm_get(buf);
+		}
+
+		if (*(p + 1) == '=') {
+			char buf[MAX_CLASS_OR_COLL_LEN + 1];
+			if (!_get_delimited(pattern, '=', buf, sizeof(buf), flags)) {
+				return COLL_ELM_INVALID;
+			}
+			return _coll_elm_get(buf);
+		}
+	}
+
+	if (!noescape && *p == '\\') {
+		p++;
+	}
+	if (pathname && *p == '/') {
+		return COLL_ELM_INVALID;
+	}
+
+	*pattern = p + 1;
+	return _coll_elm_char(*p);
+}
+
+/**
+ *
+ */
+static int _match_bracket_expr(const char **pattern, const char *str, int flags)
+{
+	const bool pathname = (flags & FNM_PATHNAME) != 0;
+	const bool special_period = (flags & FNM_PERIOD) != 0;
+	const char *p = *pattern;
+	bool negative = false;
+	int matched = 0;
+
+	#define _matched(match) { \
+		int _match = match; \
+		if (_match < 0) { \
+			/* Invalid pattern */ \
+			return _match; \
+		} else if (matched == 0 && _match > 0) { \
+			/* First match */ \
+			matched = _match; \
+		} \
+	}
+
+	assert(*p == '[');  /* calling code should ensure this */
+	p++;
+
+	if (*str == '\0' || (pathname && *str == '/') ||
+	    (pathname && special_period && *str == '.' && *(str - 1) == '/')) {
+		/* No bracket expression matches end of string,
+		 * slash in pathname match or initial period with FNM_PERIOD
+		 * option.
+		 */
+		return 0;
+	}
+
+	if (*p == '^' || *p == '!') {
+		negative = true;
+		p++;
+	}
+
+	if (*p == ']') {
+		/* When ']' is first, treat it as a normal character. */
+		_matched(*str == ']');
+		p++;
+	}
+	
+	_coll_elm_t current_elm = COLL_ELM_INVALID;
+	
+	while (*p != ']') {
+		if (*p == '-' && *(p + 1) != ']' &&
+		    current_elm != COLL_ELM_INVALID) {
+			/* Range expression. */
+			p++;
+			_coll_elm_t end_elm = _next_coll_elm(&p, flags);
+			if (end_elm == COLL_ELM_INVALID) {
+				return INVALID_PATTERN;
+			}
+			_matched(_coll_elm_between(current_elm, end_elm, str));
+			continue;
+		}
+	
+		if (*p == '[' && *(p + 1) == ':') {
+			current_elm = COLL_ELM_INVALID;
+			_matched(_match_char_class(&p, str, flags));
+			continue;
+		}
+		
+		current_elm = _next_coll_elm(&p, flags);
+		if (current_elm == COLL_ELM_INVALID) {
+			return INVALID_PATTERN;
+		}
+		_matched(_coll_elm_match(current_elm, str));
+	}
+
+	/* No error occured - update pattern pointer. */
+	*pattern = p + 1;
+
+	if (matched == 0) {
+		/* No match found */
+		return negative;
+	} else {
+		/* Matched 'match' characters. */
+		return negative ? 0 : matched;
+	}
+
+	#undef _matched
+}
+
+/**
+ *
+ */
+static bool _partial_match(const char **pattern, const char **string, int flags)
+{
+	/* Only a single *-delimited subpattern is matched here.
+	 * So in this function, '*' is understood as the end of pattern.
+	 */
+
+	const bool pathname = (flags & FNM_PATHNAME) != 0;
+	const bool special_period = (flags & FNM_PERIOD) != 0;
+	const bool noescape = (flags & FNM_NOESCAPE) != 0;
+	const bool leading_dir = (flags & FNM_LEADING_DIR) != 0;
+
+	const char *s = *string;
+	const char *p = *pattern;
+
+	while (*p != '*') {
+		/* Bracket expression. */
+		if (*p == '[') {
+			int matched = _match_bracket_expr(&p, s, flags);
+			if (matched == 0) {
+				/* Doesn't match. */
+				return false;
+			}
+			if (matched != INVALID_PATTERN) {
+				s += matched;
+				continue;
+			}
+
+			assert(matched == INVALID_PATTERN);
+			/* Fall through to match [ as an ordinary character. */
+		}
+
+		/* Wildcard match. */
+		if (*p == '?') {
+			if (*s == '\0') {
+				/* No character to match. */
+				return false;
+			}
+			if (pathname && *s == '/') {
+				/* Slash must be matched explicitly. */
+				return false;
+			}
+			if (special_period && pathname &&
+			    *s == '.' && *(s - 1) == '/') {
+				/* Initial period must be matched explicitly. */
+				return false;
+			}
+			
+			/* None of the above, match anything else. */
+			p++;
+			s++;
+			continue;
+		}
+
+		if (!noescape && *p == '\\') {
+			/* Escaped character. */
+			p++;
+		}
+
+		if (*p == '\0') {
+			/* End of pattern, must match end of string or
+			 * an end of subdirectory name (optional).
+			 */
+
+			if (*s == '\0' || (leading_dir && *s == '/')) {
+				break;
+			}
+
+			return false;
+		}
+
+		if (*p == *s) {
+			/* Exact match. */
+			p++;
+			s++;
+			continue;
+		}
+
+		/* Nothing matched. */
+		return false;
+	}
+
+	/* Entire sub-pattern matched. */
+	
+	/* postconditions */
+	assert(*p == '\0' || *p == '*');
+	assert(*p != '\0' || *s == '\0' || (leading_dir && *s == '/'));
+	
+	*pattern = p;
+	*string = s;
+	return true;
+}
+
+static bool _full_match(const char *pattern, const char *string, int flags)
+{
+	const bool pathname = (flags & FNM_PATHNAME) != 0;
+	const bool special_period = (flags & FNM_PERIOD) != 0;
+	const bool leading_dir = (flags & FNM_LEADING_DIR) != 0;
+
+	if (special_period && *string == '.') {
+		/* Initial dot must be matched by an explicit dot in pattern. */
+		if (*pattern != '.') {
+			return false;
+		}
+		pattern++;
+		string++;
+	}
+
+	if (*pattern != '*') {
+		if (!_partial_match(&pattern, &string, flags)) {
+			/* The initial match must succeed. */
+			return false;
+		}
+	}
+
+	while (*pattern != '\0') {
+		assert(*pattern == '*');
+		pattern++;
+
+		bool matched = false;
+
+		const char *end;
+		if (pathname && special_period &&
+		    *string == '.' && *(string - 1) == '/') {
+			end = string;
+		} else {
+			end= strchrnul(string, pathname ? '/' : '\0');
+		}
+
+		/* Try to match every possible offset. */
+		while (string <= end) {
+			if (_partial_match(&pattern, &string, flags)) {
+				matched = true;
+				break;
+			}
+			string++;
+		}
+
+		if (matched) {
+			continue;
+		}
+
+		return false;
+	}
+
+	return *string == '\0' || (leading_dir && *string == '/');
+}
+
+static char *_casefold(const char *s)
+{
+	char *result = strdup(s);
+	for (char *i = result; *i != '\0'; ++i) {
+		*i = tolower(*i);
+	}
+	return result;
+}
 
 /**
@@ -48,7 +495,110 @@
 int posix_fnmatch(const char *pattern, const char *string, int flags)
 {
-	// TODO
-	not_implemented();
-}
+	// TODO: don't fold everything in advance, but only when needed
+
+	if ((flags & FNM_CASEFOLD) != 0) {
+		/* Just fold the entire pattern and string. */
+		pattern = _casefold(pattern);
+		string = _casefold(string);
+	}
+
+	bool result = _full_match(pattern, string, flags);
+
+	if ((flags & FNM_CASEFOLD) != 0) {
+		free((char *) pattern);
+		free((char *) string);
+	}
+
+	return result ? 0 : FNM_NOMATCH;
+}
+
+// FIXME: put the testcases somewhere else
+
+#if 0
+
+#include <stdio.h>
+
+void __posix_fnmatch_test()
+{
+	int fail = 0;
+
+	#undef assert
+	#define assert(x) { if (x) printf("SUCCESS: "#x"\n"); else { printf("FAILED: "#x"\n"); fail++; } }
+	#define match(s1, s2, flags) assert(posix_fnmatch(s1, s2, flags) == 0)
+	#define nomatch(s1, s2, flags) assert(posix_fnmatch(s1, s2, flags) == FNM_NOMATCH)
+
+	assert(FNM_PATHNAME == FNM_FILE_NAME);
+	match("", "", 0);
+	match("*", "hello", 0);
+	match("hello", "hello", 0);
+	match("hello*", "hello", 0);
+	nomatch("hello?", "hello", 0);
+	match("*hello", "prdel hello", 0);
+	match("he[sl]lo", "hello", 0);
+	match("he[sl]lo", "heslo", 0);
+	nomatch("he[sl]lo", "heblo", 0);
+	nomatch("he[^sl]lo", "hello", 0);
+	nomatch("he[^sl]lo", "heslo", 0);
+	match("he[^sl]lo", "heblo", 0);
+	nomatch("he[!sl]lo", "hello", 0);
+	nomatch("he[!sl]lo", "heslo", 0);
+	match("he[!sl]lo", "heblo", 0);
+	match("al*[c-t]a*vis*ta", "alheimer talir jehovista", 0);
+	match("al*[c-t]a*vis*ta", "alfons had jehovista", 0);
+	match("[a-ce-z]", "a", 0);
+	match("[a-ce-z]", "c", 0);
+	nomatch("[a-ce-z]", "d", 0);
+	match("[a-ce-z]", "e", 0);
+	match("[a-ce-z]", "z", 0);
+	nomatch("[^a-ce-z]", "a", 0);
+	nomatch("[^a-ce-z]", "c", 0);
+	match("[^a-ce-z]", "d", 0);
+	nomatch("[^a-ce-z]", "e", 0);
+	nomatch("[^a-ce-z]", "z", 0);
+	match("helen??", "helenos", 0);
+	match("****booo****", "booo", 0);
+	
+	match("hello[[:space:]]world", "hello world", 0);
+	nomatch("hello[[:alpha:]]world", "hello world", 0);
+	
+	match("/hoooo*", "/hooooooo/hooo", 0);
+	nomatch("/hoooo*", "/hooooooo/hooo", FNM_PATHNAME);
+	nomatch("/hoooo*/", "/hooooooo/hooo", FNM_PATHNAME);
+	match("/hoooo*/*", "/hooooooo/hooo", FNM_PATHNAME);
+	match("/hoooo*/hooo", "/hooooooo/hooo", FNM_PATHNAME);
+	match("/hoooo*", "/hooooooo/hooo", FNM_PATHNAME | FNM_LEADING_DIR);
+	nomatch("/hoooo*/", "/hooooooo/hooo", FNM_PATHNAME | FNM_LEADING_DIR);
+	nomatch("/hoooo", "/hooooooo/hooo", FNM_LEADING_DIR);
+	match("/hooooooo", "/hooooooo/hooo", FNM_LEADING_DIR);
+	
+	match("*", "hell", 0);
+	match("*?", "hell", 0);
+	match("?*?", "hell", 0);
+	match("?*??", "hell", 0);
+	match("??*??", "hell", 0);
+	nomatch("???*??", "hell", 0);
+	
+	nomatch("", "hell", 0);
+	nomatch("?", "hell", 0);
+	nomatch("??", "hell", 0);
+	nomatch("???", "hell", 0);
+	match("????", "hell", 0);
+	
+	match("*", "h.ello", FNM_PERIOD);
+	match("*", "h.ello", FNM_PATHNAME | FNM_PERIOD);
+	nomatch("*", ".hello", FNM_PERIOD);
+	match("h?ello", "h.ello", FNM_PERIOD);
+	nomatch("?hello", ".hello", FNM_PERIOD);
+	match("/home/user/.*", "/home/user/.hello", FNM_PATHNAME | FNM_PERIOD);
+	match("/home/user/*", "/home/user/.hello", FNM_PERIOD);
+	nomatch("/home/user/*", "/home/user/.hello", FNM_PATHNAME | FNM_PERIOD);
+
+	nomatch("HeLlO", "hello", 0);
+	match("HeLlO", "hello", FNM_CASEFOLD);
+
+	printf("Failed: %d\n", fail);
+}
+
+#endif
 
 /** @}
Index: uspace/lib/posix/fnmatch.h
===================================================================
--- uspace/lib/posix/fnmatch.h	(revision f5b25224f3b95c0a700f5f9f6c8bb2ecad2c28f0)
+++ uspace/lib/posix/fnmatch.h	(revision 8cd8bf61fa7549be36c3193a2eff646b2c0f84ec)
@@ -48,4 +48,12 @@
 #define FNM_NOESCAPE 4
 
+/* GNU Extensions */
+#undef FNM_FILE_NAME
+#undef FNM_LEADING_DIR
+#undef FNM_CASEFOLD
+#define FNM_FILE_NAME FNM_PATHNAME
+#define FNM_LEADING_DIR 8
+#define FNM_CASEFOLD 16
+
 extern int posix_fnmatch(const char *pattern, const char *string, int flags);
 
Index: uspace/lib/posix/iso646.h
===================================================================
--- uspace/lib/posix/iso646.h	(revision 8cd8bf61fa7549be36c3193a2eff646b2c0f84ec)
+++ uspace/lib/posix/iso646.h	(revision 8cd8bf61fa7549be36c3193a2eff646b2c0f84ec)
@@ -0,0 +1,27 @@
+
+/** @addtogroup libposix
+ * @{
+ */
+/** @file
+ */
+
+#ifndef POSIX_ISO646_H_
+#define POSIX_ISO646_H_
+
+#define and &&
+#define and_eq &=
+#define bitand &
+#define bitor |
+#define compl ˜
+#define not !
+#define not_eq !=
+#define or ||
+#define or_eq |=
+#define xor ^
+#define xor_eq ^=
+
+#endif /* POSIX_ISO646_H_ */
+
+/** @}
+ */
+
Index: uspace/lib/posix/locale.c
===================================================================
--- uspace/lib/posix/locale.c	(revision 8cd8bf61fa7549be36c3193a2eff646b2c0f84ec)
+++ uspace/lib/posix/locale.c	(revision 8cd8bf61fa7549be36c3193a2eff646b2c0f84ec)
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2011 Jiri Zarevucky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libposix
+ * @{
+ */
+/** @file
+ */
+
+#define LIBPOSIX_INTERNAL
+
+#include "internal/common.h"
+#include "locale.h"
+
+#include "errno.h"
+#include "limits.h"
+#include "string.h"
+
+struct __posix_locale {
+	int _dummy;
+};
+
+const struct posix_lconv C_LOCALE = {
+	.currency_symbol = (char *) "",
+	.decimal_point = (char *) ".",
+	.frac_digits = CHAR_MAX,
+	.grouping = (char *) "",
+	.int_curr_symbol = (char *) "",
+	.int_frac_digits = CHAR_MAX,
+	.int_n_cs_precedes = CHAR_MAX,
+	.int_n_sep_by_space = CHAR_MAX,
+	.int_n_sign_posn = CHAR_MAX,
+	.int_p_cs_precedes = CHAR_MAX,
+	.int_p_sep_by_space = CHAR_MAX,
+	.int_p_sign_posn = CHAR_MAX,
+	.mon_decimal_point = (char *) "",
+	.mon_grouping = (char *) "",
+	.mon_thousands_sep = (char *) "",
+	.negative_sign = (char *) "",
+	.n_cs_precedes = CHAR_MAX,
+	.n_sep_by_space = CHAR_MAX,
+	.n_sign_posn = CHAR_MAX,
+	.positive_sign = (char *) "",
+	.p_cs_precedes = CHAR_MAX,
+	.p_sep_by_space = CHAR_MAX,
+	.p_sign_posn = CHAR_MAX,
+	.thousands_sep = (char *) ""
+};
+
+char *posix_setlocale(int category, const char *locale)
+{
+	// TODO
+	if (locale == NULL || *locale == '\0' ||
+	    posix_strcmp(locale, "C") == 0) {
+		return (char *) "C";
+	}
+	return NULL;
+}
+
+struct posix_lconv *posix_localeconv(void)
+{
+	// TODO
+	return (struct posix_lconv *) &C_LOCALE;
+}
+
+posix_locale_t posix_duplocale(posix_locale_t locobj)
+{
+	if (locobj == NULL) {
+		errno = EINVAL;
+		return NULL;
+	}
+	posix_locale_t copy = malloc(sizeof(struct __posix_locale));
+	if (copy == NULL) {
+		errno = ENOMEM;
+		return NULL;
+	}
+	memcpy(copy, locobj, sizeof(struct __posix_locale));
+	return copy;
+}
+
+void posix_freelocale(posix_locale_t locobj)
+{
+	free(locobj);
+}
+
+posix_locale_t posix_newlocale(int category_mask, const char *locale,
+    posix_locale_t base)
+{
+	if (locale == NULL ||
+	    (category_mask & LC_ALL_MASK) != category_mask) {
+		errno = EINVAL;
+		return NULL;
+	}
+	// TODO
+	posix_locale_t new = malloc(sizeof(struct __posix_locale));
+	if (new == NULL) {
+		errno = ENOMEM;
+		return NULL;
+	}
+	if (base != NULL) {
+		posix_freelocale(base);
+	}
+	return new;
+}
+
+posix_locale_t posix_uselocale (posix_locale_t newloc)
+{
+	// TODO
+	return NULL;
+}
+
+/** @}
+ */
Index: uspace/lib/posix/locale.h
===================================================================
--- uspace/lib/posix/locale.h	(revision 8cd8bf61fa7549be36c3193a2eff646b2c0f84ec)
+++ uspace/lib/posix/locale.h	(revision 8cd8bf61fa7549be36c3193a2eff646b2c0f84ec)
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2011 Jiri Zarevucky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libposix
+ * @{
+ */
+/** @file
+ */
+
+#ifndef POSIX_LOCALE_H_
+#define POSIX_LOCALE_H_
+
+#ifndef NULL
+	#define NULL ((void *) 0)
+#endif
+
+#ifndef __locale_t_defined
+	#define __locale_t_defined
+	typedef struct __posix_locale *posix_locale_t;
+	#ifndef LIBPOSIX_INTERNAL
+		#define locale_t posix_locale_t
+	#endif
+#endif
+
+#undef LC_ALL
+#undef LC_COLLATE
+#undef LC_CTYPE
+#undef LC_MESSAGES
+#undef LC_MONETARY
+#undef LC_NUMERIC
+#undef LC_TIME
+#define LC_ALL 0
+#define LC_COLLATE 1
+#define LC_CTYPE 2
+#define LC_MESSAGES 3
+#define LC_MONETARY 4
+#define LC_NUMERIC 5
+#define LC_TIME 6
+
+#undef LC_COLLATE_MASK
+#undef LC_CTYPE_MASK
+#undef LC_MESSAGES_MASK
+#undef LC_MONETARY_MASK
+#undef LC_NUMERIC_MASK
+#undef LC_TIME_MASK
+#undef LC_ALL_MASK
+#define LC_COLLATE_MASK (1 << 0)
+#define LC_CTYPE_MASK (1 << 1)
+#define LC_MESSAGES_MASK (1 << 2)
+#define LC_MONETARY_MASK (1 << 3)
+#define LC_NUMERIC_MASK (1 << 4)
+#define LC_TIME_MASK (1 << 5)
+#define LC_ALL_MASK (LC_COLLATE_MASK | LC_CTYPE_MASK | LC_MESSAGES_MASK | \
+    LC_MONETARY_MASK | LC_NUMERIC_MASK | LC_TIME_MASK)
+
+#undef LC_GLOBAL_LOCALE
+#define LC_GLOBAL_LOCALE NULL
+
+struct posix_lconv {
+	char    *currency_symbol;
+	char    *decimal_point;
+	char     frac_digits;
+	char    *grouping;
+	char    *int_curr_symbol;
+	char     int_frac_digits;
+	char     int_n_cs_precedes;
+	char     int_n_sep_by_space;
+	char     int_n_sign_posn;
+	char     int_p_cs_precedes;
+	char     int_p_sep_by_space;
+	char     int_p_sign_posn;
+	char    *mon_decimal_point;
+	char    *mon_grouping;
+	char    *mon_thousands_sep;
+	char    *negative_sign;
+	char     n_cs_precedes;
+	char     n_sep_by_space;
+	char     n_sign_posn;
+	char    *positive_sign;
+	char     p_cs_precedes;
+	char     p_sep_by_space;
+	char     p_sign_posn;
+	char    *thousands_sep;
+};
+
+extern char *posix_setlocale(int category, const char *locale);
+extern struct posix_lconv *posix_localeconv(void);
+
+/* POSIX Extensions */
+extern posix_locale_t posix_duplocale(posix_locale_t locobj);
+extern void posix_freelocale(posix_locale_t locobj);
+extern posix_locale_t posix_newlocale(int category_mask, const char *locale,
+    posix_locale_t base);
+extern posix_locale_t posix_uselocale (posix_locale_t newloc);
+
+#ifndef LIBPOSIX_INTERNAL
+	#define lconv posix_lconv
+
+	#define setlocale posix_setlocale
+	#define localeconv posix_localeconv
+
+	#define newlocale posix_newlocale
+	#define uselocale posix_uselocale
+	#define duplocale posix_duplocale
+	#define freelocale posix_freelocale
+#endif
+
+
+#endif /* POSIX_LOCALE_H_ */
+
+/** @}
+ */
Index: uspace/lib/posix/pwd.c
===================================================================
--- uspace/lib/posix/pwd.c	(revision f5b25224f3b95c0a700f5f9f6c8bb2ecad2c28f0)
+++ uspace/lib/posix/pwd.c	(revision 8cd8bf61fa7549be36c3193a2eff646b2c0f84ec)
@@ -47,5 +47,5 @@
 	.pw_gid = 1,
 	.pw_dir = (char *) "/",
-	.pw_shell = (char *) "bdsh"
+	.pw_shell = (char *) "/app/bdsh"
 };
 
Index: uspace/lib/posix/signal.c
===================================================================
--- uspace/lib/posix/signal.c	(revision 8cd8bf61fa7549be36c3193a2eff646b2c0f84ec)
+++ uspace/lib/posix/signal.c	(revision 8cd8bf61fa7549be36c3193a2eff646b2c0f84ec)
@@ -0,0 +1,373 @@
+/*
+ * Copyright (c) 2011 Jiri Zarevucky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libposix
+ * @{
+ */
+/** @file
+ */
+
+#define LIBPOSIX_INTERNAL
+
+#include "signal.h"
+#include "internal/common.h"
+#include "limits.h"
+#include "stdlib.h"
+#include "string.h"
+#include "errno.h"
+
+#include "libc/fibril_synch.h"
+#include "libc/task.h"
+
+/* Used to serialize signal handling. */
+static FIBRIL_MUTEX_INITIALIZE(_signal_mutex);
+
+static posix_sigset_t _signal_mask = 0;
+
+#define DEFAULT_HANDLER { .sa_handler = SIG_DFL, \
+    .sa_mask = 0, .sa_flags = 0, .sa_sigaction = NULL }
+
+static struct posix_sigaction _signal_actions[_TOP_SIGNAL + 1] = {
+	DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, 
+	DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, 
+	DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, 
+	DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, 
+	DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, 
+	DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, 
+	DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER
+};
+
+void __posix_default_signal_handler(int signo)
+{
+	switch (signo) {
+	case SIGABRT:
+		abort();
+	case SIGQUIT:
+		fprintf(stderr, "Quit signal raised. Exiting.");
+		exit(EXIT_FAILURE);
+	case SIGINT:
+		fprintf(stderr, "Interrupt signal caught. Exiting.");
+		exit(EXIT_FAILURE);
+	case SIGTERM:
+		fprintf(stderr, "Termination signal caught. Exiting.");
+		exit(EXIT_FAILURE);
+	case SIGSTOP:
+		fprintf(stderr, "Stop signal caught, but unsupported. Ignoring.");
+		break;
+	case SIGKILL:
+		/* This will only occur when raise or similar is called. */
+		/* Commit suicide. */
+		task_kill(task_get_id());
+		
+		/* Should not be reached. */
+		abort();
+	case SIGFPE:
+	case SIGBUS:
+	case SIGILL:
+	case SIGSEGV:
+		posix_psignal(signo, "Hardware exception raised by user code");
+		abort();
+	case SIGSYS:
+	case SIGXCPU:
+	case SIGXFSZ:
+	case SIGTRAP:
+	case SIGHUP:
+	case SIGPIPE:
+	case SIGPOLL:
+	case SIGURG:
+	case SIGTSTP:
+	case SIGTTIN:
+	case SIGTTOU:
+		posix_psignal(signo, "Unsupported signal caught");
+		abort();
+	case SIGCHLD:
+	case SIGUSR1:
+	case SIGUSR2:
+	case SIGALRM:
+	case SIGVTALRM:
+	case SIGPROF:
+	case SIGCONT:
+		/* ignored */
+		break;
+	}
+}
+
+void __posix_hold_signal_handler(int signo)
+{
+	/* Nothing */
+}
+
+void __posix_ignore_signal_handler(int signo)
+{
+	/* Nothing */
+}
+
+
+int posix_sigemptyset(posix_sigset_t *set)
+{
+	assert(set != NULL);
+
+	*set = 0;
+	return 0;
+}
+
+int posix_sigfillset(posix_sigset_t *set)
+{
+	assert(set != NULL);
+
+	*set = UINT32_MAX;
+	return 0;
+}
+
+int posix_sigaddset(posix_sigset_t *set, int signo)
+{
+	assert(set != NULL);
+
+	*set |= (1 << signo);
+	return 0;
+}
+
+int posix_sigdelset(posix_sigset_t *set, int signo)
+{
+	assert(set != NULL);
+
+	*set &= ~(1 << signo);
+	return 0;
+}
+
+int posix_sigismember(const posix_sigset_t *set, int signo)
+{
+	assert(set != NULL);
+	
+	return (*set & (1 << signo)) != 0;
+}
+
+static void _sigaction_unsafe(int sig, const struct posix_sigaction *restrict act,
+    struct posix_sigaction *restrict oact)
+{
+	if (oact != NULL) {
+		memcpy(oact, &_signal_actions[sig],
+		    sizeof(struct posix_sigaction));
+	}
+
+	if (act != NULL) {
+		memcpy(&_signal_actions[sig], act,
+		    sizeof(struct posix_sigaction));
+	}
+}
+
+int posix_sigaction(int sig, const struct posix_sigaction *restrict act,
+    struct posix_sigaction *restrict oact)
+{
+	if (sig > _TOP_SIGNAL || (act != NULL &&
+	    (sig == SIGKILL || sig == SIGSTOP))) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	if (sig > _TOP_CATCHABLE_SIGNAL) {
+		posix_psignal(sig,
+		    "WARNING: registering handler for a partially"
+		    " or fully unsupported signal. This handler may only be"
+		    " invoked by the raise() function, which may not be what"
+		    " the application developer intended.\nSignal name");
+	}
+
+	fibril_mutex_lock(&_signal_mutex);
+	_sigaction_unsafe(sig, act, oact);
+	fibril_mutex_unlock(&_signal_mutex);
+
+	return 0;
+}
+
+void (*posix_signal(int sig, void (*func)(int)))(int)
+{
+	struct posix_sigaction new = {
+		.sa_handler = func,
+		.sa_mask = 0,
+		.sa_flags = 0,
+		.sa_sigaction = NULL
+	};
+	struct posix_sigaction old;
+	if (posix_sigaction(sig, func == NULL ? NULL : &new, &old) == 0) {
+		return old.sa_handler;
+	} else {
+		return SIG_ERR;
+	}
+}
+
+static int _raise_sigaction(int signo, posix_siginfo_t *siginfo)
+{
+	assert(signo >= 0 && signo <= _TOP_SIGNAL);
+	assert(siginfo != NULL);
+
+	fibril_mutex_lock(&_signal_mutex);
+
+	struct posix_sigaction action = _signal_actions[signo];
+
+	if (posix_sigismember(&_signal_mask, signo) ||
+	    action.sa_handler == SIG_HOLD) {
+		// TODO: queue signal
+		fibril_mutex_unlock(&_signal_mutex);
+		return -1;
+	}
+
+	/* Modifying signal mask is unnecessary,
+	 * signal handling is serialized.
+	 */
+
+	if ((action.sa_flags & SA_RESETHAND) && signo != SIGILL && signo != SIGTRAP) {
+		_signal_actions[signo] = (struct posix_sigaction) DEFAULT_HANDLER;
+	};
+
+	if (action.sa_flags & SA_SIGINFO) {
+		assert(action.sa_sigaction != NULL);
+		action.sa_sigaction(signo, siginfo, NULL);
+	} else {
+		assert(action.sa_handler != NULL);
+		action.sa_handler(signo);
+	}
+
+	fibril_mutex_unlock(&_signal_mutex);
+
+	return 0;
+}
+
+int posix_raise(int sig)
+{
+	if (sig >= 0 && sig <= _TOP_SIGNAL) {
+		posix_siginfo_t siginfo = {
+			.si_signo = sig,
+			.si_code = SI_USER
+		};
+		return _raise_sigaction(sig, &siginfo);
+	} else {
+		errno = EINVAL;
+		return -1;
+	}
+}
+
+int posix_kill(posix_pid_t pid, int signo)
+{
+	if (pid < 1) {
+		// TODO
+		errno = ENOTSUP;
+		return -1;
+	}
+
+	if (pid == task_get_id()) {
+		return posix_raise(signo);
+	}
+
+	if (pid > _TOP_SIGNAL) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	switch (signo) {
+	case SIGKILL:
+		task_kill(pid);
+		break;
+	default:
+		/* Nothing else supported yet. */
+		errno = ENOTSUP;
+		return -1;
+	}
+
+	return 0;
+}
+
+int posix_killpg(posix_pid_t pid, int sig)
+{
+	assert(pid > 1);
+	return posix_kill(-pid, sig);
+}
+
+void posix_psiginfo(const posix_siginfo_t *pinfo, const char *message)
+{
+	assert(pinfo != NULL);
+	posix_psignal(pinfo->si_signo, message);
+	// TODO: print si_code
+}
+
+void posix_psignal(int signum, const char *message)
+{
+	char *sigmsg = posix_strsignal(signum);
+	if (message == NULL || *message == '\0') {
+		fprintf(stderr, "%s\n", sigmsg);
+	} else {
+		fprintf(stderr, "%s: %s\n", message, sigmsg);
+	}
+}
+
+int posix_thread_sigmask(int how, const posix_sigset_t *restrict set,
+    posix_sigset_t *restrict oset)
+{
+	fibril_mutex_lock(&_signal_mutex);
+
+	if (oset != NULL) {
+		*oset = _signal_mask;
+	}
+	if (set != NULL) {
+		switch (how) {
+		case SIG_BLOCK:
+			_signal_mask |= *set;
+			break;
+		case SIG_UNBLOCK:
+			_signal_mask &= ~*set;
+			break;
+		case SIG_SETMASK:
+			_signal_mask = *set;
+			break;
+		default:
+			fibril_mutex_unlock(&_signal_mutex);
+			return EINVAL;
+		}
+	}
+
+	// TODO: queued signal handling
+
+	fibril_mutex_unlock(&_signal_mutex);
+
+	return 0;
+}
+
+int posix_sigprocmask(int how, const posix_sigset_t *restrict set,
+    posix_sigset_t *restrict oset)
+{
+	int result = posix_thread_sigmask(how, set, oset);
+	if (result != 0) {
+		errno = result;
+		return -1;
+	}
+	return 0;
+}
+
+/** @}
+ */
+
Index: uspace/lib/posix/signal.h
===================================================================
--- uspace/lib/posix/signal.h	(revision f5b25224f3b95c0a700f5f9f6c8bb2ecad2c28f0)
+++ uspace/lib/posix/signal.h	(revision 8cd8bf61fa7549be36c3193a2eff646b2c0f84ec)
@@ -39,28 +39,19 @@
 #include "sys/types.h"
 
-/* HelenOS doesn't have signals, so calls to functions of this header
- * are just replaced with their respective failure return value.
- *
- * Other macros and constants are here just to satisfy the symbol resolver
- * and have no practical value whatsoever, until HelenOS implements some
- * equivalent of signals. Maybe something neat based on IPC will be devised
- * in the future?
- */
+extern void __posix_default_signal_handler(int signo);
+extern void __posix_hold_signal_handler(int signo);
+extern void __posix_ignore_signal_handler(int signo);
 
 #undef SIG_DFL
-#define SIG_DFL ((void (*)(int)) 0)
+#define SIG_DFL ((void (*)(int)) __posix_default_signal_handler)
 #undef SIG_ERR
-#define SIG_ERR ((void (*)(int)) 0)
+#define SIG_ERR ((void (*)(int)) NULL)
 #undef SIG_HOLD
-#define SIG_HOLD ((void (*)(int)) 0)
+#define SIG_HOLD ((void (*)(int)) __posix_hold_signal_handler)
 #undef SIG_IGN
-#define SIG_IGN ((void (*)(int)) 0)
-
-#define signal(sig,func) (errno = ENOTSUP, SIG_ERR)
-#define raise(sig) ((int) -1)
-#define kill(pid,sig) (errno = ENOTSUP, (int) -1)
+#define SIG_IGN ((void (*)(int)) __posix_ignore_signal_handler)
 
 typedef int posix_sig_atomic_t;
-typedef int posix_sigset_t;
+typedef uint32_t posix_sigset_t;
 typedef struct posix_mcontext {
 	// FIXME: should not be empty to avoid compiler warnings (-pedantic)
@@ -87,6 +78,6 @@
 	int si_errno;
 
-	pid_t si_pid;
-	uid_t si_uid;
+	posix_pid_t si_pid;
+	posix_uid_t si_uid;
 	void *si_addr;
 	int si_status;
@@ -120,81 +111,170 @@
 /* Values of posix_sigevent::sigev_notify */
 #undef SIGEV_NONE
+#undef SIGEV_SIGNAL
+#undef SIGEV_THREAD
 #define SIGEV_NONE 0
-#undef SIGEV_SIGNAL
 #define SIGEV_SIGNAL 0
-#undef SIGEV_THREAD
 #define SIGEV_THREAD 0
 
 #undef SIGRT_MIN
+#undef SIGRT_MAX
 #define SIGRT_MIN 0
-#undef SIGRT_MAX
 #define SIGRT_MAX 0
 
 #undef SIG_BLOCK
+#undef SIG_UNBLOCK
+#undef SIG_SETMASK
 #define SIG_BLOCK 0
-#undef SIG_UNBLOCK
-#define SIG_UNBLOCK 0
-#undef SIG_SETMASK
-#define SIG_SETMASK 0
+#define SIG_UNBLOCK 1
+#define SIG_SETMASK 2
 
 #undef SA_NOCLDSTOP
-#define SA_NOCLDSTOP 0
 #undef SA_ONSTACK
-#define SA_ONSTACK 0
 #undef SA_RESETHAND
-#define SA_RESETHAND 0
 #undef SA_RESTART
-#define SA_RESTART 0
 #undef SA_SIGINFO
-#define SA_SIGINFO 0
 #undef SA_NOCLDWAIT
-#define SA_NOCLDWAIT 0
 #undef SA_NODEFER
-#define SA_NODEFER 0
+#define SA_NOCLDSTOP (1 << 0)
+#define SA_ONSTACK (1 << 1)
+#define SA_RESETHAND (1 << 2)
+#define SA_RESTART (1 << 3)
+#define SA_SIGINFO (1 << 4)
+#define SA_NOCLDWAIT (1 << 5)
+#define SA_NODEFER (1 << 6)
 
 #undef SS_ONSTACK
+#undef SS_DISABLE
 #define SS_ONSTACK 0
-#undef SS_DISABLE
 #define SS_DISABLE 0
 
 #undef MINSIGSTKSZ
+#undef SIGSTKSZ
 #define MINSIGSTKSZ 0
-#undef SIGSTKSZ
 #define SIGSTKSZ 0
 
 /* full POSIX set */
 enum {
+	/* Termination Signals */
 	SIGABRT,
+	SIGQUIT,
+	SIGINT,
+	SIGTERM,
+	
+	/* Child Signal */
+	SIGCHLD,
+	
+	/* User signals */
+	SIGUSR1,
+	SIGUSR2,
+
+	/* Timer */
 	SIGALRM,
+	SIGVTALRM,
+	SIGPROF, /* obsolete */
+
+	_TOP_CATCHABLE_SIGNAL = SIGPROF,
+
+	/* Process Scheduler Interaction - not supported */
+	SIGSTOP,
+	SIGCONT,
+
+	/* Process Termination - can't be caught */
+	SIGKILL,
+
+	_TOP_SENDABLE_SIGNAL = SIGKILL,
+
+	/* Hardware Exceptions - can't be caught or sent */
+	SIGFPE,
 	SIGBUS,
-	SIGCHLD,
-	SIGCONT,
-	SIGFPE,
+	SIGILL,
+	SIGSEGV,
+
+	/* Other Exceptions - not supported */
+	SIGSYS,
+	SIGXCPU,
+	SIGXFSZ,
+
+	/* Debugging - not supported */
+	SIGTRAP,
+
+	/* Communication Signals - not supported */
 	SIGHUP,
-	SIGILL,
-	SIGINT,
-	SIGKILL,
 	SIGPIPE,
-	SIGQUIT,
-	SIGSEGV,
-	SIGSTOP,
-	SIGTERM,
+	SIGPOLL, /* obsolete */
+	SIGURG,
+
+	/* Terminal Signals - not supported */
 	SIGTSTP,
 	SIGTTIN,
 	SIGTTOU,
-	SIGUSR1,
-	SIGUSR2,
-	SIGPOLL,
-	SIGPROF,
-	SIGSYS,
-	SIGTRAP,
-	SIGURG,
-	SIGVTALRM,
-	SIGXCPU,
-	SIGXFSZ
-};
-
-/* Just declared to avoid compiler warnings. */
+	
+	_TOP_SIGNAL = SIGTTOU
+};
+
+/* Values for sigaction field si_code. */
+
+enum {
+	SI_USER,
+	SI_QUEUE,
+	SI_TIMER,
+	SI_ASYNCIO,
+	SI_MESGQ,
+	ILL_ILLOPC,
+	ILL_ILLOPN,
+	ILL_ILLADR,
+	ILL_ILLTRP,
+	ILL_PRVOPC,
+	ILL_PRVREG,
+	ILL_COPROC,
+	ILL_BADSTK,
+	FPE_INTDIV,
+	FPE_INTOVF,
+	FPE_FLTDIV,
+	FPE_FLTOVF,
+	FPE_FLTUND,
+	FPE_FLTRES,
+	FPE_FLTINV,
+	FPE_FLTSUB,
+	SEGV_MAPERR,
+	SEGV_ACCERR,
+	BUS_ADRALN,
+	BUS_ADRERR,
+	BUS_OBJERR,
+	TRAP_BRKPT,
+	TRAP_TRACE,
+	CLD_EXITED,
+	CLD_KILLED,
+	CLD_DUMPED,
+	CLD_TRAPPED,
+	CLD_STOPPED,
+	CLD_CONTINUED,
+	POLL_IN,
+	POLL_OUT,
+	POLL_MSG,
+	POLL_ERR,
+	POLL_PRI,
+	POLL_HUP
+};
+
+extern int posix_sigaction(int sig, const struct posix_sigaction *restrict act,
+    struct posix_sigaction *restrict oact);
+
+extern void (*posix_signal(int sig, void (*func)(int)))(int);
+extern int posix_raise(int sig);
+extern int posix_kill(posix_pid_t pid, int sig);
+extern int posix_killpg(posix_pid_t pid, int sig);
+
+extern void posix_psiginfo(const posix_siginfo_t *pinfo, const char *message);
+extern void posix_psignal(int signum, const char *message);
+
 extern int posix_sigemptyset(posix_sigset_t *set);
+extern int posix_sigfillset(posix_sigset_t *set);
+extern int posix_sigaddset(posix_sigset_t *set, int signo);
+extern int posix_sigdelset(posix_sigset_t *set, int signo);
+extern int posix_sigismember(const posix_sigset_t *set, int signo);
+
+extern int posix_thread_sigmask(int how, const posix_sigset_t *restrict set,
+    posix_sigset_t *restrict oset);
 extern int posix_sigprocmask(int how, const posix_sigset_t *restrict set,
     posix_sigset_t *restrict oset);
@@ -204,5 +284,7 @@
 	#define sigset_t posix_sigset_t
 	#define sigval posix_sigval
-	#define sigevent posix_sigevent
+	#ifndef sigevent
+		#define sigevent posix_sigevent
+	#endif
 	#define sigaction posix_sigaction
 	#define mcontext_t posix_mcontext_t
@@ -210,5 +292,20 @@
 	#define stack_t posix_stack_t
 	#define siginfo_t posix_siginfo_t
+
+	#define signal posix_signal
+	#define raise posix_raise
+	#define kill posix_kill
+	#define killpg posix_killpg
+
+	#define psiginfo posix_psiginfo
+	#define psignal posix_psignal
+
 	#define sigemptyset posix_sigemptyset
+	#define sigfillset posix_sigfillset
+	#define sigaddset posix_sigaddset
+	#define sigdelset posix_sigdelset
+	#define sigismember posix_sigismember
+
+	#define pthread_sigmask posix_thread_sigmask
 	#define sigprocmask posix_sigprocmask
 #endif
Index: uspace/lib/posix/stdbool.h
===================================================================
--- uspace/lib/posix/stdbool.h	(revision f5b25224f3b95c0a700f5f9f6c8bb2ecad2c28f0)
+++ uspace/lib/posix/stdbool.h	(revision 8cd8bf61fa7549be36c3193a2eff646b2c0f84ec)
@@ -40,5 +40,5 @@
 
 #ifdef LIBC_BOOL_H_
-	#error You can't include bool.h and stdbool.h at the same time.
+	#error "You can't include bool.h and stdbool.h at the same time."
 #endif
 #define LIBC_BOOL_H_
Index: uspace/lib/posix/stdint.h
===================================================================
--- uspace/lib/posix/stdint.h	(revision f5b25224f3b95c0a700f5f9f6c8bb2ecad2c28f0)
+++ uspace/lib/posix/stdint.h	(revision 8cd8bf61fa7549be36c3193a2eff646b2c0f84ec)
@@ -35,4 +35,6 @@
 #ifndef POSIX_STDINT_H_
 #define POSIX_STDINT_H_
+
+#include "libc/stdint.h"
 
 #undef INT8_MAX
Index: uspace/lib/posix/stdio.c
===================================================================
--- uspace/lib/posix/stdio.c	(revision f5b25224f3b95c0a700f5f9f6c8bb2ecad2c28f0)
+++ uspace/lib/posix/stdio.c	(revision 8cd8bf61fa7549be36c3193a2eff646b2c0f84ec)
@@ -36,34 +36,197 @@
 #define LIBPOSIX_INTERNAL
 
-#include <assert.h>
-#include <errno.h>
+/* Has to be first. */
+#include "stdbool.h"
 
 #include "internal/common.h"
 #include "stdio.h"
+
+#include "assert.h"
+#include "errno.h"
 #include "string.h"
-
-/* not the best of solutions, but freopen will eventually
+#include "sys/types.h"
+
+#include "libc/io/printf_core.h"
+#include "libc/str.h"
+#include "libc/malloc.h"
+
+
+/* not the best of solutions, but freopen and ungetc will eventually
  * need to be implemented in libc anyway
  */
 #include "../c/generic/private/stdio.h"
 
-/**
- * 
- * @param c
- * @param stream
- * @return 
+/** Clears the stream's error and end-of-file indicators.
+ *
+ * @param stream Stream whose indicators shall be cleared.
+ */
+void posix_clearerr(FILE *stream)
+{
+	stream->error = 0;
+	stream->eof = 0;
+}
+
+/**
+ * Generate a pathname for the controlling terminal.
+ *
+ * @param s Allocated buffer to which the pathname shall be put.
+ * @return Either s or static location filled with the requested pathname.
+ */
+char *posix_ctermid(char *s)
+{
+	/* Currently always returns an error value (empty string). */
+	// TODO: return a real terminal path
+
+	static char dummy_path[L_ctermid] = {'\0'};
+
+	if (s == NULL) {
+		return dummy_path;
+	}
+
+	s[0] = '\0';
+	return s;
+}
+
+/**
+ * Push byte back into input stream.
+ * 
+ * @param c Byte to be pushed back.
+ * @param stream Stream to where the byte shall be pushed.
+ * @return Provided byte on success or EOF if not possible.
  */
 int posix_ungetc(int c, FILE *stream)
 {
-	// TODO
-	not_implemented();
-}
-
-/**
- * 
- * @param filename
- * @param mode
- * @param stream
- * @return
+	uint8_t b = (uint8_t) c;
+
+	bool can_unget =
+		/* Provided character is legal. */
+	    c != EOF &&
+		/* Stream is consistent. */
+	    !stream->error &&
+		/* Stream is buffered. */
+	    stream->btype != _IONBF &&
+		/* Last operation on the stream was a read operation. */
+	    stream->buf_state == _bs_read &&
+		/* Stream buffer is already allocated (i.e. there was already carried
+		 * out either write or read operation on the stream). This is probably
+		 * redundant check but let's be safe. */
+	    stream->buf != NULL &&
+		/* There is still space in the stream to retreat. POSIX demands the
+		 * possibility to unget at least 1 character. It should be always
+		 * possible, assuming the last operation on the stream read at least 1
+		 * character, because the buffer is refilled in the lazily manner. */
+	    stream->buf_tail > stream->buf;
+
+	if (can_unget) {
+		--stream->buf_tail;
+		stream->buf_tail[0] = b;
+		stream->eof = false;
+		return (int) b;
+	} else {
+		return EOF;
+	}
+}
+
+/**
+ * Read a stream until the delimiter (or EOF) is encountered.
+ *
+ * @param lineptr Pointer to the output buffer in which there will be stored
+ *     nul-terminated string together with the delimiter (if encountered).
+ *     Will be resized if necessary.
+ * @param n Pointer to the size of the output buffer. Will be increased if
+ *     necessary.
+ * @param delimiter Delimiter on which to finish reading the stream.
+ * @param stream Input stream.
+ * @return Number of fetched characters (including delimiter if encountered)
+ *     or -1 on error (set in errno).
+ */
+ssize_t posix_getdelim(char **restrict lineptr, size_t *restrict n,
+    int delimiter, FILE *restrict stream)
+{
+	/* Check arguments for sanity. */
+	if (!lineptr || !n) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	size_t alloc_step = 80; /* Buffer size gain during reallocation. */
+	char *pos = *lineptr; /* Next free byte of the output buffer. */
+	size_t cnt = 0; /* Number of fetched characters. */
+	int c = fgetc(stream); /* Current input character. Might be EOF. */
+
+	do {
+		/* Mask EOF as NUL to terminate string. */
+		if (c == EOF) {
+			c = '\0';
+		}
+
+		/* Ensure there is still space left in the buffer. */
+		if (pos == *lineptr + *n) {
+			*lineptr = realloc(*lineptr, *n + alloc_step);
+			if (*lineptr) {
+				pos = *lineptr + *n;
+				*n += alloc_step;
+			} else {
+				errno = ENOMEM;
+				return -1;
+			}
+		}
+
+		/* Store the fetched character. */
+		*pos = c;
+
+		/* Fetch the next character according to the current character. */
+		if (c != '\0') {
+			++pos;
+			++cnt;
+			if (c == delimiter) {
+				/* Delimiter was just stored. Provide EOF as the next
+				 * character - it will be masked as NUL and output string
+				 * will be properly terminated. */
+				c = EOF;
+			} else {
+				/* Neither delimiter nor EOF were encountered. Just fetch
+				 * the next character from the stream. */
+				c = fgetc(stream);
+			}
+		}
+	} while (c != '\0');
+
+	if (errno == EOK && cnt > 0) {
+		return cnt;
+	} else {
+		/* Either some error occured or the stream was already at EOF. */
+		return -1;
+	}
+}
+
+/**
+ * Read a stream until the newline (or EOF) is encountered.
+ * 
+ * @param lineptr Pointer to the output buffer in which there will be stored
+ *     nul-terminated string together with the delimiter (if encountered).
+ *     Will be resized if necessary.
+ * @param n Pointer to the size of the output buffer. Will be increased if
+ *     necessary.
+ * @param stream Input stream.
+ * @return Number of fetched characters (including newline if encountered)
+ *     or -1 on error (set in errno).
+ */
+ssize_t posix_getline(char **restrict lineptr, size_t *restrict n,
+    FILE *restrict stream)
+{
+	return posix_getdelim(lineptr, n, '\n', stream);
+}
+
+/**
+ * Reopen a file stream.
+ * 
+ * @param filename Pathname of a file to be reopened or NULL for changing
+ *     the mode of the stream.
+ * @param mode Mode to be used for reopening the file or changing current
+ *     mode of the stream.
+ * @param stream Current stream associated with the opened file.
+ * @return On success, either a stream of the reopened file or the provided
+ *     stream with a changed mode. NULL otherwise.
  */
 FILE *posix_freopen(
@@ -115,7 +278,11 @@
 /**
  *
- * @param s
- */
-void posix_perror(const char *s)
+ * @param buf
+ * @param size
+ * @param mode
+ * @return
+ */
+FILE *posix_fmemopen(void *restrict buf, size_t size,
+    const char *restrict mode)
 {
 	// TODO
@@ -124,11 +291,10 @@
 
 /**
- * 
- * @param stream
- * @param offset
- * @param whence
+ *
+ * @param bufp
+ * @param sizep
  * @return
  */
-int posix_fseeko(FILE *stream, posix_off_t offset, int whence)
+FILE *posix_open_memstream(char **bufp, size_t *sizep)
 {
 	// TODO
@@ -137,35 +303,362 @@
 
 /**
- * 
- * @param stream
+ * Write error messages to standard error.
+ *
+ * @param s Error message.
+ */
+void posix_perror(const char *s)
+{
+	if (s == NULL || s[0] == '\0') {
+		fprintf(stderr, "%s\n", posix_strerror(errno));
+	} else {
+		fprintf(stderr, "%s: %s\n", s, posix_strerror(errno));
+	}
+}
+
+struct _posix_fpos {
+	off64_t offset;
+};
+
+/** Restores stream a to position previously saved with fgetpos().
+ *
+ * @param stream Stream to restore
+ * @param pos Position to restore
+ * @return Zero on success, non-zero (with errno set) on failure
+ */
+int posix_fsetpos(FILE *stream, const posix_fpos_t *pos)
+{
+	return fseek(stream, pos->offset, SEEK_SET);
+}
+
+/** Saves the stream's position for later use by fsetpos().
+ *
+ * @param stream Stream to save
+ * @param pos Place to store the position
+ * @return Zero on success, non-zero (with errno set) on failure
+ */
+int posix_fgetpos(FILE *restrict stream, posix_fpos_t *restrict pos)
+{
+	off64_t ret = ftell(stream);
+	if (ret == -1) {
+		return errno;
+	}
+	pos->offset = ret;
+	return 0;
+}
+
+/**
+ * Reposition a file-position indicator in a stream.
+ * 
+ * @param stream Stream to seek in.
+ * @param offset Direction and amount of bytes to seek.
+ * @param whence From where to seek.
+ * @return Zero on success, -1 otherwise.
+ */
+int posix_fseek(FILE *stream, long offset, int whence)
+{
+	return fseek(stream, (off64_t) offset, whence);
+}
+
+/**
+ * Reposition a file-position indicator in a stream.
+ * 
+ * @param stream Stream to seek in.
+ * @param offset Direction and amount of bytes to seek.
+ * @param whence From where to seek.
+ * @return Zero on success, -1 otherwise.
+ */
+int posix_fseeko(FILE *stream, posix_off_t offset, int whence)
+{
+	return fseek(stream, (off64_t) offset, whence);
+}
+
+/**
+ * Discover current file offset in a stream.
+ * 
+ * @param stream Stream for which the offset shall be retrieved.
+ * @return Current offset or -1 if not possible.
+ */
+long posix_ftell(FILE *stream)
+{
+	return (long) ftell(stream);
+}
+
+/**
+ * Discover current file offset in a stream.
+ * 
+ * @param stream Stream for which the offset shall be retrieved.
+ * @return Current offset or -1 if not possible.
+ */
+posix_off_t posix_ftello(FILE *stream)
+{
+	return (posix_off_t) ftell(stream);
+}
+
+/**
+ * Print formatted output to the opened file.
+ *
+ * @param fildes File descriptor of the opened file.
+ * @param format Format description.
+ * @return Either the number of printed characters or negative value on error.
+ */
+int posix_dprintf(int fildes, const char *restrict format, ...)
+{
+	va_list list;
+	va_start(list, format);
+	int result = posix_vdprintf(fildes, format, list);
+	va_end(list);
+	return result;
+}
+
+/**
+ * Write ordinary string to the opened file.
+ *
+ * @param str String to be written.
+ * @param size Size of the string (in bytes)..
+ * @param fd File descriptor of the opened file.
+ * @return The number of written characters.
+ */
+static int _dprintf_str_write(const char *str, size_t size, void *fd)
+{
+	ssize_t wr = write(*(int *) fd, str, size);
+	return str_nlength(str, wr);
+}
+
+/**
+ * Write wide string to the opened file.
+ * 
+ * @param str String to be written.
+ * @param size Size of the string (in bytes).
+ * @param fd File descriptor of the opened file.
+ * @return The number of written characters.
+ */
+static int _dprintf_wstr_write(const wchar_t *str, size_t size, void *fd)
+{
+	size_t offset = 0;
+	size_t chars = 0;
+	size_t sz;
+	char buf[4];
+	
+	while (offset < size) {
+		sz = 0;
+		if (chr_encode(str[chars], buf, &sz, sizeof(buf)) != EOK) {
+			break;
+		}
+		
+		if (write(*(int *) fd, buf, sz) != (ssize_t) sz) {
+			break;
+		}
+		
+		chars++;
+		offset += sizeof(wchar_t);
+	}
+	
+	return chars;
+}
+
+/**
+ * Print formatted output to the opened file.
+ * 
+ * @param fildes File descriptor of the opened file.
+ * @param format Format description.
+ * @param ap Print arguments.
+ * @return Either the number of printed characters or negative value on error.
+ */
+int posix_vdprintf(int fildes, const char *restrict format, va_list ap)
+{
+	printf_spec_t spec = {
+		.str_write = _dprintf_str_write,
+		.wstr_write = _dprintf_wstr_write,
+		.data = &fildes
+	};
+	
+	return printf_core(format, &spec, ap);
+}
+
+/**
+ * Print formatted output to the string.
+ * 
+ * @param s Output string.
+ * @param format Format description.
+ * @return Either the number of printed characters (excluding null byte) or
+ *     negative value on error.
+ */
+int posix_sprintf(char *s, const char *restrict format, ...)
+{
+	va_list list;
+	va_start(list, format);
+	int result = posix_vsprintf(s, format, list);
+	va_end(list);
+	return result;
+}
+
+/**
+ * Print formatted output to the string.
+ * 
+ * @param s Output string.
+ * @param format Format description.
+ * @param ap Print arguments.
+ * @return Either the number of printed characters (excluding null byte) or
+ *     negative value on error.
+ */
+int posix_vsprintf(char *s, const char *restrict format, va_list ap)
+{
+	return vsnprintf(s, STR_NO_LIMIT, format, ap);
+}
+
+/**
+ * Convert formatted input from the stream.
+ * 
+ * @param stream Input stream.
+ * @param format Format description.
+ * @return The number of converted output items or EOF on failure.
+ */
+int posix_fscanf(FILE *restrict stream, const char *restrict format, ...)
+{
+	va_list list;
+	va_start(list, format);
+	int result = posix_vfscanf(stream, format, list);
+	va_end(list);
+	return result;
+}
+
+/**
+ * Convert formatted input from the standard input.
+ * 
+ * @param format Format description.
+ * @return The number of converted output items or EOF on failure.
+ */
+int posix_scanf(const char *restrict format, ...)
+{
+	va_list list;
+	va_start(list, format);
+	int result = posix_vscanf(format, list);
+	va_end(list);
+	return result;
+}
+
+/**
+ * Convert formatted input from the standard input.
+ * 
+ * @param format Format description.
+ * @param arg Output items.
+ * @return The number of converted output items or EOF on failure.
+ */
+int posix_vscanf(const char *restrict format, va_list arg)
+{
+	return posix_vfscanf(stdin, format, arg);
+}
+
+/**
+ * Convert formatted input from the string.
+ * 
+ * @param s Input string.
+ * @param format Format description.
+ * @return The number of converted output items or EOF on failure.
+ */
+int posix_sscanf(const char *restrict s, const char *restrict format, ...)
+{
+	va_list list;
+	va_start(list, format);
+	int result = posix_vsscanf(s, format, list);
+	va_end(list);
+	return result;
+}
+
+/**
+ * Acquire file stream for the thread.
+ *
+ * @param file File stream to lock.
+ */
+void posix_flockfile(FILE *file)
+{
+	/* dummy */
+}
+
+/**
+ * Acquire file stream for the thread (non-blocking).
+ *
+ * @param file File stream to lock.
+ * @return Zero for success and non-zero if the lock cannot be acquired.
+ */
+int posix_ftrylockfile(FILE *file)
+{
+	/* dummy */
+	return 0;
+}
+
+/**
+ * Relinquish the ownership of the locked file stream.
+ *
+ * @param file File stream to unlock.
+ */
+void posix_funlockfile(FILE *file)
+{
+	/* dummy */
+}
+
+/**
+ * Get a byte from a stream (thread-unsafe).
+ *
+ * @param stream Input file stream.
+ * @return Either read byte or EOF.
+ */
+int posix_getc_unlocked(FILE *stream)
+{
+	return getc(stream);
+}
+
+/**
+ * Get a byte from the standard input stream (thread-unsafe).
+ *
+ * @return Either read byte or EOF.
+ */
+int posix_getchar_unlocked(void)
+{
+	return getchar();
+}
+
+/**
+ * Put a byte on a stream (thread-unsafe).
+ *
+ * @param c Byte to output.
+ * @param stream Output file stream.
+ * @return Either written byte or EOF.
+ */
+int posix_putc_unlocked(int c, FILE *stream)
+{
+	return putc(c, stream);
+}
+
+/**
+ * Put a byte on the standard output stream (thread-unsafe).
+ * 
+ * @param c Byte to output.
+ * @return Either written byte or EOF.
+ */
+int posix_putchar_unlocked(int c)
+{
+	return putchar(c);
+}
+
+/**
+ * Remove a file.
+ *
+ * @param path Pathname of the file that shall be removed.
+ * @return Zero on success, -1 otherwise.
+ */
+int posix_remove(const char *path)
+{
+	// FIXME: unlink() and rmdir() seem to be equivalent at the moment,
+	//        but that does not have to be true forever
+	return unlink(path);
+}
+
+/**
+ * 
+ * @param s
  * @return
  */
-posix_off_t posix_ftello(FILE *stream)
-{
-	// TODO
-	not_implemented();
-}
-
-/**
- * 
- * @param s
- * @param format
- * @param ...
- * @return
- */
-int posix_sprintf(char *s, const char *format, ...)
-{
-	// TODO
-	not_implemented();
-}
-
-/**
- * 
- * @param s
- * @param format
- * @param ...
- * @return
- */
-int posix_vsprintf(char *s, const char *format, va_list ap)
+char *posix_tmpnam(char *s)
 {
 	// TODO: low priority, just a compile-time dependency of binutils
@@ -173,39 +666,4 @@
 }
 
-/**
- * 
- * @param s
- * @param format
- * @param ...
- * @return
- */
-int posix_sscanf(const char *s, const char *format, ...)
-{
-	// TODO
-	not_implemented();
-}
-
-/**
- *
- * @param path
- * @return
- */
-int posix_remove(const char *path)
-{
-	// TODO: low priority, just a compile-time dependency of binutils
-	not_implemented();
-}
-
-/**
- * 
- * @param s
- * @return
- */
-char *posix_tmpnam(char *s)
-{
-	// TODO: low priority, just a compile-time dependency of binutils
-	not_implemented();
-}
-
 /** @}
  */
Index: uspace/lib/posix/stdio.h
===================================================================
--- uspace/lib/posix/stdio.h	(revision f5b25224f3b95c0a700f5f9f6c8bb2ecad2c28f0)
+++ uspace/lib/posix/stdio.h	(revision 8cd8bf61fa7549be36c3193a2eff646b2c0f84ec)
@@ -40,6 +40,13 @@
 #include "sys/types.h"
 #include "libc/stdarg.h"
+#include "limits.h"
 
-/* Character Input/Output */
+#undef L_ctermid
+#define L_ctermid PATH_MAX
+
+extern void posix_clearerr(FILE *stream);
+extern char *posix_ctermid(char *s);
+
+/* Input/Output */
 #undef putc
 #define putc fputc
@@ -47,4 +54,9 @@
 #define getc fgetc
 extern int posix_ungetc(int c, FILE *stream);
+
+extern ssize_t posix_getdelim(char **restrict lineptr, size_t *restrict n,
+    int delimiter, FILE *restrict stream);
+extern ssize_t posix_getline(char **restrict lineptr, size_t *restrict n,
+    FILE *restrict stream);
 
 /* Opening Streams */
@@ -54,15 +66,52 @@
    FILE *restrict stream);
 
+/* Memory Streams */
+
+extern FILE *posix_fmemopen(void *restrict buf, size_t size,
+    const char *restrict mode);
+extern FILE *posix_open_memstream(char **bufp, size_t *sizep);
+
 /* Error Messages */
 extern void posix_perror(const char *s);
 
 /* File Positioning */
+
+typedef struct _posix_fpos posix_fpos_t;
+extern int posix_fsetpos(FILE *stream, const posix_fpos_t *pos);
+extern int posix_fgetpos(FILE *restrict stream, posix_fpos_t *restrict pos);
+extern int posix_fseek(FILE *stream, long offset, int whence);
 extern int posix_fseeko(FILE *stream, posix_off_t offset, int whence);
+extern long posix_ftell(FILE *stream);
 extern posix_off_t posix_ftello(FILE *stream);
 
 /* Formatted Input/Output */
-extern int posix_sprintf(char *restrict s, const char *restrict format, ...);
+extern int posix_dprintf(int fildes, const char *restrict format, ...)
+    PRINTF_ATTRIBUTE(2, 3);
+extern int posix_vdprintf(int fildes, const char *restrict format, va_list ap);
+extern int posix_sprintf(char *restrict s, const char *restrict format, ...)
+    PRINTF_ATTRIBUTE(2, 3);
 extern int posix_vsprintf(char *restrict s, const char *restrict format, va_list ap);
-extern int posix_sscanf(const char *restrict s, const char *restrict format, ...);
+
+extern int posix_fscanf(
+    FILE *restrict stream, const char *restrict format, ...);
+extern int posix_vfscanf(
+    FILE *restrict stream, const char *restrict format, va_list arg);
+extern int posix_scanf(const char *restrict format, ...);
+extern int posix_vscanf(const char *restrict format, va_list arg);
+extern int posix_sscanf(
+    const char *restrict s, const char *restrict format, ...);
+extern int posix_vsscanf(
+    const char *restrict s, const char *restrict format, va_list arg);
+
+/* File Locking */
+
+extern void posix_flockfile(FILE *file);
+extern int posix_ftrylockfile(FILE *file);
+extern void posix_funlockfile(FILE *file);
+
+extern int posix_getc_unlocked(FILE *stream);
+extern int posix_getchar_unlocked(void);
+extern int posix_putc_unlocked(int c, FILE *stream);
+extern int posix_putchar_unlocked(int c);
 
 /* Deleting Files */
@@ -76,16 +125,47 @@
 
 #ifndef LIBPOSIX_INTERNAL
+	#define clearerr posix_clearerr
+	#define ctermid posix_ctermid
+
 	#define ungetc posix_ungetc
+
+	#define getdelim posix_getdelim
+	#define getline posix_getline
 
 	#define freopen posix_freopen
 
+	#define fmemopen posix_fmemopen
+	#define open_memstream posix_open_memstream
+
 	#define perror posix_perror
 
+	#define fpos_t posix_fpos_t
+	#define fsetpos posix_fsetpos
+	#define fgetpos posix_fgetpos
+	#define fseek posix_fseek
 	#define fseeko posix_fseeko
+	#define ftell posix_ftell
 	#define ftello posix_ftello
 
+	#define dprintf posix_dprintf
+	#define vdprintf posix_vdprintf
 	#define sprintf posix_sprintf
 	#define vsprintf posix_vsprintf
+
+	#define fscanf posix_fscanf
+	#define vfscanf posix_vfscanf
+	#define vscanf posix_vscanf
+	#define scanf posix_scanf
 	#define sscanf posix_sscanf
+	#define vsscanf posix_vsscanf
+
+	#define flockfile posix_flockfile
+	#define ftrylockfile posix_ftrylockfile
+	#define funlockfile posix_funlockfile
+
+	#define getc_unlocked posix_getc_unlocked
+	#define getchar_unlocked posix_getchar_unlocked
+	#define putc_unlocked posix_putc_unlocked
+	#define putchar_unlocked posix_putchar_unlocked
 
 	#define remove posix_remove
Index: uspace/lib/posix/stdio/scanf.c
===================================================================
--- uspace/lib/posix/stdio/scanf.c	(revision 8cd8bf61fa7549be36c3193a2eff646b2c0f84ec)
+++ uspace/lib/posix/stdio/scanf.c	(revision 8cd8bf61fa7549be36c3193a2eff646b2c0f84ec)
@@ -0,0 +1,1337 @@
+/*
+ * Copyright (c) 2011 Petr Koupy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libposix
+ * @{
+ */
+/** @file Implementation of the scanf backend.
+ */
+
+#define LIBPOSIX_INTERNAL
+
+/* Must be first. */
+#include "../stdbool.h"
+
+#include "../assert.h"
+#include "../errno.h"
+
+#include "../stdio.h"
+#include "../stdlib.h"
+#include "../stddef.h"
+#include "../string.h"
+#include "../ctype.h"
+#include "../sys/types.h"
+
+#include "../internal/common.h"
+#include "../libc/malloc.h"
+
+/** Unified data type for possible data sources for scanf. */
+typedef union __data_source {
+	FILE *stream; /**< Input file stream. */
+	const char *string; /**< Input string. */
+} _data_source;
+
+/** Internal state of the input provider. */
+enum {
+	/** Partly constructed but not yet functional. */
+	_PROV_CONSTRUCTED,
+	/** Ready to serve any request. */
+	_PROV_READY,
+	/** Cursor is temporarily lent to the external entity. No action is
+	  * possible until the cursor is returned.  */
+	_PROV_CURSOR_LENT,
+};
+
+/** Universal abstraction over data input for scanf. */
+typedef struct __input_provider {
+	/** Source of data elements. */
+	_data_source source;
+	/** How many elements was already processed. */
+	int consumed;
+	/** How many elements was already fetched from the source. */
+	int fetched;
+	/** Elements are fetched from the source in batches (e.g. by getline())
+	  * to allow using strtol/strtod family even on streams. */
+	char *window;
+	/** Size of the current window. */
+	size_t window_size;
+	/** Points to the next element to be processed inside the current window. */
+	const char *cursor;
+	/** Internal state of the provider. */
+	int state;
+
+	/** Take control over data source. Finish initialization of the internal
+	  * structures (e.g. allocation of window). */
+	void (*capture)(struct __input_provider *);
+	/** Get a single element from the source and update the internal structures
+	  * accordingly (e.g. greedy update of the window). Return -1 if the
+	  * element cannot be obtained. */
+	int (*pop)(struct __input_provider *);
+	/** Undo the most recent not-undone pop operation. Might be necesarry to
+	  * flush current window and seek data source backwards. Return 0 if the
+	  * pop history is exhausted, non-zero on success. */
+	int (*undo)(struct __input_provider *);
+	/** Lend the cursor to the caller.  */
+	const char * (*borrow_cursor)(struct __input_provider *);
+	/** Take control over possibly incremented cursor and update the internal
+	  * structures if necessary. */
+	void (*return_cursor)(struct __input_provider *, const char *);
+	/** Release the control over the source. That is, synchronize any
+	  * fetched but non-consumed elements (e.g. by seeking) and destruct
+	  * internal structures (e.g. window deallocation). */
+	void (*release)(struct __input_provider *);
+} _input_provider;
+
+/** @see __input_provider */
+static void _capture_stream(_input_provider *self)
+{
+	assert(self->source.stream);
+	assert(self->state == _PROV_CONSTRUCTED);
+	/* Caller could already pre-allocated the window. */
+	assert((self->window == NULL && self->window_size == 0) ||
+		(self->window && self->window_size > 0));
+
+	/* Initialize internal structures. */
+	self->consumed = 0;
+	ssize_t fetched = posix_getline(
+		&self->window, &self->window_size, self->source.stream);
+	if (fetched != -1) {
+		self->fetched = fetched;
+		self->cursor = self->window;
+	} else {
+		/* EOF encountered. */
+		self->fetched = 0;
+		self->cursor = NULL;
+	}
+	self->state = _PROV_READY;
+}
+
+/** @see __input_provider */
+static void _capture_string(_input_provider *self)
+{
+	assert(self->source.string);
+	assert(self->state == _PROV_CONSTRUCTED);
+
+	/* Initialize internal structures. */
+	self->consumed = 0;
+	self->fetched = posix_strlen(self->source.string);
+	self->window = (char *) self->source.string;
+	self->window_size = self->fetched + 1;
+	self->cursor = self->window;
+	self->state = _PROV_READY;
+}
+
+/** @see __input_provider */
+static int _pop_stream(_input_provider *self)
+{
+	assert(self->state == _PROV_READY);
+
+	if (self->cursor) {
+		int c = *self->cursor;
+		++self->consumed;
+		++self->cursor;
+		/* Do we need to fetch a new line from the source? */
+		if (*self->cursor == '\0') {
+			ssize_t fetched = posix_getline(&self->window,
+				&self->window_size, self->source.stream);
+			if (fetched != -1) {
+				self->fetched += fetched;
+				self->cursor = self->window;
+			} else {
+				/* EOF encountered. */
+				self->cursor = NULL;
+			}
+		}
+		return c;
+	} else {
+		/* Already at EOF. */
+		return -1;
+	}
+}
+
+/** @see __input_provider */
+static int _pop_string(_input_provider *self)
+{
+	assert(self->state == _PROV_READY);
+
+	if (*self->cursor != '\0') {
+		int c = *self->cursor;
+		++self->consumed;
+		++self->cursor;
+		return c;
+	} else {
+		/* String depleted. */
+		return -1;
+	}
+}
+
+/** @see __input_provider */
+static int _undo_stream(_input_provider *self)
+{
+	assert(self->state == _PROV_READY);
+
+	if (self->consumed == 0) {
+		/* Undo history exhausted. */
+		return 0;
+	}
+
+	if (!self->cursor || self->window == self->cursor) {
+		/* Complex case. Either at EOF (cursor == NULL) or there is no more
+		 * place to retreat to inside the window. Seek the source backwards
+		 * and flush the window. Regarding the scanf, this could happend only
+		 * when matching unbounded string (%s) or unbounded scanset (%[) not
+		 * containing newline, while at the same time newline is the character
+		 * that breaks the matching process. */
+		int rc = posix_fseek(
+		    self->source.stream, -1, SEEK_CUR);
+		if (rc == -1) {
+			/* Seek failed.  */
+			return 0;
+		}
+		ssize_t fetched = posix_getline(&self->window,
+			&self->window_size, self->source.stream);
+		if (fetched != -1) {
+			assert(fetched == 1);
+			self->fetched = self->consumed + 1;
+			self->cursor = self->window;
+		} else {
+			/* Stream is broken. */
+			return 0;
+		}
+	} else {
+		/* Simple case. Still inside window. */
+		--self->cursor;
+	}
+	--self->consumed;
+	return 1; /* Success. */
+}
+
+/** @see __input_provider */
+static int _undo_string(_input_provider *self)
+{
+	assert(self->state == _PROV_READY);
+
+	if (self->consumed > 0) {
+		--self->consumed;
+		--self->cursor;
+	} else {
+		/* Undo history exhausted. */
+		return 0;
+	}
+	return 1; /* Success. */
+}
+
+/** @see __input_provider */
+static const char *_borrow_cursor_universal(_input_provider *self)
+{
+	assert(self->state == _PROV_READY);
+
+	self->state = _PROV_CURSOR_LENT;
+	return self->cursor;
+}
+
+/** @see __input_provider */
+static void _return_cursor_stream(_input_provider *self, const char *cursor)
+{
+	assert(self->state == _PROV_CURSOR_LENT);
+
+	/* Check how much of the window did external entity consumed. */
+	self->consumed += cursor - self->cursor;
+	self->cursor = cursor;
+	if (*self->cursor == '\0') {
+		/* Window was completely consumed, fetch new data. */
+		ssize_t fetched = posix_getline(&self->window,
+			&self->window_size, self->source.stream);
+		if (fetched != -1) {
+			self->fetched += fetched;
+			self->cursor = self->window;
+		} else {
+			/* EOF encountered. */
+			self->cursor = NULL;
+		}
+	}
+	self->state = _PROV_READY;
+}
+
+/** @see __input_provider */
+static void _return_cursor_string(_input_provider *self, const char *cursor)
+{
+	assert(self->state == _PROV_CURSOR_LENT);
+
+	/* Check how much of the window did external entity consumed. */
+	self->consumed += cursor - self->cursor;
+	self->cursor = cursor;
+	self->state = _PROV_READY;
+}
+
+/** @see __input_provider */
+static void _release_stream(_input_provider *self)
+{
+	assert(self->state == _PROV_READY);
+	assert(self->consumed >= self->fetched);
+
+	/* Try to correct the difference between the stream position and what was
+	 * actually consumed. If it is not possible, continue anyway. */
+	posix_fseek(self->source.stream, self->consumed - self->fetched, SEEK_CUR);
+
+	/* Destruct internal structures. */
+	self->fetched = 0;
+	self->cursor = NULL;
+	free(self->window);
+	self->window = NULL;
+	self->window_size = 0;
+	self->state = _PROV_CONSTRUCTED;
+}
+
+/** @see __input_provider */
+static void _release_string(_input_provider *self)
+{
+	assert(self->state == _PROV_READY);
+
+	/* Destruct internal structures. */
+	self->fetched = 0;
+	self->cursor = NULL;
+	self->window = NULL;
+	self->window_size = 0;
+	self->state = _PROV_CONSTRUCTED;
+}
+
+/** Length modifier values. */
+enum {
+	LMOD_NONE,
+	LMOD_hh,
+	LMOD_h,
+	LMOD_l,
+	LMOD_ll,
+	LMOD_j,
+	LMOD_z,
+	LMOD_t,
+	LMOD_L,
+	LMOD_p, /* Reserved for %p conversion. */
+};
+
+/**
+ * Decides whether provided characters specify length modifier. If so, the
+ * recognized modifier is stored through provider pointer.
+ *
+ * @param c Candidate on the length modifier.
+ * @param _c Next character (might be NUL).
+ * @param modifier Pointer to the modifier value.
+ * @return Whether the modifier was recognized or not.
+ */
+static inline int is_length_mod(int c, int _c, int *modifier)
+{
+	assert(modifier);
+
+	switch (c) {
+	case 'h':
+		/* Check whether the modifier was not already recognized. */
+		if (*modifier == LMOD_NONE) {
+			*modifier = _c == 'h' ? LMOD_hh : LMOD_h;
+		} else {
+			/* Format string is invalid. Notify the caller. */
+			*modifier = LMOD_NONE;
+		}
+		return 1;
+	case 'l':
+		if (*modifier == LMOD_NONE) {
+			*modifier = _c == 'l' ? LMOD_ll : LMOD_l;
+		} else {
+			*modifier = LMOD_NONE;
+		}
+		return 1;
+	case 'j':
+		*modifier = *modifier == LMOD_NONE ? LMOD_j : LMOD_NONE;
+		return 1;
+	case 'z':
+		*modifier = *modifier == LMOD_NONE ? LMOD_z : LMOD_NONE;
+		return 1;
+	case 't':
+		*modifier = *modifier == LMOD_NONE ? LMOD_t : LMOD_NONE;
+		return 1;
+	case 'L':
+		*modifier = *modifier == LMOD_NONE ? LMOD_L : LMOD_NONE;
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+/**
+ * Decides whether provided character specifies integer conversion. If so, the
+ * semantics of the conversion is stored through provided pointers..
+ * 
+ * @param c Candidate on the integer conversion.
+ * @param is_unsigned Pointer to store whether the conversion is signed or not.
+ * @param base Pointer to store the base of the integer conversion.
+ * @return Whether the conversion was recognized or not.
+ */
+static inline int is_int_conv(int c, bool *is_unsigned, int *base)
+{
+	assert(is_unsigned && base);
+
+	switch (c) {
+	case 'd':
+		*is_unsigned = false;
+		*base = 10;
+		return 1;
+	case 'i':
+		*is_unsigned = false;
+		*base = 0;
+		return 1;
+	case 'o':
+		*is_unsigned = true;
+		*base = 8;
+		return 1;
+	case 'u':
+		*is_unsigned = true;
+		*base = 10;
+		return 1;
+	case 'p': /* According to POSIX, %p modifier is implementation defined but
+			   * must correspond to its printf counterpart. */
+	case 'x':
+	case 'X':
+		*is_unsigned = true;
+		*base = 16;
+		return 1;
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+/**
+ * Decides whether provided character specifies conversion of the floating
+ * point number.
+ *
+ * @param c Candidate on the floating point conversion.
+ * @return Whether the conversion was recognized or not.
+ */
+static inline int is_float_conv(int c)
+{
+	switch (c) {
+	case 'a':
+	case 'A':
+	case 'e':
+	case 'E':
+	case 'f':
+	case 'F':
+	case 'g':
+	case 'G':
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+/**
+ * Decides whether provided character specifies conversion of the character
+ * sequence.
+ *
+ * @param c Candidate on the character sequence conversion.
+ * @param modifier Pointer to store length modifier for wide chars.
+ * @return Whether the conversion was recognized or not.
+ */
+static inline int is_seq_conv(int c, int *modifier)
+{
+	assert(modifier);
+	
+	switch (c) {
+	case 'S':
+		*modifier = LMOD_l;
+		/* fallthrough */
+	case 's':
+		return 1;
+	case 'C':
+		*modifier = LMOD_l;
+		/* fallthrough */
+	case 'c':
+		return 1;
+	case '[':
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+/**
+ * Backend for the whole family of scanf functions. Uses input provider
+ * to abstract over differences between strings and streams. Should be
+ * POSIX compliant (apart from the not supported stuff).
+ *
+ * NOT SUPPORTED: locale (see strtold), wide chars, numbered output arguments
+ * 
+ * @param in Input provider.
+ * @param fmt Format description.
+ * @param arg Output arguments.
+ * @return The number of converted output items or EOF on failure.
+ */
+static inline int _internal_scanf(
+    _input_provider *in, const char *restrict fmt, va_list arg)
+{
+	int c = -1;
+	int converted_cnt = 0;
+	bool converting = false;
+	bool matching_failure = false;
+
+	bool assign_supress = false;
+	bool assign_alloc = false;
+	long width = -1;
+	int length_mod = LMOD_NONE;
+	bool int_conv_unsigned = false;
+	int int_conv_base = 0;
+
+	/* Buffers allocated by scanf for optional 'm' specifier must be remembered
+	 * to deallocaate them in case of an error. Because each of those buffers
+	 * corresponds to one of the argument from va_list, there is an upper bound
+	 * on the number of those arguments. In case of C99, this uppper bound is
+	 * 127 arguments. */
+	char *buffers[127];
+	for (int i = 0; i < 127; ++i) {
+		buffers[i] = NULL;
+	}
+	int next_unused_buffer_idx = 0;
+
+	in->capture(in);
+
+	/* Interpret format string. Control shall prematurely jump from the cycle
+	 * on input failure, matching failure or illegal format string. In order
+	 * to keep error reporting simple enough and to keep input consistent,
+	 * error condition shall be always manifested as jump from the cycle,
+	 * not function return. Format string pointer shall be updated specifically
+	 * for each sub-case (i.e. there shall be no loop-wide increment).*/
+	while (*fmt) {
+
+		if (converting) {
+
+			/* Processing inside conversion specifier. Either collect optional
+			 * parameters or execute the conversion. When the conversion
+			 * is successfully completed, increment conversion count and switch
+			 * back to normal mode. */
+			if (*fmt == '*') {
+				/* Assignment-supression (optional). */
+				if (assign_supress) {
+					/* Already set. Illegal format string. */
+					break;
+				}
+				assign_supress = true;
+				++fmt;
+			} else if (*fmt == 'm') {
+				/* Assignment-allocation (optional). */
+				if (assign_alloc) {
+					/* Already set. Illegal format string. */
+					break;
+				}
+				assign_alloc = true;
+				++fmt;
+			} else if (*fmt == '$') {
+				/* Reference to numbered output argument. */
+				// TODO
+				not_implemented();
+			} else if (isdigit(*fmt)) {
+				/* Maximum field length (optional). */
+				if (width != -1) {
+					/* Already set. Illegal format string. */
+					break;
+				}
+				char *fmt_new = NULL;
+				width = posix_strtol(fmt, &fmt_new, 10);
+				if (width != 0) {
+					fmt = fmt_new;
+				} else {
+					/* Since POSIX requires width to be non-zero, it is
+					 * sufficient to interpret zero width as error without
+					 * referring to errno. */
+					break;
+				}
+			} else if (is_length_mod(*fmt, *(fmt + 1), &length_mod)) {
+				/* Length modifier (optional). */
+				if (length_mod == LMOD_NONE) {
+					/* Already set. Illegal format string. The actual detection
+					 * is carried out in the is_length_mod(). */
+					break;
+				}
+				if (length_mod == LMOD_hh || length_mod == LMOD_ll) {
+					/* Modifier was two characters long. */
+					++fmt;
+				}
+				++fmt;
+			} else if (is_int_conv(*fmt, &int_conv_unsigned, &int_conv_base)) {
+				/* Integer conversion. */
+
+				/* Check sanity of optional parts of conversion specifier. */
+				if (assign_alloc || length_mod == LMOD_L) {
+					/* Illegal format string. */
+					break;
+				}
+
+				/* Conversion of the integer with %p specifier needs special
+				 * handling, because it is not allowed to have arbitrary
+				 * length modifier.  */
+				if (*fmt == 'p') {
+					if (length_mod == LMOD_NONE) {
+						length_mod = LMOD_p;
+					} else {
+						/* Already set. Illegal format string. */
+						break;
+					}
+				}
+
+				/* First consume any white spaces, so we can borrow cursor
+				 * from the input provider. This way, the cursor will either
+				 * point to the non-white space while the input will be
+				 * prefetched up to the newline (which is suitable for strtol),
+				 * or the input will be at EOF. */
+				do {
+					c = in->pop(in);
+				} while (isspace(c));
+
+				/* After skipping the white spaces, can we actually continue? */
+				if (c == -1) {
+					/* Input failure. */
+					break;
+				} else {
+					/* Everything is OK, just undo the last pop, so the cursor
+					 * can be borrowed. */
+					in->undo(in);
+				}
+
+				const char *cur_borrowed = NULL;
+				const char *cur_limited = NULL;
+				char *cur_updated = NULL;
+
+				/* Borrow the cursor. Until it is returned to the provider
+				 * we cannot jump from the cycle, because it would leave
+				 * the input inconsistent. */
+				cur_borrowed = in->borrow_cursor(in);
+
+				/* If the width is limited, the cursor horizont must be
+				 * decreased accordingly. Otherwise the strtol could read more
+				 * than allowed by width. */
+				if (width != -1) {
+					cur_limited = posix_strndup(cur_borrowed, width);
+				} else {
+					cur_limited = cur_borrowed;
+				}
+				cur_updated = (char *) cur_limited;
+
+				long long sres = 0;
+				unsigned long long ures = 0;
+				errno = 0; /* Reset errno to recognize error later. */
+				/* Try to convert the integer. */
+				if (int_conv_unsigned) {
+					ures = posix_strtoull(cur_limited, &cur_updated, int_conv_base);
+				} else {
+					sres = posix_strtoll(cur_limited, &cur_updated, int_conv_base);
+				}
+
+				/* Update the cursor so it can be returned to the provider. */
+				cur_borrowed += cur_updated - cur_limited;
+				if (width != -1) {
+					/* Deallocate duplicated part of the cursor view. */
+					free(cur_limited);
+				}
+				cur_limited = NULL;
+				cur_updated = NULL;
+				/* Return the cursor to the provider. Input consistency is again
+				 * the job of the provider, so we can report errors from
+				 * now on. */
+				in->return_cursor(in, cur_borrowed);
+				cur_borrowed = NULL;
+
+				/* Check whether the conversion was successful. */
+				if (errno != EOK) {
+					matching_failure = true;
+					break;
+				}
+
+				/* If not supressed, assign the converted integer into
+				 * the next output argument. */
+				if (!assign_supress) {
+					if (int_conv_unsigned) {
+						switch (length_mod) {
+						case LMOD_hh: ; /* Label cannot be part of declaration. */
+							unsigned char *phh = va_arg(arg, unsigned char *);
+							*phh = (unsigned char) ures;
+							break;
+						case LMOD_h: ;
+							unsigned short *ph = va_arg(arg, unsigned short *);
+							*ph = (unsigned short) ures;
+							break;
+						case LMOD_NONE: ;
+							unsigned *pdef = va_arg(arg, unsigned *);
+							*pdef = (unsigned) ures;
+							break;
+						case LMOD_l: ;
+							unsigned long *pl = va_arg(arg, unsigned long *);
+							*pl = (unsigned long) ures;
+							break;
+						case LMOD_ll: ;
+							unsigned long long *pll = va_arg(arg, unsigned long long *);
+							*pll = (unsigned long long) ures;
+							break;
+						case LMOD_j: ;
+							posix_uintmax_t *pj = va_arg(arg, posix_uintmax_t *);
+							*pj = (posix_uintmax_t) ures;
+							break;
+						case LMOD_z: ;
+							size_t *pz = va_arg(arg, size_t *);
+							*pz = (size_t) ures;
+							break;
+						case LMOD_t: ;
+							// FIXME: What is unsigned counterpart of the ptrdiff_t?
+							size_t *pt = va_arg(arg, size_t *);
+							*pt = (size_t) ures;
+							break;
+						case LMOD_p: ;
+							void **pp = va_arg(arg, void **);
+							*pp = (void *) (uintptr_t) ures;
+							break;
+						default:
+							assert(false);
+						}
+					} else {
+						switch (length_mod) {
+						case LMOD_hh: ; /* Label cannot be part of declaration. */
+							signed char *phh = va_arg(arg, signed char *);
+							*phh = (signed char) sres;
+							break;
+						case LMOD_h: ;
+							short *ph = va_arg(arg, short *);
+							*ph = (short) sres;
+							break;
+						case LMOD_NONE: ;
+							int *pdef = va_arg(arg, int *);
+							*pdef = (int) sres;
+							break;
+						case LMOD_l: ;
+							long *pl = va_arg(arg, long *);
+							*pl = (long) sres;
+							break;
+						case LMOD_ll: ;
+							long long *pll = va_arg(arg, long long *);
+							*pll = (long long) sres;
+							break;
+						case LMOD_j: ;
+							posix_intmax_t *pj = va_arg(arg, posix_intmax_t *);
+							*pj = (posix_intmax_t) sres;
+							break;
+						case LMOD_z: ;
+							ssize_t *pz = va_arg(arg, ssize_t *);
+							*pz = (ssize_t) sres;
+							break;
+						case LMOD_t: ;
+							posix_ptrdiff_t *pt = va_arg(arg, posix_ptrdiff_t *);
+							*pt = (posix_ptrdiff_t) sres;
+							break;
+						default:
+							assert(false);
+						}
+					}
+					++converted_cnt;
+				}
+
+				converting = false;
+				++fmt;
+			} else if (is_float_conv(*fmt)) {
+				/* Floating point number conversion. */
+
+				/* Check sanity of optional parts of conversion specifier. */
+				if (assign_alloc) {
+					/* Illegal format string. */
+					break;
+				}
+				if (length_mod != LMOD_NONE &&
+				    length_mod != LMOD_l &&
+				    length_mod != LMOD_L) {
+					/* Illegal format string. */
+					break;
+				}
+
+				/* First consume any white spaces, so we can borrow cursor
+				 * from the input provider. This way, the cursor will either
+				 * point to the non-white space while the input will be
+				 * prefetched up to the newline (which is suitable for strtof),
+				 * or the input will be at EOF. */
+				do {
+					c = in->pop(in);
+				} while (isspace(c));
+
+				/* After skipping the white spaces, can we actually continue? */
+				if (c == -1) {
+					/* Input failure. */
+					break;
+				} else {
+					/* Everything is OK, just undo the last pop, so the cursor
+					 * can be borrowed. */
+					in->undo(in);
+				}
+
+				const char *cur_borrowed = NULL;
+				const char *cur_limited = NULL;
+				char *cur_updated = NULL;
+
+				/* Borrow the cursor. Until it is returned to the provider
+				 * we cannot jump from the cycle, because it would leave
+				 * the input inconsistent. */
+				cur_borrowed = in->borrow_cursor(in);
+
+				/* If the width is limited, the cursor horizont must be
+				 * decreased accordingly. Otherwise the strtof could read more
+				 * than allowed by width. */
+				if (width != -1) {
+					cur_limited = posix_strndup(cur_borrowed, width);
+				} else {
+					cur_limited = cur_borrowed;
+				}
+				cur_updated = (char *) cur_limited;
+
+				float fres = 0.0;
+				double dres = 0.0;
+				long double ldres = 0.0;
+				errno = 0; /* Reset errno to recognize error later. */
+				/* Try to convert the floating point nubmer. */
+				switch (length_mod) {
+				case LMOD_NONE:
+					fres = posix_strtof(cur_limited, &cur_updated);
+					break;
+				case LMOD_l:
+					dres = posix_strtod(cur_limited, &cur_updated);
+					break;
+				case LMOD_L:
+					ldres = posix_strtold(cur_limited, &cur_updated);
+					break;
+				default:
+					assert(false);
+				}
+
+				/* Update the cursor so it can be returned to the provider. */
+				cur_borrowed += cur_updated - cur_limited;
+				if (width != -1) {
+					/* Deallocate duplicated part of the cursor view. */
+					free(cur_limited);
+				}
+				cur_limited = NULL;
+				cur_updated = NULL;
+				/* Return the cursor to the provider. Input consistency is again
+				 * the job of the provider, so we can report errors from
+				 * now on. */
+				in->return_cursor(in, cur_borrowed);
+				cur_borrowed = NULL;
+
+				/* Check whether the conversion was successful. */
+				if (errno != EOK) {
+					matching_failure = true;
+					break;
+				}
+
+				/* If nto supressed, assign the converted floating point number
+				 * into the next output argument. */
+				if (!assign_supress) {
+					switch (length_mod) {
+					case LMOD_NONE: ; /* Label cannot be part of declaration. */
+						float *pf = va_arg(arg, float *);
+						*pf = fres;
+						break;
+					case LMOD_l: ;
+						double *pd = va_arg(arg, double *);
+						*pd = dres;
+						break;
+					case LMOD_L: ;
+						long double *pld = va_arg(arg, long double *);
+						*pld = ldres;
+						break;
+					default:
+						assert(false);
+					}
+					++converted_cnt;
+				}
+
+				converting = false;
+				++fmt;
+			} else if (is_seq_conv(*fmt, &length_mod)) {
+				/* Character sequence conversion. */
+				
+				/* Check sanity of optional parts of conversion specifier. */
+				if (length_mod != LMOD_NONE &&
+				    length_mod != LMOD_l) {
+					/* Illegal format string. */
+					break;
+				}
+
+				if (length_mod == LMOD_l) {
+					/* Wide chars not supported. */
+					// TODO
+					not_implemented();
+				}
+
+				int term_size = 1; /* Size of the terminator (0 or 1)). */
+				if (*fmt == 'c') {
+					term_size = 0;
+					width = width == -1 ? 1 : width;
+				}
+
+				if (*fmt == 's') {
+					/* Skip white spaces. */
+					do {
+						c = in->pop(in);
+					} while (isspace(c));
+				} else {
+					/* Fetch a single character. */
+					c = in->pop(in);
+				}
+
+				/* Check whether there is still input to read. */
+				if (c == -1) {
+					/* Input failure. */
+					break;
+				}
+
+				/* Prepare scanset. */
+				char terminate_on[256];
+				for (int i = 0; i < 256; ++i) {
+					terminate_on[i] = 0;
+				}
+				if (*fmt == 'c') {
+					++fmt;
+				} else if (*fmt == 's') {
+					terminate_on[' '] = 1;
+					terminate_on['\n'] = 1;
+					terminate_on['\t'] = 1;
+					terminate_on['\f'] = 1;
+					terminate_on['\r'] = 1;
+					terminate_on['\v'] = 1;
+					++fmt;
+				} else {
+					assert(*fmt == '[');
+					bool not = false;
+					bool dash = false;
+					++fmt;
+					/* Check for negation. */
+					if (*fmt == '^') {
+						not = true;
+						++fmt;
+					}
+					/* Check for escape sequences. */
+					if (*fmt == '-' || *fmt == ']') {
+						terminate_on[(int) *fmt] = 1;
+						++fmt;
+					}
+					/* Check for ordinary characters and ranges. */
+					while (*fmt != '\0' && *fmt != ']') {
+						if (dash) {
+							for (char chr = *(fmt - 2); chr <= *fmt; ++chr) {
+								terminate_on[(int) chr] = 1;
+							}
+							dash = false;
+						} else if (*fmt == '-') {
+							dash = true;
+						} else {
+							terminate_on[(int) *fmt] = 1;
+						}
+						++fmt;
+					}
+					/* Check for escape sequence. */
+					if (dash == true) {
+						terminate_on['-'] = 1;
+					}
+					/* Check whether the specifier was correctly terminated.*/
+					if (*fmt == '\0') {
+						/* Illegal format string. */
+						break;
+					} else {
+						++fmt;
+					}
+					/* Inverse the scanset if necessary. */
+					if (not == false) {
+						for (int i = 0; i < 256; ++i) {
+							terminate_on[i] = terminate_on[i] ? 0 : 1;
+						}
+					}
+				}
+
+				char * buf = NULL;
+				size_t buf_size = 0;
+				char * cur = NULL;
+				size_t alloc_step = 80; /* Buffer size gain during reallocation. */
+				int my_buffer_idx = 0;
+
+				/* Retrieve the buffer into which popped characters
+				 * will be stored. */
+				if (!assign_supress) {
+					if (assign_alloc) {
+						/* We must allocate our own buffer. */
+						buf_size =
+						    width == -1 ? alloc_step : (size_t) width + term_size;
+						buf = malloc(buf_size);
+						if (!buf) {
+							/* No memory. */
+							break;
+						}
+						my_buffer_idx = next_unused_buffer_idx;
+						++next_unused_buffer_idx;
+						buffers[my_buffer_idx] = buf;
+						cur = buf;
+					} else {
+						/* Caller provided its buffer. */
+						buf = va_arg(arg, char *);
+						cur = buf;
+						buf_size =
+						    width == -1 ? SIZE_MAX : (size_t) width + term_size;
+					}
+				}
+
+				/* Match the string. The next character is already popped. */
+				while ((width == -1 || width > 0) && c != -1 && !terminate_on[c]) {
+
+					/* Check whether the buffer is still sufficiently large. */
+					if (!assign_supress) {
+						/* Always reserve space for the null terminator. */
+						if (cur == buf + buf_size - term_size) {
+							/* Buffer size must be increased. */
+							buf = realloc(buf, buf_size + alloc_step);
+							if (buf) {
+								buffers[my_buffer_idx] = buf;
+								cur = buf + buf_size - term_size;
+								buf_size += alloc_step;
+							} else {
+								/* Break just from this tight loop. Errno will
+								 * be checked after it. */
+								break;
+							}
+						}
+						/* Store the input character. */
+						*cur = c;
+					}
+
+					width = width == -1 ? -1 : width - 1;
+					++cur;
+					c = in->pop(in);
+				}
+				if (errno == ENOMEM) {
+					/* No memory. */
+					break;
+				}
+				if (c != -1) {
+					/* There is still more input, so undo the last pop. */
+					in->undo(in);
+				}
+
+				/* Check for failures. */
+				if (cur == buf) {
+					/* Matching failure. Input failure was already checked
+					 * earlier. */
+					matching_failure = true;
+					if (!assign_supress && assign_alloc) {
+						/* Roll back. */
+						free(buf);
+						buffers[my_buffer_idx] = NULL;
+						--next_unused_buffer_idx;
+					}
+					break;
+				}
+
+				/* Store the terminator. */
+				if (!assign_supress && term_size > 0) {
+					/* Space for the terminator was reserved. */
+					*cur = '\0';
+				}
+
+				/* Store the result if not already stored. */
+				if (!assign_supress) {
+					if (assign_alloc) {
+						char **pbuf = va_arg(arg, char **);
+						*pbuf = buf;
+					}
+					++converted_cnt;
+				}
+				
+				converting = false;
+				/* Format string pointer already incremented. */
+			} else if (*fmt == 'n') {
+				/* Report the number of consumed bytes so far. */
+
+				/* Sanity check. */
+				bool sane =
+				    width == -1 &&
+					length_mod == LMOD_NONE &&
+					assign_alloc == false &&
+					assign_supress == false;
+
+				if (sane) {
+					int *pi = va_arg(arg, int *);
+					*pi = in->consumed;
+				} else {
+					/* Illegal format string. */
+					break;
+				}
+
+				/* This shall not be counted as conversion. */
+				converting = false;
+				++fmt;
+			} else {
+				/* Illegal format string. */
+				break;
+			}
+			
+		} else {
+
+			/* Processing outside conversion specifier. Either skip white
+			 * spaces or match characters one by one. If conversion specifier
+			 * is detected, switch to coversion mode. */
+			if (isspace(*fmt)) {
+				/* Skip white spaces in the format string. */
+				while (isspace(*fmt)) {
+					++fmt;
+				}
+				/* Skip white spaces in the input. */
+				do {
+					c = in->pop(in);
+				} while (isspace(c));
+				if (c != -1) {
+					/* Input is not at EOF, so undo the last pop operation. */
+					in->undo(in);
+				}
+			} else if (*fmt == '%' && *(fmt + 1) != '%') {
+				/* Conversion specifier detected. Switch modes. */
+				converting = true;
+				/* Reset the conversion context. */
+				assign_supress = false;
+				assign_alloc = false;
+				width = -1;
+				length_mod = LMOD_NONE;
+				int_conv_unsigned = false;
+				int_conv_base = 0;
+				++fmt;
+			} else {
+				/* One by one matching. */
+				if (*fmt == '%') {
+					/* Escape sequence detected. */
+					++fmt;
+					assert(*fmt == '%');
+				}
+				c = in->pop(in);
+				if (c == -1) {
+					/* Input failure. */
+					break;
+				} else if (c != *fmt) {
+					/* Matching failure. */
+					in->undo(in);
+					matching_failure = true;
+					break;
+				} else {
+					++fmt;
+				}
+			}
+			
+		}
+
+	}
+
+	in->release(in);
+
+	/* This somewhat complicated return value decision is required by POSIX. */
+	int rc;
+	if (matching_failure) {
+		rc = converted_cnt;
+	} else {
+		if (errno == EOK) {
+			rc = converted_cnt > 0 ? converted_cnt : EOF;
+		} else {
+			rc = EOF;
+		}
+	}
+	if (rc == EOF) {
+		/* Caller will not know how many arguments were successfully converted,
+		 * so the deallocation of buffers is our responsibility. */
+		for (int i = 0; i < next_unused_buffer_idx; ++i) {
+			free(buffers[i]);
+			buffers[i] = NULL;
+		}
+		next_unused_buffer_idx = 0;
+	}
+	return rc;
+}
+
+/**
+ * Convert formatted input from the stream.
+ *
+ * @param stream Input stream.
+ * @param format Format description.
+ * @param arg Output items.
+ * @return The number of converted output items or EOF on failure.
+ */
+int posix_vfscanf(
+    FILE *restrict stream, const char *restrict format, va_list arg)
+{
+	_input_provider provider = {
+	    { 0 }, 0, 0, NULL, 0, NULL, _PROV_CONSTRUCTED,
+	    _capture_stream, _pop_stream, _undo_stream,
+	    _borrow_cursor_universal, _return_cursor_stream, _release_stream
+	};
+	provider.source.stream = stream;
+	return _internal_scanf(&provider, format, arg);
+}
+
+/**
+ * Convert formatted input from the string.
+ *
+ * @param s Input string.
+ * @param format Format description.
+ * @param arg Output items.
+ * @return The number of converted output items or EOF on failure.
+ */
+int posix_vsscanf(
+    const char *restrict s, const char *restrict format, va_list arg)
+{
+	_input_provider provider = {
+	    { 0 }, 0, 0, NULL, 0, NULL, _PROV_CONSTRUCTED,
+	    _capture_string, _pop_string, _undo_string,
+	    _borrow_cursor_universal, _return_cursor_string, _release_string
+	};
+	provider.source.string = s;
+	return _internal_scanf(&provider, format, arg);
+}
+
+// FIXME: put the testcases somewhere else
+
+#if 0
+
+//#include <stdio.h>
+//#include <malloc.h>
+//#include <string.h>
+
+#define test_val(fmt, exp_val, act_val) \
+	if (exp_val == act_val) { \
+		printf("succ, expected "fmt", actual "fmt"\n", exp_val, act_val); \
+	} else { \
+		printf("fail, expected "fmt", actual "fmt"\n", exp_val, act_val); \
+		++fail; \
+	}
+
+#define test_str(fmt, exp_str, act_str) \
+	if (posix_strcmp(exp_str, act_str) == 0) { \
+		printf("succ, expected "fmt", actual "fmt"\n", exp_str, act_str); \
+	} else { \
+		printf("fail, expected "fmt", actual "fmt"\n", exp_str, act_str); \
+		++fail; \
+	}
+
+void __posix_scanf_test(void);
+void __posix_scanf_test(void)
+{
+	int fail = 0;
+
+	int ret;
+
+	unsigned char uhh;
+	signed char shh;
+	unsigned short uh;
+	short sh;
+	unsigned udef;
+	int sdef;
+	unsigned long ul;
+	long sl;
+	unsigned long long ull;
+	long long sll;
+	void *p;
+	
+	float f;
+	double d;
+	long double ld;
+
+	char str[20];
+	char seq[20];
+	char scanset[20];
+
+	char *pstr;
+	char *pseq;
+	char *pscanset;
+	
+	ret = posix_sscanf(
+	    "\n j tt % \t -121314 98765 aqw 0765 0x77 0xABCDEF88 -99 884",
+	    " j tt %%%3hhd%1hhu%3hd %3hu%u aqw%n %lo%llx %p %li %lld",
+	    &shh, &uhh, &sh, &uh, &udef, &sdef, &ul, &ull, &p, &sl, &sll);
+	test_val("%d", -12, shh);
+	test_val("%u", 1, uhh);
+	test_val("%d", 314, sh);
+	test_val("%u", 987, uh);
+	test_val("%u", 65, udef);
+	test_val("%d", 28, sdef);
+	test_val("%lo", (unsigned long) 0765, ul);
+	test_val("%llx", (unsigned long long) 0x77, ull);
+	test_val("%p", (void *) 0xABCDEF88, p);
+	test_val("%ld", (long) -99, sl);
+	test_val("%lld", (long long) 884, sll);
+	test_val("%d", 10, ret);
+
+	ret = posix_sscanf(
+	    "\n \t\t1.0 -0x555.AP10 1234.5678e12",
+	    "%f %lf %Lf",
+	    &f, &d, &ld);
+	test_val("%f", 1.0, f);
+	test_val("%lf", (double) -0x555.AP10, d);
+	test_val("%Lf", (long double) 1234.5678e12, ld);
+	test_val("%d", 3, ret);
+	 
+	ret = posix_sscanf(
+	    "\n\n\thello world    \n",
+	    "%5s %ms",
+	    str, &pstr);
+	test_str("%s", "hello", str);
+	test_str("%s", "world", pstr);
+	test_val("%d", 2, ret);
+	free(pstr);
+
+	ret = posix_sscanf(
+	    "\n\n\thello world    \n",
+	    " %5c %mc",
+	    seq, &pseq);
+	seq[5] = '\0';
+	pseq[1] = '\0';
+	test_str("%s", "hello", seq);
+	test_str("%s", "w", pseq);
+	test_val("%d", 2, ret);
+	free(pseq);
+
+	ret = posix_sscanf(
+	    "\n\n\th-e-l-l-o world-]    \n",
+	    " %9[-eh-o] %m[^]-]",
+	    scanset, &pscanset);
+	test_str("%s", "h-e-l-l-o", scanset);
+	test_str("%s", "world", pscanset);
+	test_val("%d", 2, ret);
+	free(pscanset);
+
+	printf("Failed: %d\n", fail);
+}
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/posix/stdlib.c
===================================================================
--- uspace/lib/posix/stdlib.c	(revision f5b25224f3b95c0a700f5f9f6c8bb2ecad2c28f0)
+++ uspace/lib/posix/stdlib.c	(revision 8cd8bf61fa7549be36c3193a2eff646b2c0f84ec)
@@ -36,10 +36,12 @@
 #define LIBPOSIX_INTERNAL
 
+#include "internal/common.h"
 #include "stdlib.h"
+
+#include "errno.h"
+
 #include "libc/sort.h"
 #include "libc/str.h"
 #include "libc/vfs/vfs.h"
-#include "internal/common.h"
-#include <errno.h>  // FIXME: use POSIX errno
 
 /**
@@ -338,4 +340,16 @@
 }
 
+/**
+ * Should read system load statistics. Not supported. Always returns -1.
+ *
+ * @param loadavg
+ * @param nelem
+ * @return
+ */
+int bsd_getloadavg(double loadavg[], int nelem)
+{
+	return -1;
+}
+
 /** @}
  */
Index: uspace/lib/posix/stdlib.h
===================================================================
--- uspace/lib/posix/stdlib.h	(revision f5b25224f3b95c0a700f5f9f6c8bb2ecad2c28f0)
+++ uspace/lib/posix/stdlib.h	(revision 8cd8bf61fa7549be36c3193a2eff646b2c0f84ec)
@@ -120,4 +120,5 @@
 /* Legacy Declarations */
 extern char *posix_mktemp(char *tmpl);
+extern int bsd_getloadavg(double loadavg[], int nelem);
 
 #ifndef LIBPOSIX_INTERNAL
@@ -163,4 +164,5 @@
 
 	#define mktemp posix_mktemp
+	#define getloadavg bsd_getloadavg
 #endif
 
Index: uspace/lib/posix/stdlib/strtol.c
===================================================================
--- uspace/lib/posix/stdlib/strtol.c	(revision f5b25224f3b95c0a700f5f9f6c8bb2ecad2c28f0)
+++ uspace/lib/posix/stdlib/strtol.c	(revision 8cd8bf61fa7549be36c3193a2eff646b2c0f84ec)
@@ -37,7 +37,8 @@
 #include "../internal/common.h"
 #include "../stdlib.h"
-#include <errno.h>  // FIXME: use POSIX errno
+
 #include "../limits.h"
 #include "../ctype.h"
+#include "../errno.h"
 
 // TODO: documentation
Index: uspace/lib/posix/stdlib/strtold.c
===================================================================
--- uspace/lib/posix/stdlib/strtold.c	(revision f5b25224f3b95c0a700f5f9f6c8bb2ecad2c28f0)
+++ uspace/lib/posix/stdlib/strtold.c	(revision 8cd8bf61fa7549be36c3193a2eff646b2c0f84ec)
@@ -35,13 +35,15 @@
 #define LIBPOSIX_INTERNAL
 
+/* Must be first. */
+#include "../stdbool.h"
+
 #include "../internal/common.h"
-
-#include "../libc/assert.h"
+#include "../stdlib.h"
+
+#include "../assert.h"
 #include "../ctype.h"
-#include <errno.h> // TODO: use POSIX errno
-#include "../libc/bool.h"
 #include "../stdint.h"
-#include "../stdlib.h"
 #include "../strings.h"
+#include "../errno.h"
 
 #ifndef HUGE_VALL
Index: uspace/lib/posix/string.c
===================================================================
--- uspace/lib/posix/string.c	(revision f5b25224f3b95c0a700f5f9f6c8bb2ecad2c28f0)
+++ uspace/lib/posix/string.c	(revision 8cd8bf61fa7549be36c3193a2eff646b2c0f84ec)
@@ -36,25 +36,14 @@
 #define LIBPOSIX_INTERNAL
 
+#include "internal/common.h"
 #include "string.h"
 
-#include <assert.h>
-#include <str_error.h>
-#include <stdlib.h>
-#include <errno.h>
-
-/**
- * Defined for convenience. Returns pointer to the terminating nul character.
- *
- * @param s
- * @return
- */
-static char *strzero(const char *s)
-{
-	while (*s != '\0') {
-		s++;
-	}
-
-	return (char *) s;
-}
+#include "assert.h"
+#include "errno.h"
+#include "limits.h"
+#include "stdlib.h"
+#include "signal.h"
+
+#include "libc/str_error.h"
 
 /**
@@ -183,5 +172,5 @@
 	assert(src != NULL);
 
-	posix_strcpy(strzero(dest), src);
+	posix_strcpy(posix_strchr(dest, '\0'), src);
 	return dest;
 }
@@ -199,5 +188,5 @@
 	assert(src != NULL);
 
-	char *zeroptr = posix_strncpy(strzero(dest), src, n);
+	char *zeroptr = posix_strncpy(posix_strchr(dest, '\0'), src, n);
 	/* strncpy doesn't append the nul terminator, so we do it here */
 	zeroptr[n] = '\0';
@@ -240,6 +229,5 @@
 char *posix_strdup(const char *s)
 {
-	// FIXME: SIZE_MAX doesn't work
-	return posix_strndup(s, STR_NO_LIMIT);
+	return posix_strndup(s, SIZE_MAX);
 }
 
@@ -360,19 +348,6 @@
 	assert(s != NULL);
 	
-	/* special handling for the case that zero is searched for */
-	if (c == '\0') {
-		return strzero(s);
-	}
-	
-	/* otherwise just loop through the string until found */
-	while (*s != (char) c) {
-		if (*s == '\0') {
-			return NULL;
-		}
-
-		s++;
-	}
-	
-	return (char *) s;
+	char *res = gnu_strchrnul(s, c);
+	return (*res == c) ? res : NULL;
 }
 
@@ -387,5 +362,5 @@
 	assert(s != NULL);
 	
-	const char *ptr = strzero(s);
+	const char *ptr = posix_strchr(s, '\0');
 	
 	/* the same as in strchr, except it loops in reverse direction */
@@ -399,4 +374,15 @@
 
 	return (char *) ptr;
+}
+
+char *gnu_strchrnul(const char *s, int c)
+{
+	assert(s != NULL);
+	
+	while (*s != c && *s != '\0') {
+		s++;
+	}
+	
+	return (char *) s;
 }
 
@@ -524,8 +510,9 @@
 char *posix_strerror(int errnum)
 {
-	/* uses function from libc, we just have to negate errno
-	 * (POSIX uses positive errorcodes, HelenOS has negative)
+	/* Uses function from libc, we just have to negate errno
+	 * (POSIX uses positive errorcodes, HelenOS has negative).
 	 */
-	return (char *) str_error(-errnum);
+	// FIXME: not all POSIX error codes are in libc
+	return (char *) str_error(-posix_abs(errnum));
 }
 
@@ -562,5 +549,5 @@
 	assert(s != NULL);
 	
-	return (size_t) (strzero(s) - s);
+	return (size_t) (posix_strchr(s, '\0') - s);
 }
 
@@ -585,4 +572,49 @@
 }
 
+/**
+ *
+ * @param signum
+ * @return
+ */
+char *posix_strsignal(int signum)
+{
+	static const char *const sigstrings[] = {
+		[SIGABRT] = "SIGABRT (Process abort signal)",
+		[SIGALRM] = "SIGALRM (Alarm clock)",
+		[SIGBUS] = "SIGBUS (Access to an undefined portion of a memory object)",
+		[SIGCHLD] = "SIGCHLD (Child process terminated, stopped, or continued)",
+		[SIGCONT] = "SIGCONT (Continue executing, if stopped)",
+		[SIGFPE] = "SIGFPE (Erroneous arithmetic operation)",
+		[SIGHUP] = "SIGHUP (Hangup)",
+		[SIGILL] = "SIGILL (Illegal instruction)",
+		[SIGINT] = "SIGINT (Terminal interrupt signal)",
+		[SIGKILL] = "SIGKILL (Kill process)",
+		[SIGPIPE] = "SIGPIPE (Write on a pipe with no one to read it)",
+		[SIGQUIT] = "SIGQUIT (Terminal quit signal)",
+		[SIGSEGV] = "SIGSEGV (Invalid memory reference)",
+		[SIGSTOP] = "SIGSTOP (Stop executing)",
+		[SIGTERM] = "SIGTERM (Termination signal)",
+		[SIGTSTP] = "SIGTSTP (Terminal stop signal)",
+		[SIGTTIN] = "SIGTTIN (Background process attempting read)",
+		[SIGTTOU] = "SIGTTOU (Background process attempting write)",
+		[SIGUSR1] = "SIGUSR1 (User-defined signal 1)",
+		[SIGUSR2] = "SIGUSR2 (User-defined signal 2)",
+		[SIGPOLL] = "SIGPOLL (Pollable event)",
+		[SIGPROF] = "SIGPROF (Profiling timer expired)",
+		[SIGSYS] = "SIGSYS (Bad system call)",
+		[SIGTRAP] = "SIGTRAP (Trace/breakpoint trap)",
+		[SIGURG] = "SIGURG (High bandwidth data is available at a socket)",
+		[SIGVTALRM] = "SIGVTALRM (Virtual timer expired)",
+		[SIGXCPU] = "SIGXCPU (CPU time limit exceeded)",
+		[SIGXFSZ] = "SIGXFSZ (File size limit exceeded)"
+	};
+
+	if (signum <= _TOP_SIGNAL) {
+		return (char *) sigstrings[signum];
+	}
+
+	return (char *) "ERROR, Invalid signal number";
+}
+
 /** @}
  */
Index: uspace/lib/posix/string.h
===================================================================
--- uspace/lib/posix/string.h	(revision f5b25224f3b95c0a700f5f9f6c8bb2ecad2c28f0)
+++ uspace/lib/posix/string.h	(revision 8cd8bf61fa7549be36c3193a2eff646b2c0f84ec)
@@ -85,4 +85,5 @@
 extern char *posix_strchr(const char *s, int c);
 extern char *posix_strrchr(const char *s, int c);
+extern char *gnu_strchrnul(const char *s, int c);
 extern char *posix_strpbrk(const char *s1, const char *s2);
 extern size_t posix_strcspn(const char *s1, const char *s2);
@@ -101,4 +102,7 @@
 extern size_t posix_strlen(const char *s);
 extern size_t posix_strnlen(const char *s, size_t n);
+
+/* Signal messages */
+extern char *posix_strsignal(int signum);
 
 /* Legacy declarations */
@@ -127,4 +131,5 @@
 	#define strchr posix_strchr
 	#define strrchr posix_strrchr
+	#define strchrnul gnu_strchrnul
 	#define strpbrk posix_strpbrk
 	#define strcspn posix_strcspn
@@ -141,4 +146,6 @@
 	#define strnlen posix_strnlen
 
+	#define strsignal posix_strsignal
+
 	#define ffs posix_ffs
 	#define strcasecmp posix_strcasecmp
Index: uspace/lib/posix/strings.c
===================================================================
--- uspace/lib/posix/strings.c	(revision f5b25224f3b95c0a700f5f9f6c8bb2ecad2c28f0)
+++ uspace/lib/posix/strings.c	(revision 8cd8bf61fa7549be36c3193a2eff646b2c0f84ec)
@@ -38,4 +38,5 @@
 #include "internal/common.h"
 #include "strings.h"
+
 #include "string.h"
 #include "ctype.h"
Index: uspace/lib/posix/sys/stat.c
===================================================================
--- uspace/lib/posix/sys/stat.c	(revision f5b25224f3b95c0a700f5f9f6c8bb2ecad2c28f0)
+++ uspace/lib/posix/sys/stat.c	(revision 8cd8bf61fa7549be36c3193a2eff646b2c0f84ec)
@@ -36,13 +36,15 @@
 #define LIBPOSIX_INTERNAL
 
+#include "../internal/common.h"
 #include "stat.h"
-#include "../internal/common.h"
-#include <mem.h>
+
+#include "../errno.h"
+#include "../libc/mem.h"
 
 /**
- * Convert HelenOS stat struct into POSIX stat struct (if possible)
+ * Convert HelenOS stat struct into POSIX stat struct (if possible).
  *
- * @param dest
- * @param src
+ * @param dest POSIX stat struct.
+ * @param src HelenOS stat struct.
  */
 static void stat_to_posix(struct posix_stat *dest, struct stat *src)
@@ -66,14 +68,18 @@
 
 /**
+ * Retrieve file status for file associated with file descriptor.
  *
- * @param fd
- * @param st
- * @return
+ * @param fd File descriptor of the opened file.
+ * @param st Status structure to be filled with information.
+ * @return Zero on success, -1 otherwise.
  */
 int posix_fstat(int fd, struct posix_stat *st)
 {
 	struct stat hst;
-	if (fstat(fd, &hst) == -1) {
-		// TODO: propagate a POSIX compatible errno
+	int rc = fstat(fd, &hst);
+	if (rc < 0) {
+		/* fstat() returns negative error code instead of using errno.
+		 */
+		errno = -rc;
 		return -1;
 	}
@@ -83,26 +89,31 @@
 
 /**
+ * Retrieve file status for symbolic link.
  * 
- * @param path
- * @param st
- * @return
+ * @param path Path to the symbolic link.
+ * @param st Status structure to be filled with information.
+ * @return Zero on success, -1 otherwise.
  */
-int posix_lstat(const char *restrict path, struct posix_stat *restrict st)
+int posix_lstat(const char *path, struct posix_stat *st)
 {
-	// TODO
-	not_implemented();
+	/* There are currently no symbolic links in HelenOS. */
+	return posix_stat(path, st);
 }
 
 /**
+ * Retrieve file status for regular file (or symbolic link target).
  *
- * @param path
- * @param st
- * @return
+ * @param path Path to the file/link.
+ * @param st Status structure to be filled with information.
+ * @return Zero on success, -1 otherwise.
  */
 int posix_stat(const char *path, struct posix_stat *st)
 {
 	struct stat hst;
-	if (stat(path, &hst) == -1) {
-		// TODO: propagate a POSIX compatible errno
+	int rc = stat(path, &hst);
+	if (rc < 0) {
+		/* stat() returns negative error code instead of using errno.
+		 */
+		errno = -rc;
 		return -1;
 	}
@@ -112,24 +123,27 @@
 
 /**
+ * Change permission bits for the file if possible.
  * 
- * @param path
- * @param mode
- * @return
+ * @param path Path to the file.
+ * @param mode Permission bits to be set.
+ * @return Zero on success, -1 otherwise.
  */
 int posix_chmod(const char *path, mode_t mode)
 {
-	// TODO
-	not_implemented();
+	/* HelenOS doesn't support permissions, return success. */
+	return 0;
 }
 
 /**
+ * Set the file mode creation mask of the process.
  * 
- * @param mask
- * @return
+ * @param mask Set permission bits are cleared in the related creation
+ *     functions. Non-permission bits are ignored.
+ * @return Previous file mode creation mask.
  */
 mode_t posix_umask(mode_t mask)
 {
-	// TODO
-	not_implemented();
+	/* HelenOS doesn't support permissions, return empty mask. */
+	return 0;
 }
 
Index: uspace/lib/posix/sys/types.h
===================================================================
--- uspace/lib/posix/sys/types.h	(revision f5b25224f3b95c0a700f5f9f6c8bb2ecad2c28f0)
+++ uspace/lib/posix/sys/types.h	(revision 8cd8bf61fa7549be36c3193a2eff646b2c0f84ec)
@@ -52,4 +52,8 @@
 typedef struct posix_thread_attr posix_thread_attr_t;
 
+/* Clock types */
+typedef long posix_clock_t;
+typedef int posix_clockid_t;
+
 #ifndef LIBPOSIX_INTERNAL
 	#define ino_t posix_ino_t
@@ -64,4 +68,7 @@
 	
 	#define pthread_attr_t posix_thread_attr_t
+	
+	#define clock_t posix_clock_t
+	#define clockid_t posix_clockid_t
 #endif
 
Index: uspace/lib/posix/time.c
===================================================================
--- uspace/lib/posix/time.c	(revision f5b25224f3b95c0a700f5f9f6c8bb2ecad2c28f0)
+++ uspace/lib/posix/time.c	(revision 8cd8bf61fa7549be36c3193a2eff646b2c0f84ec)
@@ -36,7 +36,360 @@
 #define LIBPOSIX_INTERNAL
 
+/* Must be first. */
+#include "stdbool.h"
+
 #include "internal/common.h"
 #include "time.h"
 
+#include "ctype.h"
+#include "errno.h"
+#include "signal.h"
+
+#include "libc/malloc.h"
+#include "libc/task.h"
+#include "libc/stats.h"
+#include "libc/sys/time.h"
+
+// TODO: documentation
+// TODO: test everything in this file
+
+/* Helper functions ***********************************************************/
+
+#define HOURS_PER_DAY (24)
+#define MINS_PER_HOUR (60)
+#define SECS_PER_MIN (60)
+#define MINS_PER_DAY (MINS_PER_HOUR * HOURS_PER_DAY)
+#define SECS_PER_HOUR (SECS_PER_MIN * MINS_PER_HOUR)
+#define SECS_PER_DAY (SECS_PER_HOUR * HOURS_PER_DAY)
+
+static bool _is_leap_year(time_t year)
+{
+	year += 1900;
+
+	if (year % 400 == 0)
+		return true;
+	if (year % 100 == 0)
+		return false;
+	if (year % 4 == 0)
+		return true;
+	return false;
+}
+
+static int _days_in_month(time_t year, time_t mon)
+{
+	assert(mon >= 0 && mon <= 11);
+	year += 1900;
+
+	static int month_days[] =
+		{ 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+	if (mon == 1) {
+		/* february */
+		return _is_leap_year(year) ? 29 : 28;
+	} else {
+		return month_days[mon];
+	}
+}
+
+static int _day_of_year(time_t year, time_t mon, time_t mday)
+{
+	static int mdays[] =
+	    { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
+	static int leap_mdays[] =
+	    { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
+
+	return (_is_leap_year(year) ? leap_mdays[mon] : mdays[mon]) + mday - 1;
+}
+
+/* Integer division that rounds to negative infinity.
+ */
+static time_t _floor_div(time_t op1, time_t op2)
+{
+	if (op1 >= 0 || op1 % op2 == 0) {
+		return op1 / op2;
+	} else {
+		return op1 / op2 - 1;
+	}
+}
+
+/* Modulo that rounds to negative infinity.
+ */
+static time_t _floor_mod(time_t op1, time_t op2)
+{
+	int div = _floor_div(op1, op2);
+
+	/* (a / b) * b + a % b == a */
+	/* thus, a % b == a - (a / b) * b */
+
+	int result = op1 - div * op2;
+	
+	/* Some paranoid checking to ensure I didn't make a mistake here. */
+	assert(result >= 0);
+	assert(result < op2);
+	assert(div * op2 + result == op1);
+	
+	return result;
+}
+
+static time_t _days_since_epoch(time_t year, time_t mon, time_t mday)
+{
+	return (year - 70) * 365 + _floor_div(year - 69, 4) -
+	    _floor_div(year - 1, 100) + _floor_div(year + 299, 400) +
+	    _day_of_year(year, mon, mday);
+}
+
+/* Assumes normalized broken-down time. */
+static time_t _secs_since_epoch(const struct posix_tm *tm)
+{
+	return _days_since_epoch(tm->tm_year, tm->tm_mon, tm->tm_mday) *
+	    SECS_PER_DAY + tm->tm_hour * SECS_PER_HOUR +
+	    tm->tm_min * SECS_PER_MIN + tm->tm_sec;
+}
+
+static int _day_of_week(time_t year, time_t mon, time_t mday)
+{
+	/* 1970-01-01 is Thursday */
+	return (_days_since_epoch(year, mon, mday) + 4) % 7;
+}
+
+struct _long_tm {
+	time_t tm_sec;
+	time_t tm_min;
+	time_t tm_hour;
+	time_t tm_mday;
+	time_t tm_mon;
+	time_t tm_year;
+	int tm_wday;
+	int tm_yday;
+	int tm_isdst;
+};
+
+static void _posix_to_long_tm(struct _long_tm *ltm, struct posix_tm *ptm)
+{
+	assert(ltm != NULL && ptm != NULL);
+	ltm->tm_sec = ptm->tm_sec;
+	ltm->tm_min = ptm->tm_min;
+	ltm->tm_hour = ptm->tm_hour;
+	ltm->tm_mday = ptm->tm_mday;
+	ltm->tm_mon = ptm->tm_mon;
+	ltm->tm_year = ptm->tm_year;
+	ltm->tm_wday = ptm->tm_wday;
+	ltm->tm_yday = ptm->tm_yday;
+	ltm->tm_isdst = ptm->tm_isdst;
+}
+
+static void _long_to_posix_tm(struct posix_tm *ptm, struct _long_tm *ltm)
+{
+	assert(ltm != NULL && ptm != NULL);
+	// FIXME: the cast should be unnecessary, libarch/common.h brain-damage
+	assert((ltm->tm_year >= (int) INT_MIN) && (ltm->tm_year <= (int) INT_MAX));
+
+	ptm->tm_sec = ltm->tm_sec;
+	ptm->tm_min = ltm->tm_min;
+	ptm->tm_hour = ltm->tm_hour;
+	ptm->tm_mday = ltm->tm_mday;
+	ptm->tm_mon = ltm->tm_mon;
+	ptm->tm_year = ltm->tm_year;
+	ptm->tm_wday = ltm->tm_wday;
+	ptm->tm_yday = ltm->tm_yday;
+	ptm->tm_isdst = ltm->tm_isdst;
+}
+
+static void _normalize_time(struct _long_tm *tm)
+{
+	// TODO: DST correction
+
+	/* Adjust time. */
+	tm->tm_min += _floor_div(tm->tm_sec, SECS_PER_MIN);
+	tm->tm_sec = _floor_mod(tm->tm_sec, SECS_PER_MIN);
+	tm->tm_hour += _floor_div(tm->tm_min, MINS_PER_HOUR);
+	tm->tm_min = _floor_mod(tm->tm_min, MINS_PER_HOUR);
+	tm->tm_mday += _floor_div(tm->tm_hour, HOURS_PER_DAY);
+	tm->tm_hour = _floor_mod(tm->tm_hour, HOURS_PER_DAY);
+
+	/* Adjust month. */
+	tm->tm_year += _floor_div(tm->tm_mon, 12);
+	tm->tm_mon = _floor_mod(tm->tm_mon, 12);
+
+	/* Now the difficult part - days of month. */
+	/* Slow, but simple. */
+	// FIXME: do this faster
+
+	while (tm->tm_mday < 1) {
+		tm->tm_mon--;
+		if (tm->tm_mon == -1) {
+			tm->tm_mon = 11;
+			tm->tm_year--;
+		}
+		
+		tm->tm_mday += _days_in_month(tm->tm_year, tm->tm_mon);
+	}
+
+	while (tm->tm_mday > _days_in_month(tm->tm_year, tm->tm_mon)) {
+		tm->tm_mday -= _days_in_month(tm->tm_year, tm->tm_mon);
+		
+		tm->tm_mon++;
+		if (tm->tm_mon == 12) {
+			tm->tm_mon = 0;
+			tm->tm_year++;
+		}
+	}
+
+	/* Calculate the remaining two fields. */
+	tm->tm_yday = _day_of_year(tm->tm_year, tm->tm_mon, tm->tm_mday);
+	tm->tm_wday = _day_of_week(tm->tm_year, tm->tm_mon, tm->tm_mday);
+}
+
+/* Which day the week-based year starts on relative to the first calendar day.
+ * E.g. if the year starts on December 31st, the return value is -1.
+ */
+static int _wbyear_offset(int year)
+{
+	int start_wday = _day_of_week(year, 0, 1);
+	return _floor_mod(4 - start_wday, 7) - 3;
+}
+
+/* Returns week-based year of the specified time.
+ * Assumes normalized broken-down time.
+ */
+static int _wbyear(const struct posix_tm *tm)
+{
+	int day = tm->tm_yday - _wbyear_offset(tm->tm_year);
+	if (day < 0) {
+		/* Last week of previous year. */
+		return tm->tm_year - 1;
+	}
+	if (day > 364 + _is_leap_year(tm->tm_year)){
+		/* First week of next year. */
+		return tm->tm_year + 1;
+	}
+	/* All the other days are in the calendar year. */
+	return tm->tm_year;
+}
+
+/** Week number of the year, assuming weeks start on sunday.
+ *  The first Sunday of January is the first day of week 1;
+ *  days in the new year before this are in week 0.
+ *
+ * @param tm Normalized broken-down time.
+ * @return The week number (0 - 53).
+ */
+static int _sun_week_number(const struct posix_tm *tm)
+{
+	int first_day = (7 - _day_of_week(tm->tm_year, 0, 1)) % 7;
+	return (tm->tm_yday - first_day + 7) / 7;
+}
+
+/** Week number of the year, assuming weeks start on monday.
+ *  If the week containing January 1st has four or more days in the new year,
+ *  then it is considered week 1. Otherwise, it is the last week of the previous
+ *  year, and the next week is week 1. Both January 4th and the first Thursday
+ *  of January are always in week 1.
+ *
+ * @param tm Normalized broken-down time.
+ * @return The week number (1 - 53).
+ */
+static int _iso_week_number(const struct posix_tm *tm)
+{
+	int day = tm->tm_yday - _wbyear_offset(tm->tm_year);
+	if (day < 0) {
+		/* Last week of previous year. */
+		return 53;
+	}
+	if (day > 364 + _is_leap_year(tm->tm_year)){
+		/* First week of next year. */
+		return 1;
+	}
+	/* All the other days give correct answer. */
+	return (day / 7 + 1);
+}
+
+/** Week number of the year, assuming weeks start on monday.
+ *  The first Monday of January is the first day of week 1;
+ *  days in the new year before this are in week 0. 
+ *
+ * @param tm Normalized broken-down time.
+ * @return The week number (0 - 53).
+ */
+static int _mon_week_number(const struct posix_tm *tm)
+{
+	int first_day = (1 - _day_of_week(tm->tm_year, 0, 1)) % 7;
+	return (tm->tm_yday - first_day + 7) / 7;
+}
+
+/******************************************************************************/
+
+int posix_daylight;
+long posix_timezone;
+char *posix_tzname[2];
+
+void posix_tzset(void)
+{
+	// TODO: read environment
+	posix_tzname[0] = (char *) "GMT";
+	posix_tzname[1] = (char *) "GMT";
+	posix_daylight = 0;
+	posix_timezone = 0;
+}
+
+double posix_difftime(time_t time1, time_t time0)
+{
+	return (double) (time1 - time0);
+}
+
+/** This function first normalizes the provided broken-down time
+ *  (moves all values to their proper bounds) and then tries to
+ *  calculate the appropriate time_t representation.
+ *
+ * @param timeptr Broken-down time.
+ * @return time_t representation of the time, undefined value on overflow
+ */
+time_t posix_mktime(struct posix_tm *tm)
+{
+	// TODO: take DST flag into account
+	// TODO: detect overflow
+
+	struct _long_tm ltm;
+	_posix_to_long_tm(&ltm, tm);
+	_normalize_time(&ltm);
+	_long_to_posix_tm(tm, &ltm);
+
+	return _secs_since_epoch(tm);
+}
+
+struct posix_tm *posix_gmtime(const time_t *timer)
+{
+	static struct posix_tm result;
+	return posix_gmtime_r(timer, &result);
+}
+
+struct posix_tm *posix_gmtime_r(const time_t *restrict timer,
+    struct posix_tm *restrict result)
+{
+	assert(timer != NULL);
+	assert(result != NULL);
+
+	/* Set epoch and seconds to _long_tm struct and normalize to get
+	 * correct values.
+	 */
+	struct _long_tm ltm = {
+		.tm_sec = *timer,
+		.tm_min = 0,
+		.tm_hour = 0, /* 00:00:xx */
+		.tm_mday = 1,
+		.tm_mon = 0, /* January 1st */
+		.tm_year = 70, /* 1970 */
+	};
+	_normalize_time(&ltm);
+
+	if (ltm.tm_year < (int) INT_MIN || ltm.tm_year > (int) INT_MAX) {
+		errno = EOVERFLOW;
+		return NULL;
+	}
+
+	_long_to_posix_tm(result, &ltm);
+	return result;
+}
+
 /**
  *
@@ -44,9 +397,16 @@
  * @return
  */
-struct posix_tm *posix_localtime(const time_t *timep)
-{
-	// TODO
-	static struct posix_tm result = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-	return &result;
+struct posix_tm *posix_localtime(const time_t *timer)
+{
+	static struct posix_tm result;
+	return posix_localtime_r(timer, &result);
+}
+
+struct posix_tm *posix_localtime_r(const time_t *restrict timer,
+    struct posix_tm *restrict result)
+{
+	// TODO: deal with timezone
+	// currently assumes system and all times are in GMT
+	return posix_gmtime_r(timer, result);
 }
 
@@ -56,9 +416,32 @@
  * @return
  */
-char *posix_asctime(const struct posix_tm *tm)
-{
-	// TODO
-	static char result[] = "Sun Jan 01 00:00:00 1900\n";
-	return result;
+char *posix_asctime(const struct posix_tm *timeptr)
+{
+	static char buf[ASCTIME_BUF_LEN];
+	return posix_asctime_r(timeptr, buf);
+}
+
+char *posix_asctime_r(const struct posix_tm *restrict timeptr,
+    char *restrict buf)
+{
+	assert(timeptr != NULL);
+	assert(buf != NULL);
+
+	static const char *wday[] = {
+		"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+	};
+	static const char *mon[] = {
+		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
+		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+	};
+
+	snprintf(buf, ASCTIME_BUF_LEN, "%s %s %2d %02d:%02d:%02d %d\n",
+	    wday[timeptr->tm_wday],
+	    mon[timeptr->tm_mon],
+	    timeptr->tm_mday, timeptr->tm_hour,
+	    timeptr->tm_min, timeptr->tm_sec,
+	    1900 + timeptr->tm_year);
+
+	return buf;
 }
 
@@ -68,7 +451,20 @@
  * @return
  */
-char *posix_ctime(const time_t *timep)
-{
-	return posix_asctime(posix_localtime(timep));
+char *posix_ctime(const time_t *timer)
+{
+	struct posix_tm *loctime = posix_localtime(timer);
+	if (loctime == NULL) {
+		return NULL;
+	}
+	return posix_asctime(loctime);
+}
+
+char *posix_ctime_r(const time_t *timer, char *buf)
+{
+	struct posix_tm loctime;
+	if (posix_localtime_r(timer, &loctime) == NULL) {
+		return NULL;
+	}
+	return posix_asctime_r(&loctime, buf);
 }
 
@@ -81,5 +477,265 @@
  * @return
  */
-size_t posix_strftime(char *s, size_t maxsize, const char *format, const struct posix_tm *tm)
+size_t posix_strftime(char *s, size_t maxsize,
+    const char *format, const struct posix_tm *tm)
+{
+	// TODO: use locale
+	static const char *wday_abbr[] = {
+		"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+	};
+	static const char *wday[] = {
+		"Sunday", "Monday", "Tuesday", "Wednesday",
+		"Thursday", "Friday", "Saturday"
+	};
+	static const char *mon_abbr[] = {
+		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
+		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+	};
+	static const char *mon[] = {
+		"January", "February", "March", "April", "May", "June", "July",
+		"August", "September", "October", "November", "December"
+	};
+	
+	if (maxsize < 1) {
+		return 0;
+	}
+	
+	char *ptr = s;
+	size_t consumed;
+	size_t remaining = maxsize;
+	
+	#define append(...) { \
+		/* FIXME: this requires POSIX-correct snprintf */ \
+		/*        otherwise it won't work with non-ascii chars */ \
+		consumed = snprintf(ptr, remaining, __VA_ARGS__); \
+		if (consumed >= remaining) { \
+			return 0; \
+		} \
+		ptr += consumed; \
+		remaining -= consumed; \
+	}
+	
+	#define recurse(fmt) { \
+		consumed = posix_strftime(ptr, remaining, fmt, tm); \
+		if (consumed == 0) { \
+			return 0; \
+		} \
+		ptr += consumed; \
+		remaining -= consumed; \
+	}
+	
+	#define TO_12H(hour) (((hour) > 12) ? ((hour) - 12) : \
+	    (((hour) == 0) ? 12 : (hour)))
+	
+	while (*format != '\0') {
+		if (*format != '%') {
+			append("%c", *format);
+			format++;
+			continue;
+		}
+		
+		format++;
+		if (*format == '0' || *format == '+') {
+			// TODO: padding
+			format++;
+		}
+		while (isdigit(*format)) {
+			// TODO: padding
+			format++;
+		}
+		if (*format == 'O' || *format == 'E') {
+			// TODO: locale's alternative format
+			format++;
+		}
+		
+		switch (*format) {
+		case 'a':
+			append("%s", wday_abbr[tm->tm_wday]); break;
+		case 'A':
+			append("%s", wday[tm->tm_wday]); break;
+		case 'b':
+			append("%s", mon_abbr[tm->tm_mon]); break;
+		case 'B':
+			append("%s", mon[tm->tm_mon]); break;
+		case 'c':
+			// TODO: locale-specific datetime format
+			recurse("%Y-%m-%d %H:%M:%S"); break;
+		case 'C':
+			append("%02d", (1900 + tm->tm_year) / 100); break;
+		case 'd':
+			append("%02d", tm->tm_mday); break;
+		case 'D':
+			recurse("%m/%d/%y"); break;
+		case 'e':
+			append("%2d", tm->tm_mday); break;
+		case 'F':
+			recurse("%+4Y-%m-%d"); break;
+		case 'g':
+			append("%02d", _wbyear(tm) % 100); break;
+		case 'G':
+			append("%d", _wbyear(tm)); break;
+		case 'h':
+			recurse("%b"); break;
+		case 'H':
+			append("%02d", tm->tm_hour); break;
+		case 'I':
+			append("%02d", TO_12H(tm->tm_hour)); break;
+		case 'j':
+			append("%03d", tm->tm_yday); break;
+		case 'k':
+			append("%2d", tm->tm_hour); break;
+		case 'l':
+			append("%2d", TO_12H(tm->tm_hour)); break;
+		case 'm':
+			append("%02d", tm->tm_mon); break;
+		case 'M':
+			append("%02d", tm->tm_min); break;
+		case 'n':
+			append("\n"); break;
+		case 'p':
+			append("%s", tm->tm_hour < 12 ? "AM" : "PM"); break;
+		case 'P':
+			append("%s", tm->tm_hour < 12 ? "am" : "PM"); break;
+		case 'r':
+			recurse("%I:%M:%S %p"); break;
+		case 'R':
+			recurse("%H:%M"); break;
+		case 's':
+			append("%ld", _secs_since_epoch(tm)); break;
+		case 'S':
+			append("%02d", tm->tm_sec); break;
+		case 't':
+			append("\t"); break;
+		case 'T':
+			recurse("%H:%M:%S"); break;
+		case 'u':
+			append("%d", (tm->tm_wday == 0) ? 7 : tm->tm_wday); break;
+		case 'U':
+			append("%02d", _sun_week_number(tm)); break;
+		case 'V':
+			append("%02d", _iso_week_number(tm)); break;
+		case 'w':
+			append("%d", tm->tm_wday); break;
+		case 'W':
+			append("%02d", _mon_week_number(tm)); break;
+		case 'x':
+			// TODO: locale-specific date format
+			recurse("%Y-%m-%d"); break;
+		case 'X':
+			// TODO: locale-specific time format
+			recurse("%H:%M:%S"); break;
+		case 'y':
+			append("%02d", tm->tm_year % 100); break;
+		case 'Y':
+			append("%d", 1900 + tm->tm_year); break;
+		case 'z':
+			// TODO: timezone
+			break;
+		case 'Z':
+			// TODO: timezone
+			break;
+		case '%':
+			append("%%");
+			break;
+		default:
+			/* Invalid specifier, print verbatim. */
+			while (*format != '%') {
+				format--;
+			}
+			append("%%");
+			break;
+		}
+		format++;
+	}
+	
+	#undef append
+	#undef recurse
+	
+	return maxsize - remaining;
+}
+
+int posix_clock_getres(posix_clockid_t clock_id, struct posix_timespec *res)
+{
+	assert(res != NULL);
+
+	switch (clock_id) {
+		case CLOCK_REALTIME:
+			res->tv_sec = 0;
+			res->tv_nsec = 1000; /* Microsecond resolution. */
+			return 0;
+		default:
+			errno = EINVAL;
+			return -1;
+	}
+}
+
+int posix_clock_gettime(posix_clockid_t clock_id, struct posix_timespec *tp)
+{
+	assert(tp != NULL);
+
+	switch (clock_id) {
+		case CLOCK_REALTIME:
+			;
+			struct timeval tv;
+			gettimeofday(&tv, NULL);
+			tp->tv_sec = tv.tv_sec;
+			tp->tv_nsec = tv.tv_usec * 1000;
+			return 0;
+		default:
+			errno = EINVAL;
+			return -1;
+	}
+}
+
+int posix_clock_settime(posix_clockid_t clock_id,
+    const struct posix_timespec *tp)
+{
+	assert(tp != NULL);
+
+	switch (clock_id) {
+		case CLOCK_REALTIME:
+			// TODO: setting clock
+			// FIXME: HelenOS doesn't actually support hardware
+			//        clock yet
+			errno = EPERM;
+			return -1;
+		default:
+			errno = EINVAL;
+			return -1;
+	}
+}
+
+int posix_clock_nanosleep(posix_clockid_t clock_id, int flags,
+    const struct posix_timespec *rqtp, struct posix_timespec *rmtp)
+{
+	assert(rqtp != NULL);
+	assert(rmtp != NULL);
+
+	switch (clock_id) {
+		case CLOCK_REALTIME:
+			// TODO: interruptible sleep
+			if (rqtp->tv_sec != 0) {
+				sleep(rqtp->tv_sec);
+			}
+			if (rqtp->tv_nsec != 0) {
+				usleep(rqtp->tv_nsec / 1000);
+			}
+			return 0;
+		default:
+			errno = EINVAL;
+			return -1;
+	}
+}
+
+#if 0
+
+struct __posix_timer {
+	posix_clockid_t clockid;
+	struct posix_sigevent evp;
+};
+
+int posix_timer_create(posix_clockid_t clockid,
+    struct posix_sigevent *restrict evp,
+    posix_timer_t *restrict timerid)
 {
 	// TODO
@@ -87,9 +743,5 @@
 }
 
-/**
- * 
- * @return
- */
-posix_clock_t posix_clock(void)
+int posix_timer_delete(posix_timer_t timerid)
 {
 	// TODO
@@ -97,4 +749,45 @@
 }
 
+int posix_timer_getoverrun(posix_timer_t timerid)
+{
+	// TODO
+	not_implemented();
+}
+
+int posix_timer_gettime(posix_timer_t timerid,
+    struct posix_itimerspec *value)
+{
+	// TODO
+	not_implemented();
+}
+
+int posix_timer_settime(posix_timer_t timerid, int flags,
+    const struct posix_itimerspec *restrict value,
+    struct posix_itimerspec *restrict ovalue)
+{
+	// TODO
+	not_implemented();
+}
+
+#endif
+
+/**
+ * Get CPU time used since the process invocation.
+ *
+ * @return Consumed CPU cycles by this process or -1 if not available.
+ */
+posix_clock_t posix_clock(void)
+{
+	posix_clock_t total_cycles = -1;
+	stats_task_t *task_stats = stats_get_task(task_get_id());
+	if (task_stats) {
+		total_cycles = (posix_clock_t) (task_stats->kcycles + task_stats->ucycles);
+	}
+	free(task_stats);
+	task_stats = 0;
+
+	return total_cycles;
+}
+
 /** @}
  */
Index: uspace/lib/posix/time.h
===================================================================
--- uspace/lib/posix/time.h	(revision f5b25224f3b95c0a700f5f9f6c8bb2ecad2c28f0)
+++ uspace/lib/posix/time.h	(revision 8cd8bf61fa7549be36c3193a2eff646b2c0f84ec)
@@ -38,8 +38,34 @@
 
 #include "libc/time.h"
+#include "sys/types.h"
 
 #ifndef NULL
 	#define NULL  ((void *) 0)
 #endif
+
+#ifndef CLOCKS_PER_SEC
+	#define CLOCKS_PER_SEC (1000000L)
+#endif
+
+#ifndef __locale_t_defined
+	#define __locale_t_defined
+	typedef struct __posix_locale *posix_locale_t;
+	#ifndef LIBPOSIX_INTERNAL
+		#define locale_t posix_locale_t
+	#endif
+#endif
+
+#ifndef POSIX_SIGNAL_H_
+	struct posix_sigevent;
+	#ifndef LIBPOSIX_INTERNAL
+		#define sigevent posix_sigevent
+	#endif
+#endif
+
+#undef ASCTIME_BUF_LEN
+#define ASCTIME_BUF_LEN 26
+
+#undef CLOCK_REALTIME
+#define CLOCK_REALTIME ((posix_clockid_t) 0)
 
 struct posix_tm {
@@ -55,28 +81,119 @@
 };
 
-typedef long posix_clock_t;
+struct posix_timespec {
+	time_t tv_sec; /* Seconds. */
+	long tv_nsec; /* Nanoseconds. */
+};
+
+struct posix_itimerspec {
+	struct posix_timespec it_interval; /* Timer period. */
+	struct posix_timespec it_value; /* Timer expiration. */
+};
+
+typedef struct __posix_timer *posix_timer_t;
+
+/* Timezones */
+
+extern int posix_daylight;
+extern long posix_timezone;
+extern char *posix_tzname[2];
+
+extern void posix_tzset(void);
+
+/* time_t */
+
+extern double posix_difftime(time_t time1, time_t time0);
 
 /* Broken-down Time */
-extern struct posix_tm *posix_localtime(const time_t *timep);
+extern time_t posix_mktime(struct posix_tm *timeptr);
+extern struct posix_tm *posix_gmtime(const time_t *timer);
+extern struct posix_tm *posix_gmtime_r(const time_t *restrict timer,
+    struct posix_tm *restrict result);
+extern struct posix_tm *posix_localtime(const time_t *timer);
+extern struct posix_tm *posix_localtime_r(const time_t *restrict timer,
+    struct posix_tm *restrict result);
 
 /* Formatting Calendar Time */
-extern char *posix_asctime(const struct posix_tm *tm);
-extern char *posix_ctime(const time_t *timep);
-extern size_t posix_strftime(char *restrict s, size_t maxsize, const char *restrict format, const struct posix_tm *restrict tm);
+extern char *posix_asctime(const struct posix_tm *timeptr);
+extern char *posix_asctime_r(const struct posix_tm *restrict timeptr,
+    char *restrict buf);
+extern char *posix_ctime(const time_t *timer);
+extern char *posix_ctime_r(const time_t *timer, char *buf);
+
+extern size_t posix_strftime(char *restrict s, size_t maxsize,
+    const char *restrict format, const struct posix_tm *restrict tm);
+
+extern size_t posix_strftime_l(char *restrict s, size_t maxsize,
+    const char *restrict format, const struct posix_tm *restrict tm,
+    posix_locale_t loc);
+
+/* Clocks. */
+
+extern int posix_clock_getres(posix_clockid_t clock_id,
+    struct posix_timespec *res);
+extern int posix_clock_gettime(posix_clockid_t clock_id,
+    struct posix_timespec *tp);
+extern int posix_clock_settime(posix_clockid_t clock_id,
+    const struct posix_timespec *tp); 
+extern int posix_clock_nanosleep(posix_clockid_t clock_id, int flags,
+    const struct posix_timespec *rqtp, struct posix_timespec *rmtp);
+
+/* Timers. */
+
+#if 0
+
+extern int posix_timer_create(posix_clockid_t clockid,
+    struct posix_sigevent *restrict evp,
+    posix_timer_t *restrict timerid);
+extern int posix_timer_delete(posix_timer_t timerid);
+extern int posix_timer_getoverrun(posix_timer_t timerid);
+extern int posix_timer_gettime(posix_timer_t timerid,
+    struct posix_itimerspec *value);
+extern int posix_timer_settime(posix_timer_t timerid, int flags,
+    const struct posix_itimerspec *restrict value,
+    struct posix_itimerspec *restrict ovalue);
+
+#endif
 
 /* CPU Time */
 extern posix_clock_t posix_clock(void);
 
+
 #ifndef LIBPOSIX_INTERNAL
 	#define tm posix_tm
 
-	#define clock_t posix_clock_t
-
+	#define timespec posix_timespec
+	#define itimerspec posix_itimerspec
+	#define timer_t posix_timer_t
+
+	#define difftime posix_difftime
+	#define mktime posix_mktime
+	#define gmtime posix_gmtime
+	#define gmtime_r posix_gmtime_r
 	#define localtime posix_localtime
+	#define localtime_r posix_localtime_r
+
+	#define daylight posix_daylight
+	#define timezone posix_timezone
+	#define tzname posix_tzname
+	#define tzset posix_tzset
 
 	#define asctime posix_asctime
+	#define asctime_r posix_asctime_r
 	#define ctime posix_ctime
+	#define ctime_r posix_ctime_r
 	#define strftime posix_strftime
 
+	#define clock_getres posix_clock_getres
+	#define clock_gettime posix_clock_gettime
+	#define clock_settime posix_clock_settime
+	#define clock_nanosleep posix_clock_nanosleep
+	
+	#define timer_create posix_timer_create
+	#define timer_delete posix_timer_delete
+	#define timer_getoverrun posix_timer_getoverrun
+	#define timer_gettime posix_timer_gettime
+	#define timer_settime posix_timer_settime
+	
 	#define clock posix_clock
 #endif
Index: uspace/lib/posix/unistd.c
===================================================================
--- uspace/lib/posix/unistd.c	(revision f5b25224f3b95c0a700f5f9f6c8bb2ecad2c28f0)
+++ uspace/lib/posix/unistd.c	(revision 8cd8bf61fa7549be36c3193a2eff646b2c0f84ec)
@@ -38,24 +38,63 @@
 #include "internal/common.h"
 #include "unistd.h"
-#include <task.h>
+
+#include "errno.h"
+#include "string.h"
+#include "fcntl.h"
+
+#include "libc/task.h"
+#include "libc/stats.h"
+#include "libc/malloc.h"
 
 /* Array of environment variable strings (NAME=VALUE). */
-char **environ = NULL;
-
-/**
- * Dummy function. Always returns false, because there is no easy way to find
- * out under HelenOS.
- *
- * @param fd
- * @return Always false.
+char **posix_environ = NULL;
+
+/**
+ * Get current user name.
+ *
+ * @return User name (static) string or NULL if not found.
+ */
+char *posix_getlogin(void)
+{
+	/* There is currently no support for user accounts in HelenOS. */
+	return (char *) "user";
+}
+
+/**
+ * Get current user name.
+ *
+ * @param name Pointer to a user supplied buffer.
+ * @param namesize Length of the buffer.
+ * @return Zero on success, error code otherwise.
+ */
+int posix_getlogin_r(char *name, size_t namesize)
+{
+	/* There is currently no support for user accounts in HelenOS. */
+	if (namesize >= 5) {
+		posix_strcpy(name, (char *) "user");
+		return 0;
+	} else {
+		errno = ERANGE;
+		return -1;
+	}
+}
+
+/**
+ * Test whether open file descriptor is associated with a terminal.
+ *
+ * @param fd Open file descriptor to test.
+ * @return Boolean result of the test.
  */
 int posix_isatty(int fd)
 {
+	/* Always returns false, because there is no easy way to find
+     * out under HelenOS. */
 	return false;
 }
 
 /**
- * 
- * @return
+ * Determine the page size of the current run of the process.
+ *
+ * @return Page size of the process.
  */
 int posix_getpagesize(void)
@@ -65,6 +104,7 @@
 
 /**
- * 
- * @return
+ * Get the process ID of the calling process.
+ *
+ * @return Process ID.
  */
 posix_pid_t posix_getpid(void)
@@ -74,44 +114,95 @@
 
 /**
- *
- * @return
+ * Get the real user ID of the calling process.
+ *
+ * @return User ID.
  */
 posix_uid_t posix_getuid(void)
 {
-	// TODO
-	not_implemented();
-}
-
-/**
- * 
- * @return
+	/* There is currently no support for user accounts in HelenOS. */
+	return 0;
+}
+
+/**
+ * Get the real group ID of the calling process.
+ * 
+ * @return Group ID.
  */
 posix_gid_t posix_getgid(void)
 {
-	// TODO
-	not_implemented();
-}
-
-/**
- * 
- * @param path
- * @param amode
- * @return
+	/* There is currently no support for user accounts in HelenOS. */
+	return 0;
+}
+
+/**
+ * Determine accessibility of a file.
+ *
+ * @param path File to check accessibility for.
+ * @param amode Either check for existence or intended access mode.
+ * @return Zero on success, -1 otherwise.
  */
 int posix_access(const char *path, int amode)
 {
-	// TODO
-	not_implemented();
-}
-
-/**
- * 
- * @param name
- * @return
+	if (amode == F_OK) {
+		/* Check file existence by attempt to open it. */
+		int fd = open(path, O_RDONLY);
+		if (fd < 0) {
+			/* FIXME: open() returns error code as negative retval. */
+			errno = -fd;
+			fd = -1;
+		} else {
+			close(fd);
+		}
+		return fd;
+	} else if (amode & (X_OK | W_OK | R_OK)) {
+		/* HelenOS doesn't support permissions, return success. */
+		return 0;
+	} else {
+		/* Invalid amode argument. */
+		errno = EINVAL;
+		return -1;
+	}
+}
+
+/**
+ * Get configurable system variables.
+ * 
+ * @param name Variable name.
+ * @return Variable value.
  */
 long posix_sysconf(int name)
 {
-	// TODO
-	not_implemented();
+	long clk_tck = 0;
+	size_t cpu_count = 0;
+	stats_cpu_t *cpu_stats = stats_get_cpus(&cpu_count);
+	if (cpu_stats && cpu_count > 0) {
+		clk_tck = ((long) cpu_stats[0].frequency_mhz) * 1000000L;
+	}
+	free(cpu_stats);
+	cpu_stats = 0;
+
+	long phys_pages = 0;
+	long avphys_pages = 0;
+	stats_physmem_t *mem_stats = stats_get_physmem();
+	if (mem_stats) {
+		phys_pages = (long) (mem_stats->total / getpagesize());
+		avphys_pages = (long) (mem_stats->free / getpagesize());
+	}
+	free(mem_stats);
+	mem_stats = 0;
+
+	switch (name) {
+	case _SC_PHYS_PAGES:
+		return phys_pages;
+	case _SC_AVPHYS_PAGES:
+		return avphys_pages;
+	case _SC_PAGESIZE:
+		return getpagesize();
+	case _SC_CLK_TCK:
+		return clk_tck;
+	default:
+		errno = EINVAL;
+		return -1;
+	}
 }
 
Index: uspace/lib/posix/unistd.h
===================================================================
--- uspace/lib/posix/unistd.h	(revision f5b25224f3b95c0a700f5f9f6c8bb2ecad2c28f0)
+++ uspace/lib/posix/unistd.h	(revision 8cd8bf61fa7549be36c3193a2eff646b2c0f84ec)
@@ -48,6 +48,9 @@
 extern int getopt(int, char * const [], const char *);
 
-/* Environmental Variables */
+/* Environment */
 extern char **posix_environ;
+
+extern char *posix_getlogin(void);
+extern int posix_getlogin_r(char *name, size_t namesize);
 
 /* Identifying Terminals */
@@ -126,4 +129,6 @@
 #ifndef LIBPOSIX_INTERNAL
 	#define environ posix_environ
+	#define getlogin posix_getlogin
+	#define getlogin_r posix_getlogin_r
 
 	#define isatty posix_isatty
