Index: uspace/Makefile.common
===================================================================
--- uspace/Makefile.common	(revision fb0ec570bdde8224b2b38d270815b990dbef9225)
+++ uspace/Makefile.common	(revision 4e6a610ce2ce4852d4b90413ede7ea606cc91eaa)
@@ -165,5 +165,5 @@
 ifneq ($(TEST_SOURCES),)
 	TEST_OUTPUTS = $(TEST_BINARY) $(TEST_BINARY).disasm
-	TEST_CFLAGS = -I$(LIB_PREFIX)/pcut/include -D__helenos__
+	TEST_CFLAGS = -I$(LIB_PREFIX)/pcut/include -D__helenos__ $(EXTRA_TEST_CFLAGS)
 	TEST_BINARY_LIBS = $(LIB_PREFIX)/pcut/libpcut.a
 	EXTRA_CLEAN += $(TEST_OUTPUTS) $(TEST_BINARY).map
Index: uspace/lib/c/Makefile
===================================================================
--- uspace/lib/c/Makefile	(revision fb0ec570bdde8224b2b38d270815b990dbef9225)
+++ uspace/lib/c/Makefile	(revision 4e6a610ce2ce4852d4b90413ede7ea606cc91eaa)
@@ -41,4 +41,5 @@
 EXTRA_OUTPUT = $(LINKER_SCRIPTS)
 EXTRA_CLEAN = $(LINKER_SCRIPTS)
+EXTRA_TEST_CFLAGS = -Wno-deprecated-declarations
 LIBRARY = libc
 SOVERSION = 0.0
@@ -151,4 +152,5 @@
 	generic/adt/prodcons.c \
 	generic/time.c \
+	generic/tmpfile.c \
 	generic/stdio.c \
 	generic/stdlib.c \
Index: uspace/lib/c/generic/stdio.c
===================================================================
--- uspace/lib/c/generic/stdio.c	(revision fb0ec570bdde8224b2b38d270815b990dbef9225)
+++ uspace/lib/c/generic/stdio.c	(revision 4e6a610ce2ce4852d4b90413ede7ea606cc91eaa)
@@ -34,7 +34,13 @@
 
 #include <errno.h>
+#include <stdbool.h>
 #include <stdio.h>
+#include <str.h>
 #include <str_error.h>
+#include <tmpfile.h>
 #include <vfs/vfs.h>
+
+/** Static buffer for tmpnam function */
+static char tmpnam_buf[L_tmpnam];
 
 /** Get stream position.
@@ -82,4 +88,8 @@
 	rc = vfs_rename_path(old_path, new_path);
 	if (rc != EOK) {
+		/*
+		 * Note that ISO C leaves the value of errno undefined,
+		 * whereas according to UN*X standards, it is set.
+		 */
 		errno = rc;
 		return -1;
@@ -96,4 +106,8 @@
 	rc = vfs_unlink_path(path);
 	if (rc != EOK) {
+		/*
+		 * Note that ISO C leaves the value of errno undefined,
+		 * whereas according to UN*X standards, it is set.
+		 */
 		errno = rc;
 		return -1;
@@ -101,4 +115,48 @@
 
 	return 0;
+}
+
+/** Create a temporary file.
+ *
+ * @return Open stream descriptor or @c NULL on error. In that case
+ *         errno is set (UN*X). Note that ISO C leaves the value of errno
+ *         undefined.
+ */
+FILE *tmpfile(void)
+{
+	int file;
+	FILE *stream;
+
+	file = __tmpfile();
+	if (file < 0) {
+		printf("file is < 0\n");
+		errno = EEXIST;
+		return NULL;
+	}
+
+	stream = fdopen(file, "w+");
+	if (stream == NULL) {
+		printf("stream = NULL\n");
+		vfs_put(file);
+		errno = EACCES;
+		return NULL;
+	}
+
+	printf("returning stream\n");
+	return stream;
+}
+
+/** Create name for a temporary file.
+ *
+ * @param s Pointer to array of at least L_tmpnam bytes or @c NULL.
+ * @return The pointer @a s or pointer to internal static buffer on success,
+ *         @c NULL on error.
+ */
+char *tmpnam(char *s)
+{
+	char *p;
+
+	p = (s != NULL) ? s : tmpnam_buf;
+	return __tmpnam(p);
 }
 
@@ -115,4 +173,5 @@
 }
 
+
 /** @}
  */
Index: uspace/lib/c/generic/tmpfile.c
===================================================================
--- uspace/lib/c/generic/tmpfile.c	(revision 4e6a610ce2ce4852d4b90413ede7ea606cc91eaa)
+++ uspace/lib/c/generic/tmpfile.c	(revision 4e6a610ce2ce4852d4b90413ede7ea606cc91eaa)
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2018 Jiri Svoboda
+ * 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 libc
+ * @{
+ */
+/** @file Temporary files
+ */
+
+#include <errno.h>
+#include <fibril_synch.h>
+#include <stdio.h>
+#include <str.h>
+#include <tmpfile.h>
+#include <vfs/vfs.h>
+
+static size_t tmpfile_cnt = 0;
+static FIBRIL_MUTEX_INITIALIZE(tmpfile_lock);
+
+/** Create and open file suitable as temporary file based on template.
+ *
+ * This is designed to allow creating temporary files compatible with POSIX
+ * mk(s)temp and tempnam, as well as for the use of ISO C tmpfile, tmpnam.
+ *
+ * @param templ
+ * @param create If @c false, only construct file name
+ *
+ * @return If @a create is true, open file descriptor on success (and
+ *         @a *templ is filled in with actual file name),
+ *         if @a create is false, zero on success. -1 on failure.
+ */
+int __tmpfile_templ(char *templ, bool create)
+{
+	size_t tsize;
+	char *p;
+	int file;
+	errno_t rc;
+
+	tsize = str_size(templ);
+	if (tsize < 6)
+		return -1;
+
+	p = templ + tsize - 6;
+	if (str_cmp(p, "XXXXXX") != 0)
+		return -1;
+
+	fibril_mutex_lock(&tmpfile_lock);
+
+	while (tmpfile_cnt < 1000000) {
+		snprintf(p, 6 + 1, "%06zu", tmpfile_cnt);
+		if (create) {
+			/* Try creating file */
+			rc = vfs_lookup(templ, WALK_MUST_CREATE |
+			    WALK_REGULAR, &file);
+			if (rc == EOK) {
+				rc = vfs_open(file, MODE_READ | MODE_WRITE);
+				if (rc == EOK) {
+					++tmpfile_cnt;
+					fibril_mutex_unlock(&tmpfile_lock);
+					return file;
+				}
+
+				vfs_put(file);
+			}
+		} else {
+			/* Test if file exists */
+			rc = vfs_lookup(templ, 0, &file);
+			if (rc != EOK) {
+				++tmpfile_cnt;
+				fibril_mutex_unlock(&tmpfile_lock);
+				return 0;
+			}
+
+			vfs_put(file);
+		}
+
+		++tmpfile_cnt;
+	}
+
+	fibril_mutex_unlock(&tmpfile_lock);
+	return -1;
+}
+
+/** Create and open temporary (unnamed) file.
+ *
+ * @return Open file descriptor on success, -1 on failure.
+ */
+int __tmpfile(void)
+{
+	int file;
+	char namebuf[L_tmpnam];
+
+	str_cpy(namebuf, L_tmpnam, "/tmp/tmp.XXXXXX");
+
+	file = __tmpfile_templ(namebuf, true);
+	if (file < 0)
+		return -1;
+
+	(void) vfs_unlink_path(namebuf);
+	return file;
+}
+
+/** Construct temporary file name.
+ *
+ * @param namebuf Buffer that can hold at least L_tmpnam bytes
+ * @return @a namebuf on success, @c NULL on failure
+ */
+char *__tmpnam(char *namebuf)
+{
+	int rc;
+
+	str_cpy(namebuf, L_tmpnam, "/tmp/tmp.XXXXXX");
+
+	rc = __tmpfile_templ(namebuf, false);
+	if (rc < 0)
+		return NULL;
+
+	return namebuf;
+}
+
+/** @}
+ */
Index: uspace/lib/c/include/stdio.h
===================================================================
--- uspace/lib/c/include/stdio.h	(revision fb0ec570bdde8224b2b38d270815b990dbef9225)
+++ uspace/lib/c/include/stdio.h	(revision 4e6a610ce2ce4852d4b90413ede7ea606cc91eaa)
@@ -40,30 +40,8 @@
 #include <stdarg.h>
 #include <io/verify.h>
+#include <_bits/NULL.h>
 #include <_bits/size_t.h>
 #include <_bits/wchar_t.h>
 #include <_bits/wint_t.h>
-
-#define EOF  (-1)
-
-#ifndef SEEK_SET
-#define SEEK_SET  0
-#endif
-
-#ifndef SEEK_CUR
-#define SEEK_CUR  1
-#endif
-
-#ifndef SEEK_END
-#define SEEK_END  2
-#endif
-
-/** Default size for stream I/O buffers */
-#define BUFSIZ  4096
-
-/** Max number of files that is guaranteed to be able to open at the same time */
-#define FOPEN_MAX VFS_MAX_OPEN_FILES
-
-/** Recommended size of fixed-size array for holding file names. */
-#define FILENAME_MAX 4096
 
 /** Forward declaration */
@@ -75,4 +53,39 @@
 	off64_t pos;
 } fpos_t;
+
+#ifndef _HELENOS_SOURCE
+#define _IONBF 0
+#define _IOLBF 1
+#define _IOFBF 2
+#endif
+
+/** Default size for stream I/O buffers */
+#define BUFSIZ  4096
+
+#define EOF  (-1)
+
+/** Max number of files that is guaranteed to be able to open at the same time */
+#define FOPEN_MAX VFS_MAX_OPEN_FILES
+
+/** Recommended size of fixed-size array for holding file names. */
+#define FILENAME_MAX 4096
+
+/** Length of "/tmp/tmp.XXXXXX" + 1 */
+#define L_tmpnam 16
+
+#ifndef SEEK_SET
+#define SEEK_SET  0
+#endif
+
+#ifndef SEEK_CUR
+#define SEEK_CUR  1
+#endif
+
+#ifndef SEEK_END
+#define SEEK_END  2
+#endif
+
+/** Minimum number of unique temporary file names */
+#define TMP_MAX 1000000
 
 extern FILE *stdin;
@@ -157,13 +170,9 @@
 
 /* Misc file functions */
+extern int remove(const char *);
 extern int rename(const char *, const char *);
-extern int remove(const char *);
-
-#ifndef _HELENOS_SOURCE
-#define _IONBF 0
-#define _IOLBF 1
-#define _IOFBF 2
-
-#endif
+
+extern FILE *tmpfile(void);
+extern char *tmpnam(char *s) __attribute__((deprecated));
 
 #ifdef _HELENOS_SOURCE
Index: uspace/lib/c/include/tmpfile.h
===================================================================
--- uspace/lib/c/include/tmpfile.h	(revision 4e6a610ce2ce4852d4b90413ede7ea606cc91eaa)
+++ uspace/lib/c/include/tmpfile.h	(revision 4e6a610ce2ce4852d4b90413ede7ea606cc91eaa)
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2018 Jiri Svoboda
+ * 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.
+ */
+
+#ifndef LIBC_TMPFILE_H_
+#define LIBC_TMPFILE_H_
+
+#include <stdbool.h>
+
+extern int __tmpfile_templ(char *, bool);
+extern int __tmpfile(void);
+extern char *__tmpnam(char *);
+
+#endif
Index: uspace/lib/c/test/main.c
===================================================================
--- uspace/lib/c/test/main.c	(revision fb0ec570bdde8224b2b38d270815b990dbef9225)
+++ uspace/lib/c/test/main.c	(revision 4e6a610ce2ce4852d4b90413ede7ea606cc91eaa)
@@ -38,4 +38,5 @@
 PCUT_IMPORT(scanf);
 PCUT_IMPORT(sprintf);
+PCUT_IMPORT(stdio);
 PCUT_IMPORT(stdlib);
 PCUT_IMPORT(str);
Index: uspace/lib/c/test/stdio.c
===================================================================
--- uspace/lib/c/test/stdio.c	(revision fb0ec570bdde8224b2b38d270815b990dbef9225)
+++ uspace/lib/c/test/stdio.c	(revision 4e6a610ce2ce4852d4b90413ede7ea606cc91eaa)
@@ -38,8 +38,145 @@
 #include <pcut/pcut.h>
 #include <stdio.h>
+#include <str.h>
+#include <tmpfile.h>
+#include <vfs/vfs.h>
 
 PCUT_INIT;
 
 PCUT_TEST_SUITE(stdio);
+
+/** remove function */
+PCUT_TEST(remove)
+{
+	char buf[L_tmpnam];
+	char *p;
+	FILE *f;
+	int rc;
+
+	/* Generate unique file name */
+	p = tmpnam(buf);
+	PCUT_ASSERT_NOT_NULL(p);
+
+	/* Removing it should fail */
+	rc = remove(buf);
+	PCUT_ASSERT_TRUE(rc != 0);
+
+	f = fopen(buf, "w");
+	PCUT_ASSERT_NOT_NULL(f);
+	fclose(f);
+
+	/* Remove for the first time */
+	rc = remove(buf);
+	PCUT_ASSERT_INT_EQUALS(0, rc);
+
+	/* Should fail the second time */
+	rc = remove(buf);
+	PCUT_ASSERT_TRUE(rc != 0);
+}
+
+/** rename function */
+PCUT_TEST(rename)
+{
+	char buf1[L_tmpnam];
+	char buf2[L_tmpnam];
+	char *p;
+	FILE *f;
+	int rc;
+
+	/* Generate first unique file name */
+	p = tmpnam(buf1);
+	PCUT_ASSERT_NOT_NULL(p);
+
+	/* Generate second unique file name */
+	p = tmpnam(buf2);
+	PCUT_ASSERT_NOT_NULL(p);
+
+	f = fopen(buf1, "w");
+	PCUT_ASSERT_NOT_NULL(f);
+	fclose(f);
+
+	/* Rename to the second name */
+	rc = rename(buf1, buf2);
+	PCUT_ASSERT_INT_EQUALS(0, rc);
+
+	/* First name should no longer exist */
+	rc = remove(buf1);
+	PCUT_ASSERT_TRUE(rc != 0);
+
+	/* Second can be removed */
+	rc = remove(buf2);
+	PCUT_ASSERT_INT_EQUALS(0, rc);
+}
+
+/** tmpfile function */
+PCUT_TEST(tmpfile)
+{
+	FILE *f;
+	char c;
+	size_t n;
+
+	f = tmpfile();
+	PCUT_ASSERT_NOT_NULL(f);
+
+	c = 'x';
+	n = fwrite(&c, sizeof(c), 1, f);
+	PCUT_ASSERT_INT_EQUALS(1, n);
+
+	rewind(f);
+	c = '\0';
+	n = fread(&c, sizeof(c), 1, f);
+	PCUT_ASSERT_INT_EQUALS(1, n);
+	PCUT_ASSERT_INT_EQUALS('x', c);
+
+	fclose(f);
+}
+
+/** tmpnam function with buffer argument */
+PCUT_TEST(tmpnam_buf)
+{
+	char buf[L_tmpnam];
+	char *p;
+	FILE *f;
+
+	p = tmpnam(buf);
+	PCUT_ASSERT_NOT_NULL(p);
+
+	f = fopen(p, "w+");
+	PCUT_ASSERT_NOT_NULL(f);
+	(void) remove(p);
+	fclose(f);
+}
+
+/** tmpnam function called twice */
+PCUT_TEST(tmpnam_twice)
+{
+	char buf1[L_tmpnam];
+	char buf2[L_tmpnam];
+	char *p;
+
+	p = tmpnam(buf1);
+	PCUT_ASSERT_NOT_NULL(p);
+
+	p = tmpnam(buf2);
+	PCUT_ASSERT_NOT_NULL(p);
+
+	/* We must get two distinct names */
+	PCUT_ASSERT_TRUE(str_cmp(buf1, buf2) != 0);
+}
+
+/** tmpnam function with NULL argument */
+PCUT_TEST(tmpnam_null)
+{
+	char *p;
+	FILE *f;
+
+	p = tmpnam(NULL);
+	PCUT_ASSERT_NOT_NULL(p);
+
+	f = fopen(p, "w+");
+	PCUT_ASSERT_NOT_NULL(f);
+	(void) remove(p);
+	fclose(f);
+}
 
 /** fgetpos and fsetpos functions */
@@ -50,9 +187,6 @@
 	FILE *f;
 
-	// XXX Use tmpfile() when it is available
-	f = fopen("/tmp/fgpsp.tmp", "w+");
-	PCUT_ASSERT_NOT_NULL(f);
-	rc = remove("/tmp/fgpsp.tmp");
-	PCUT_ASSERT_INT_EQUALS(0, rc);
+	f = tmpfile();
+	PCUT_ASSERT_NOT_NULL(f);
 
 	rc = fputs("abc", f);
Index: uspace/lib/posix/Makefile
===================================================================
--- uspace/lib/posix/Makefile	(revision fb0ec570bdde8224b2b38d270815b990dbef9225)
+++ uspace/lib/posix/Makefile	(revision 4e6a610ce2ce4852d4b90413ede7ea606cc91eaa)
@@ -82,5 +82,9 @@
 TEST_SOURCES = \
 	test/main.c \
-	test/scanf.c
+	test/stdio.c \
+	test/stdlib.c \
+	test/unistd.c
+
+EXTRA_TEST_CFLAGS = -Wno-deprecated-declarations
 
 EXPORT_CPPFLAGS = \
Index: uspace/lib/posix/include/posix/stdio.h
===================================================================
--- uspace/lib/posix/include/posix/stdio.h	(revision fb0ec570bdde8224b2b38d270815b990dbef9225)
+++ uspace/lib/posix/include/posix/stdio.h	(revision 4e6a610ce2ce4852d4b90413ede7ea606cc91eaa)
@@ -48,4 +48,6 @@
 extern int fileno(FILE *);
 
+#define P_tmpdir "/tmp"
+
 /* Identifying the Terminal */
 #undef L_ctermid
@@ -77,9 +79,5 @@
 
 /* Temporary Files */
-#undef L_tmpnam
-#define L_tmpnam PATH_MAX
-extern char *tmpnam(char *s);
 extern char *tempnam(const char *dir, const char *pfx);
-extern FILE *tmpfile(void);
 
 #endif /* POSIX_STDIO_H_ */
Index: uspace/lib/posix/include/posix/stdlib.h
===================================================================
--- uspace/lib/posix/include/posix/stdlib.h	(revision fb0ec570bdde8224b2b38d270815b990dbef9225)
+++ uspace/lib/posix/include/posix/stdlib.h	(revision 4e6a610ce2ce4852d4b90413ede7ea606cc91eaa)
@@ -58,5 +58,5 @@
 
 /* Legacy Declarations */
-extern char *mktemp(char *tmpl);
+extern char *mktemp(char *tmpl) __attribute__((deprecated));
 extern int bsd_getloadavg(double loadavg[], int nelem);
 
Index: uspace/lib/posix/src/stdio.c
===================================================================
--- uspace/lib/posix/src/stdio.c	(revision fb0ec570bdde8224b2b38d270815b990dbef9225)
+++ uspace/lib/posix/src/stdio.c	(revision 4e6a610ce2ce4852d4b90413ede7ea606cc91eaa)
@@ -2,4 +2,5 @@
  * Copyright (c) 2011 Jiri Zarevucky
  * Copyright (c) 2011 Petr Koupy
+ * Copyright (c) 2018 Jiri Svoboda
  * All rights reserved.
  *
@@ -38,9 +39,12 @@
 
 #include <assert.h>
-
 #include <errno.h>
-
+#include <stdbool.h>
+#include <tmpfile.h>
+
+#include "posix/fcntl.h"
 #include "posix/stdlib.h"
 #include "posix/string.h"
+#include "posix/sys/stat.h"
 #include "posix/sys/types.h"
 #include "posix/unistd.h"
@@ -353,32 +357,38 @@
 }
 
-/**
- * Get a unique temporary file name (obsolete).
- *
- * @param s Buffer for the file name. Must be at least L_tmpnam bytes long.
- * @return The value of s on success, NULL on failure.
- */
-char *tmpnam(char *s)
-{
-	assert(L_tmpnam >= strlen("/tmp/tnXXXXXX"));
-
-	static char buffer[L_tmpnam + 1];
-	if (s == NULL) {
-		s = buffer;
-	}
-
-	strcpy(s, "/tmp/tnXXXXXX");
-	mktemp(s);
-
-	if (*s == '\0') {
-		/* Errno set by mktemp(). */
-		return NULL;
-	}
-
-	return s;
-}
-
-/**
- * Get an unique temporary file name with additional constraints (obsolete).
+/** Determine if directory is an 'appropriate' temporary directory.
+ *
+ * @param dir Directory path
+ * @return @c true iff directory is appropriate.
+ */
+static bool is_appropriate_tmpdir(const char *dir)
+{
+	struct stat sbuf;
+
+	/* Must not be NULL */
+	if (dir == NULL)
+		return false;
+
+	/* Must not be empty */
+	if (dir[0] == '\0')
+		return false;
+
+	if (stat(dir, &sbuf) != 0)
+		return false;
+
+	/* Must be a directory */
+	if ((sbuf.st_mode & S_IFMT) != S_IFDIR)
+		return false;
+
+	/* Must be writable */
+	if (access(dir, W_OK) != 0)
+		return false;
+
+	return true;
+}
+
+/** Construct unique file name.
+ *
+ * Never use this function.
  *
  * @param dir Path to directory, where the file should be created.
@@ -388,77 +398,34 @@
 char *tempnam(const char *dir, const char *pfx)
 {
-	/* Sequence number of the filename. */
-	static int seq = 0;
-
-	size_t dir_len = strlen(dir);
-	if (dir[dir_len - 1] == '/') {
-		dir_len--;
-	}
-
-	size_t pfx_len = strlen(pfx);
-	if (pfx_len > 5) {
-		pfx_len = 5;
-	}
-
-	char *result = malloc(dir_len + /* slash*/ 1 +
-	    pfx_len + /* three-digit seq */ 3 + /* .tmp */ 4 + /* nul */ 1);
-
-	if (result == NULL) {
-		errno = ENOMEM;
+	const char *dpref;
+	char *d;
+	char *buf;
+	int rc;
+
+	d = getenv("TMPDIR");
+	if (is_appropriate_tmpdir(d))
+		dpref = d;
+	else if (is_appropriate_tmpdir(dir))
+		dpref = dir;
+	else if (is_appropriate_tmpdir(P_tmpdir))
+		dpref = P_tmpdir;
+	else
+		dpref = "/";
+
+	if (dpref[strlen(dpref) - 1] != '/')
+		rc = asprintf(&buf, "%s/%sXXXXXX", dpref, pfx);
+	else
+		rc = asprintf(&buf, "%s%sXXXXXX", dpref, pfx);
+
+	if (rc < 0)
+		return NULL;
+
+	rc = __tmpfile_templ(buf, false);
+	if (rc != 0) {
+		free(buf);
 		return NULL;
 	}
 
-	char *res_ptr = result;
-	strncpy(res_ptr, dir, dir_len);
-	res_ptr += dir_len;
-	strncpy(res_ptr, pfx, pfx_len);
-	res_ptr += pfx_len;
-
-	for (; seq < 1000; ++seq) {
-		snprintf(res_ptr, 8, "%03d.tmp", seq);
-
-		int orig_errno = errno;
-		errno = EOK;
-		/* Check if the file exists. */
-		if (access(result, F_OK) == -1) {
-			if (errno == ENOENT) {
-				errno = orig_errno;
-				break;
-			} else {
-				/* errno set by access() */
-				return NULL;
-			}
-		}
-	}
-
-	if (seq == 1000) {
-		free(result);
-		errno = EINVAL;
-		return NULL;
-	}
-
-	return result;
-}
-
-/**
- * Create and open an unique temporary file.
- * The file is automatically removed when the stream is closed.
- *
- * @param dir Path to directory, where the file should be created.
- * @param pfx Optional prefix up to 5 characters long.
- * @return Newly allocated unique path for temporary file. NULL on failure.
- */
-FILE *tmpfile(void)
-{
-	char filename[] = "/tmp/tfXXXXXX";
-	int fd = mkstemp(filename);
-	if (fd == -1) {
-		/* errno set by mkstemp(). */
-		return NULL;
-	}
-
-	/* Unlink the created file, so that it's removed on close(). */
-	unlink(filename);
-	return fdopen(fd, "w+");
+	return buf;
 }
 
Index: uspace/lib/posix/src/stdlib.c
===================================================================
--- uspace/lib/posix/src/stdlib.c	(revision fb0ec570bdde8224b2b38d270815b990dbef9225)
+++ uspace/lib/posix/src/stdlib.c	(revision 4e6a610ce2ce4852d4b90413ede7ea606cc91eaa)
@@ -38,4 +38,5 @@
 
 #include <errno.h>
+#include <tmpfile.h>
 
 #include "posix/fcntl.h"
@@ -163,23 +164,26 @@
 int mkstemp(char *tmpl)
 {
-	int fd = -1;
-
-	char *tptr = tmpl + strlen(tmpl) - 6;
-
-	while (fd < 0) {
-		if (*mktemp(tmpl) == '\0') {
-			/* Errno set by mktemp(). */
-			return -1;
-		}
-
-		fd = open(tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
-
-		if (fd == -1) {
-			/* Restore template to it's original state. */
-			snprintf(tptr, 7, "XXXXXX");
-		}
-	}
-
-	return fd;
+	int tmpl_len;
+	int file;
+
+	tmpl_len = strlen(tmpl);
+	if (tmpl_len < 6) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	char *tptr = tmpl + tmpl_len - 6;
+	if (strcmp(tptr, "XXXXXX") != 0) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	file = __tmpfile_templ(tmpl, true);
+	if (file < 0) {
+		errno = EIO; // XXX could be more specific
+		return -1;
+	}
+
+	return file;
 }
 
@@ -194,5 +198,8 @@
 char *mktemp(char *tmpl)
 {
-	int tmpl_len = strlen(tmpl);
+	int tmpl_len;
+	int rc;
+
+	tmpl_len = strlen(tmpl);
 	if (tmpl_len < 6) {
 		errno = EINVAL;
@@ -208,26 +215,7 @@
 	}
 
-	static int seq = 0;
-
-	for (; seq < 1000000; ++seq) {
-		snprintf(tptr, 7, "%06d", seq);
-
-		int orig_errno = errno;
-		errno = 0;
-		/* Check if the file exists. */
-		if (access(tmpl, F_OK) == -1) {
-			if (errno == ENOENT) {
-				errno = orig_errno;
-				break;
-			} else {
-				/* errno set by access() */
-				*tmpl = '\0';
-				return tmpl;
-			}
-		}
-	}
-
-	if (seq == 10000000) {
-		errno = EEXIST;
+	rc = __tmpfile_templ(tmpl, false);
+	if (rc != 0) {
+		errno = EIO; // XXX could be more specific
 		*tmpl = '\0';
 		return tmpl;
Index: uspace/lib/posix/src/unistd.c
===================================================================
--- uspace/lib/posix/src/unistd.c	(revision fb0ec570bdde8224b2b38d270815b990dbef9225)
+++ uspace/lib/posix/src/unistd.c	(revision 4e6a610ce2ce4852d4b90413ede7ea606cc91eaa)
@@ -39,5 +39,7 @@
 #include <errno.h>
 
+#include "posix/dirent.h"
 #include "posix/string.h"
+#include "posix/sys/types.h"
 #include "posix/fcntl.h"
 
@@ -368,8 +370,14 @@
 		 */
 		int fd = open(path, O_RDONLY);
-		if (fd < 0)
-			return -1;
-		close(fd);
-		return 0;
+		if (fd >= 0) {
+			close(fd);
+			return 0;
+		}
+		DIR *dir = opendir(path);
+		if (dir != NULL) {
+			closedir(dir);
+			return 0;
+		}
+		return -1;
 	} else {
 		/* Invalid amode argument. */
Index: uspace/lib/posix/test/main.c
===================================================================
--- uspace/lib/posix/test/main.c	(revision fb0ec570bdde8224b2b38d270815b990dbef9225)
+++ uspace/lib/posix/test/main.c	(revision 4e6a610ce2ce4852d4b90413ede7ea606cc91eaa)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2014 Vojtech Horky
+ * Copyright (c) 2018 Jiri Svoboda
  * All rights reserved.
  *
@@ -31,5 +31,7 @@
 PCUT_INIT;
 
-PCUT_IMPORT(scanf);
+PCUT_IMPORT(stdio);
+PCUT_IMPORT(stdlib);
+PCUT_IMPORT(unistd);
 
 PCUT_MAIN();
Index: uspace/lib/posix/test/scanf.c
===================================================================
--- uspace/lib/posix/test/scanf.c	(revision fb0ec570bdde8224b2b38d270815b990dbef9225)
+++ 	(revision )
@@ -1,185 +1,0 @@
-/*
- * Copyright (c) 2014 Vojtech Horky
- * 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.
- */
-
-
-
-#include <errno.h>
-
-#include "posix/stdio.h"
-
-#include <pcut/pcut.h>
-
-#define EPSILON 0.000001
-
-PCUT_INIT;
-
-PCUT_TEST_SUITE(scanf);
-
-
-#ifndef UARCH_sparc64
-
-/*
- * We need some floating point functions for scanf() imlementation
- * that are not yet available for SPARC-64.
- */
-
-PCUT_TEST(int_decimal)
-{
-	int number;
-	int rc = sscanf("4242", "%d", &number);
-	PCUT_ASSERT_INT_EQUALS(1, rc);
-	PCUT_ASSERT_INT_EQUALS(4242, number);
-}
-
-PCUT_TEST(int_negative_decimal)
-{
-	int number;
-	int rc = sscanf("-53", "%d", &number);
-	PCUT_ASSERT_INT_EQUALS(1, rc);
-	PCUT_ASSERT_INT_EQUALS(-53, number);
-}
-
-/*
- * The following tests were copied from stdio/scanf.c where they were
- * commented-out. We ought to convert them to more independent tests
- * eventually.
- */
-
-PCUT_TEST(int_misc)
-{
-	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;
-
-	int rc = 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);
-
-	PCUT_ASSERT_INT_EQUALS(10, rc);
-
-	PCUT_ASSERT_INT_EQUALS(-12, shh);
-	PCUT_ASSERT_INT_EQUALS(1, uhh);
-	PCUT_ASSERT_INT_EQUALS(314, sh);
-	PCUT_ASSERT_INT_EQUALS(987, uh);
-	PCUT_ASSERT_INT_EQUALS(65, udef);
-	PCUT_ASSERT_INT_EQUALS(28, sdef);
-	PCUT_ASSERT_INT_EQUALS(0765, ul);
-	PCUT_ASSERT_INT_EQUALS(0x77, ull);
-	PCUT_ASSERT_INT_EQUALS(0xABCDEF88, (long long) (uintptr_t) p);
-	PCUT_ASSERT_INT_EQUALS(-99, sl);
-	PCUT_ASSERT_INT_EQUALS(884, sll);
-}
-
-PCUT_TEST(double_misc)
-{
-	float f;
-	double d;
-	long double ld;
-
-	int rc = sscanf(
-	    "\n \t\t1.0 -0x555.AP10 1234.5678e12",
-	    "%f %lf %Lf",
-	    &f, &d, &ld);
-
-	PCUT_ASSERT_INT_EQUALS(3, rc);
-
-	PCUT_ASSERT_DOUBLE_EQUALS(1.0, f, EPSILON);
-	PCUT_ASSERT_DOUBLE_EQUALS(-0x555.AP10, d, EPSILON);
-	PCUT_ASSERT_DOUBLE_EQUALS(1234.5678e12, ld, EPSILON);
-}
-
-PCUT_TEST(str_misc)
-{
-	char str[20];
-	char *pstr;
-
-	int rc = sscanf(
-	    "\n\n\thello world    \n",
-	    "%5s %ms",
-	    str, &pstr);
-
-	PCUT_ASSERT_INT_EQUALS(2, rc);
-
-	PCUT_ASSERT_STR_EQUALS("hello", str);
-	PCUT_ASSERT_STR_EQUALS("world", pstr);
-
-	free(pstr);
-}
-
-PCUT_TEST(str_matchers)
-{
-	char scanset[20];
-	char *pscanset;
-
-	int rc = sscanf(
-	    "\n\n\th-e-l-l-o world-]    \n",
-	    " %9[-eh-o] %m[^]-]",
-	    scanset, &pscanset);
-
-	PCUT_ASSERT_INT_EQUALS(2, rc);
-
-	PCUT_ASSERT_STR_EQUALS("h-e-l-l-o", scanset);
-	PCUT_ASSERT_STR_EQUALS("world", pscanset);
-
-	free(pscanset);
-}
-
-PCUT_TEST(char_misc)
-{
-	char seq[20];
-	char *pseq;
-
-	int rc = sscanf(
-	    "\n\n\thello world    \n",
-	    " %5c %mc",
-	    seq, &pseq);
-
-	PCUT_ASSERT_INT_EQUALS(2, rc);
-
-	/* Manually terminate the strings. */
-	seq[5] = 0;
-	pseq[1] = 0;
-
-	PCUT_ASSERT_STR_EQUALS("hello", seq);
-	PCUT_ASSERT_STR_EQUALS("w", pseq);
-
-	free(pseq);
-}
-
-#endif
-
-PCUT_EXPORT(scanf);
Index: uspace/lib/posix/test/stdio.c
===================================================================
--- uspace/lib/posix/test/stdio.c	(revision 4e6a610ce2ce4852d4b90413ede7ea606cc91eaa)
+++ uspace/lib/posix/test/stdio.c	(revision 4e6a610ce2ce4852d4b90413ede7ea606cc91eaa)
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2018 Jiri Svoboda
+ * 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.
+ */
+
+#include <pcut/pcut.h>
+#include <str.h>
+#include "posix/stdio.h"
+
+PCUT_INIT;
+
+PCUT_TEST_SUITE(stdio);
+
+/** tempnam function with directory argument not having trailing slash */
+PCUT_TEST(tempnam_no_slash)
+{
+	char *p;
+	FILE *f;
+
+	p = tempnam("/tmp", "tmp.");
+	PCUT_ASSERT_NOT_NULL(p);
+
+	PCUT_ASSERT_TRUE(str_lcmp(p, "/tmp/tmp.",
+	    str_length("/tmp/tmp.")) == 0);
+
+	f = fopen(p, "w+");
+	PCUT_ASSERT_NOT_NULL(f);
+
+	(void) remove(p);
+	fclose(f);
+}
+
+/** tempnam function with directory argument having trailing slash */
+PCUT_TEST(tempnam_with_slash)
+{
+	char *p;
+	FILE *f;
+
+	p = tempnam("/tmp/", "tmp.");
+	PCUT_ASSERT_NOT_NULL(p);
+
+	PCUT_ASSERT_TRUE(str_lcmp(p, "/tmp/tmp.",
+	    str_length("/tmp/tmp.")) == 0);
+
+	f = fopen(p, "w+");
+	PCUT_ASSERT_NOT_NULL(f);
+
+	(void) remove(p);
+	fclose(f);
+}
+
+/** tempnam function with NULL directory argument */
+PCUT_TEST(tempnam_no_dir)
+{
+	char *p;
+	FILE *f;
+
+	p = tempnam(NULL, "tmp.");
+	PCUT_ASSERT_NOT_NULL(p);
+
+	PCUT_ASSERT_TRUE(str_lcmp(p, P_tmpdir "/tmp.",
+	    str_length(P_tmpdir "/tmp.")) == 0);
+
+	f = fopen(p, "w+");
+	PCUT_ASSERT_NOT_NULL(f);
+
+	(void) remove(p);
+	fclose(f);
+}
+
+PCUT_EXPORT(stdio);
Index: uspace/lib/posix/test/stdlib.c
===================================================================
--- uspace/lib/posix/test/stdlib.c	(revision 4e6a610ce2ce4852d4b90413ede7ea606cc91eaa)
+++ uspace/lib/posix/test/stdlib.c	(revision 4e6a610ce2ce4852d4b90413ede7ea606cc91eaa)
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2018 Jiri Svoboda
+ * 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.
+ */
+
+#include <pcut/pcut.h>
+#include <str.h>
+#include "posix/fcntl.h"
+#include "posix/stdio.h"
+#include "posix/stdlib.h"
+#include "posix/unistd.h"
+
+PCUT_INIT;
+
+PCUT_TEST_SUITE(stdlib);
+
+#define MKSTEMP_TEMPL "/tmp/tmp.XXXXXX"
+#define MKTEMP_BAD_TEMPL "/tmp/tmp.XXXXX"
+#define MKTEMP_SHORT_TEMPL "XXXXX"
+
+/** mktemp function */
+PCUT_TEST(mktemp)
+{
+	int file;
+	char buf[sizeof(MKSTEMP_TEMPL)];
+	char *p;
+
+	str_cpy(buf, sizeof(buf), MKSTEMP_TEMPL);
+
+	p = mktemp(buf);
+	PCUT_ASSERT_TRUE(p == buf);
+	PCUT_ASSERT_TRUE(str_lcmp(p, MKSTEMP_TEMPL,
+	    str_length(MKSTEMP_TEMPL) - 6) == 0);
+
+	file = open(p, O_CREAT | O_EXCL | O_RDWR, 0600);
+	PCUT_ASSERT_TRUE(file >= 0);
+	close(file);
+
+	(void) unlink(p);
+}
+
+/** mktemp function called twice should return different names */
+PCUT_TEST(mktemp_twice)
+{
+	char buf1[sizeof(MKSTEMP_TEMPL)];
+	char buf2[sizeof(MKSTEMP_TEMPL)];
+	char *p;
+
+	str_cpy(buf1, sizeof(buf1), MKSTEMP_TEMPL);
+	str_cpy(buf2, sizeof(buf2), MKSTEMP_TEMPL);
+
+	p = mktemp(buf1);
+	PCUT_ASSERT_TRUE(p == buf1);
+	PCUT_ASSERT_TRUE(str_lcmp(p, MKSTEMP_TEMPL,
+	    str_length(MKSTEMP_TEMPL) - 6) == 0);
+
+	p = mktemp(buf2);
+	PCUT_ASSERT_TRUE(p == buf2);
+	PCUT_ASSERT_TRUE(str_lcmp(p, MKSTEMP_TEMPL,
+	    str_length(MKSTEMP_TEMPL) - 6) == 0);
+
+	PCUT_ASSERT_TRUE(str_cmp(buf1, buf2) != 0);
+}
+
+/** mktemp function with malformed template */
+PCUT_TEST(mktemp_bad_templ)
+{
+	char buf[sizeof(MKTEMP_BAD_TEMPL)];
+	char *p;
+
+	str_cpy(buf, sizeof(buf), MKTEMP_BAD_TEMPL);
+
+	p = mktemp(buf);
+	PCUT_ASSERT_TRUE(p == buf);
+	PCUT_ASSERT_TRUE(p[0] == '\0');
+}
+
+/** mktemp function with too short template */
+PCUT_TEST(mktemp_short_templ)
+{
+	char buf[sizeof(MKTEMP_SHORT_TEMPL)];
+	char *p;
+
+	str_cpy(buf, sizeof(buf), MKTEMP_SHORT_TEMPL);
+
+	p = mktemp(buf);
+	PCUT_ASSERT_TRUE(p == buf);
+	PCUT_ASSERT_TRUE(p[0] == '\0');
+}
+
+/** mkstemp function */
+PCUT_TEST(mkstemp)
+{
+	int file;
+	char buf[sizeof(MKSTEMP_TEMPL)];
+	ssize_t rc;
+	char c;
+
+	str_cpy(buf, sizeof(buf), MKSTEMP_TEMPL);
+
+	file = mkstemp(buf);
+	PCUT_ASSERT_TRUE(file >= 0);
+
+	(void) unlink(buf);
+
+	c = 'x';
+	rc = write(file, &c, sizeof(c));
+	PCUT_ASSERT_TRUE(rc == sizeof(c));
+
+	(void) lseek(file, 0, SEEK_SET);
+	c = '\0';
+	rc = read(file, &c, sizeof(c));
+	PCUT_ASSERT_TRUE(rc == sizeof(c));
+	PCUT_ASSERT_INT_EQUALS('x', c);
+
+	close(file);
+}
+
+PCUT_EXPORT(stdlib);
Index: uspace/lib/posix/test/unistd.c
===================================================================
--- uspace/lib/posix/test/unistd.c	(revision 4e6a610ce2ce4852d4b90413ede7ea606cc91eaa)
+++ uspace/lib/posix/test/unistd.c	(revision 4e6a610ce2ce4852d4b90413ede7ea606cc91eaa)
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2018 Jiri Svoboda
+ * 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.
+ */
+
+#include <stdio.h>
+#include <pcut/pcut.h>
+#include "posix/fcntl.h"
+#include "posix/stdlib.h"
+#include "posix/unistd.h"
+
+PCUT_INIT;
+
+PCUT_TEST_SUITE(unistd);
+
+#define MKSTEMP_TEMPL "/tmp/tmp.XXXXXX"
+#define MKTEMP_BAD_TEMPL "/tmp/tmp.XXXXX"
+#define MKTEMP_SHORT_TEMPL "XXXXX"
+
+/** access function with nonexisting entry */
+PCUT_TEST(access_nonexist)
+{
+	char name[L_tmpnam];
+	char *p;
+	int rc;
+
+	p = tmpnam(name);
+	PCUT_ASSERT_NOT_NULL(p);
+
+	rc = access(name, F_OK);
+	PCUT_ASSERT_INT_EQUALS(-1, rc);
+}
+
+/** access function with file */
+PCUT_TEST(access_file)
+{
+	char name[L_tmpnam];
+	char *p;
+	int file;
+	int rc;
+
+	p = tmpnam(name);
+	PCUT_ASSERT_NOT_NULL(p);
+
+	file = open(name, O_CREAT | O_EXCL | O_RDWR, 0600);
+	PCUT_ASSERT_TRUE(file >= 0);
+
+	rc = access(name, F_OK);
+	PCUT_ASSERT_INT_EQUALS(0, rc);
+
+	(void) unlink(name);
+	close(file);
+}
+
+PCUT_EXPORT(unistd);
