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);
