Index: uspace/lib/c/Makefile
===================================================================
--- uspace/lib/c/Makefile	(revision 7d7bc099a78595a8fbe782749779eb18f1d9053c)
+++ uspace/lib/c/Makefile	(revision 777832ee6e5de48216dba17868b414e69ad4542d)
@@ -194,4 +194,5 @@
 	test/qsort.c \
 	test/sprintf.c \
+	test/stdio.c \
 	test/stdlib.c \
 	test/str.c
Index: uspace/lib/c/generic/stdio.c
===================================================================
--- uspace/lib/c/generic/stdio.c	(revision 7d7bc099a78595a8fbe782749779eb18f1d9053c)
+++ uspace/lib/c/generic/stdio.c	(revision 777832ee6e5de48216dba17868b414e69ad4542d)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2017 Jiri Svoboda
+ * Copyright (c) 2018 Jiri Svoboda
  * All rights reserved.
  *
@@ -35,5 +35,43 @@
 #include <errno.h>
 #include <stdio.h>
+#include <str_error.h>
 #include <vfs/vfs.h>
+
+/** Get stream position.
+ *
+ * @param stream Stream
+ * @param pos Place to store position
+ *
+ * @return Zero on success, non-zero on failure
+ */
+int fgetpos(FILE *stream, fpos_t *pos)
+{
+	off64_t p;
+
+	p = ftell64(stream);
+	if (p < 0)
+		return -1;
+
+	pos->pos = p;
+	return 0;
+}
+
+/** Get stream position.
+ *
+ * @param stream Stream
+ * @param pos Position
+ *
+ * @return Zero on sucess, non-zero on failure
+ */
+int fsetpos(FILE *stream, const fpos_t *pos)
+{
+	int rc;
+
+	rc = fseek64(stream, pos->pos, SEEK_SET);
+	if (rc < 0)
+		return -1;
+
+	return 0;
+}
 
 /** Rename file or directory (C standard) */
@@ -65,4 +103,16 @@
 }
 
+/** Print error message and string representation of @c errno.
+ *
+ * @param s Error message
+ */
+void perror(const char *s)
+{
+	if (s != NULL && *s != '\0')
+		fprintf(stderr, "%s: %s\n", s, str_error(errno));
+	else
+		fprintf(stderr, "%s\n", str_error(errno));
+}
+
 /** @}
  */
Index: uspace/lib/c/include/stdio.h
===================================================================
--- uspace/lib/c/include/stdio.h	(revision 7d7bc099a78595a8fbe782749779eb18f1d9053c)
+++ uspace/lib/c/include/stdio.h	(revision 777832ee6e5de48216dba17868b414e69ad4542d)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2005 Martin Decky
+ * Copyright (c) 2018 Jiri Svoboda
  * All rights reserved.
  *
@@ -36,4 +37,5 @@
 #define LIBC_STDIO_H_
 
+#include <offset.h>
 #include <stdarg.h>
 #include <io/verify.h>
@@ -59,4 +61,7 @@
 #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
@@ -65,4 +70,9 @@
 struct _IO_FILE;
 typedef struct _IO_FILE FILE;
+
+/** File position */
+typedef struct {
+	off64_t pos;
+} fpos_t;
 
 extern FILE *stdin;
@@ -124,4 +134,7 @@
 extern size_t fwrite(const void *, size_t, size_t, FILE *);
 
+extern int fgetpos(FILE *, fpos_t *);
+extern int fsetpos(FILE *, const fpos_t *);
+
 extern int fseek(FILE *, long, int);
 extern void rewind(FILE *);
@@ -132,4 +145,6 @@
 extern int ferror(FILE *);
 extern void clearerr(FILE *);
+
+extern void perror(const char *);
 
 extern void setvbuf(FILE *, void *, int, size_t);
Index: uspace/lib/c/include/vfs/vfs.h
===================================================================
--- uspace/lib/c/include/vfs/vfs.h	(revision 7d7bc099a78595a8fbe782749779eb18f1d9053c)
+++ uspace/lib/c/include/vfs/vfs.h	(revision 777832ee6e5de48216dba17868b414e69ad4542d)
@@ -45,5 +45,5 @@
 #include <offset.h>
 
-#define MAX_OPEN_FILES	128
+#define VFS_MAX_OPEN_FILES	128
 
 enum vfs_change_state_type {
Index: uspace/lib/c/test/stdio.c
===================================================================
--- uspace/lib/c/test/stdio.c	(revision 777832ee6e5de48216dba17868b414e69ad4542d)
+++ uspace/lib/c/test/stdio.c	(revision 777832ee6e5de48216dba17868b414e69ad4542d)
@@ -0,0 +1,93 @@
+/*
+ * 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
+ * @brief Test stdio module
+ */
+
+#include <errno.h>
+#include <pcut/pcut.h>
+#include <stdio.h>
+
+PCUT_INIT;
+
+PCUT_TEST_SUITE(stdio);
+
+/** fgetpos and fsetpos functions */
+PCUT_TEST(fgetpos_setpos)
+{
+	fpos_t pos;
+	int rc;
+	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);
+
+	rc = fputs("abc", f);
+	PCUT_ASSERT_TRUE(rc >= 0);
+
+	rc = fgetpos(f, &pos);
+	PCUT_ASSERT_TRUE(rc >= 0);
+
+	rewind(f);
+
+	rc = fsetpos(f, &pos);
+	PCUT_ASSERT_TRUE(rc >= 0);
+
+	(void) fclose(f);
+}
+
+/** perror function with NULL as argument */
+PCUT_TEST(perror_null_msg)
+{
+	errno = EINVAL;
+	perror(NULL);
+}
+
+/** perror function with empty string as argument */
+PCUT_TEST(perror_empty_msg)
+{
+	errno = EINVAL;
+	perror("");
+}
+
+/** perror function with a message argument */
+PCUT_TEST(perror_msg)
+{
+	errno = EINVAL;
+	perror("This is a test");
+}
+
+PCUT_EXPORT(stdio);
Index: uspace/lib/posix/include/posix/stdio.h
===================================================================
--- uspace/lib/posix/include/posix/stdio.h	(revision 7d7bc099a78595a8fbe782749779eb18f1d9053c)
+++ uspace/lib/posix/include/posix/stdio.h	(revision 777832ee6e5de48216dba17868b414e69ad4542d)
@@ -59,14 +59,4 @@
     FILE *__restrict__ stream);
 
-/* Error Messages */
-extern void perror(const char *s);
-
-/* File Positioning */
-typedef struct {
-	off64_t offset;
-} fpos_t;
-
-extern int fsetpos(FILE *stream, const fpos_t *pos);
-extern int fgetpos(FILE *__restrict__ stream, fpos_t *__restrict__ pos);
 extern int fseeko(FILE *stream, off_t offset, int whence);
 extern off_t ftello(FILE *stream);
Index: uspace/lib/posix/src/internal/common.h
===================================================================
--- uspace/lib/posix/src/internal/common.h	(revision 7d7bc099a78595a8fbe782749779eb18f1d9053c)
+++ uspace/lib/posix/src/internal/common.h	(revision 777832ee6e5de48216dba17868b414e69ad4542d)
@@ -66,5 +66,5 @@
 }
 
-extern aoff64_t posix_pos[MAX_OPEN_FILES];
+extern aoff64_t posix_pos[VFS_MAX_OPEN_FILES];
 
 #endif /* LIBPOSIX_COMMON_H_ */
Index: uspace/lib/posix/src/stdio.c
===================================================================
--- uspace/lib/posix/src/stdio.c	(revision 7d7bc099a78595a8fbe782749779eb18f1d9053c)
+++ uspace/lib/posix/src/stdio.c	(revision 777832ee6e5de48216dba17868b414e69ad4542d)
@@ -169,46 +169,4 @@
 
 /**
- * Write error messages to standard error.
- *
- * @param s Error message.
- */
-void perror(const char *s)
-{
-	if (s == NULL || s[0] == '\0') {
-		fprintf(stderr, "%s\n", strerror(errno));
-	} else {
-		fprintf(stderr, "%s: %s\n", s, strerror(errno));
-	}
-}
-
-/** 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 fsetpos(FILE *stream, const fpos_t *pos)
-{
-	return fseek64(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 fgetpos(FILE *restrict stream, fpos_t *restrict pos)
-{
-	off64_t ret = ftell64(stream);
-	if (ret != -1) {
-		pos->offset = ret;
-		return 0;
-	} else {
-		return -1;
-	}
-}
-
-/**
  * Reposition a file-position indicator in a stream.
  *
Index: uspace/lib/posix/src/unistd.c
===================================================================
--- uspace/lib/posix/src/unistd.c	(revision 7d7bc099a78595a8fbe782749779eb18f1d9053c)
+++ uspace/lib/posix/src/unistd.c	(revision 777832ee6e5de48216dba17868b414e69ad4542d)
@@ -51,5 +51,5 @@
 
 // FIXME: replace with a hash table
-aoff64_t posix_pos[MAX_OPEN_FILES];
+aoff64_t posix_pos[VFS_MAX_OPEN_FILES];
 
 /* Array of environment variable strings (NAME=VALUE). */
Index: uspace/srv/vfs/vfs_file.c
===================================================================
--- uspace/srv/vfs/vfs_file.c	(revision 7d7bc099a78595a8fbe782749779eb18f1d9053c)
+++ uspace/srv/vfs/vfs_file.c	(revision 777832ee6e5de48216dba17868b414e69ad4542d)
@@ -71,10 +71,10 @@
 	fibril_mutex_lock(&vfs_data->lock);
 	if (!vfs_data->files) {
-		vfs_data->files = malloc(MAX_OPEN_FILES * sizeof(vfs_file_t *));
+		vfs_data->files = malloc(VFS_MAX_OPEN_FILES * sizeof(vfs_file_t *));
 		if (!vfs_data->files) {
 			fibril_mutex_unlock(&vfs_data->lock);
 			return false;
 		}
-		memset(vfs_data->files, 0, MAX_OPEN_FILES * sizeof(vfs_file_t *));
+		memset(vfs_data->files, 0, VFS_MAX_OPEN_FILES * sizeof(vfs_file_t *));
 	}
 	fibril_mutex_unlock(&vfs_data->lock);
@@ -90,5 +90,5 @@
 		return;
 
-	for (i = 0; i < MAX_OPEN_FILES; i++) {
+	for (i = 0; i < VFS_MAX_OPEN_FILES; i++) {
 		if (vfs_data->files[i])
 			(void) _vfs_fd_free(vfs_data, i);
@@ -199,5 +199,5 @@
 	unsigned int i;
 	if (desc)
-		i = MAX_OPEN_FILES - 1;
+		i = VFS_MAX_OPEN_FILES - 1;
 	else
 		i = 0;
@@ -233,5 +233,5 @@
 			i--;
 		} else {
-			if (i == MAX_OPEN_FILES - 1)
+			if (i == VFS_MAX_OPEN_FILES - 1)
 				break;
 
@@ -261,5 +261,5 @@
 static errno_t _vfs_fd_free_locked(vfs_client_data_t *vfs_data, int fd)
 {
-	if ((fd < 0) || (fd >= MAX_OPEN_FILES) || !vfs_data->files[fd]) {
+	if ((fd < 0) || (fd >= VFS_MAX_OPEN_FILES) || !vfs_data->files[fd]) {
 		return EBADF;
 	}
@@ -311,5 +311,5 @@
 
 	fibril_mutex_lock(&VFS_DATA->lock);
-	if ((fd < 0) || (fd >= MAX_OPEN_FILES)) {
+	if ((fd < 0) || (fd >= VFS_MAX_OPEN_FILES)) {
 		fibril_mutex_unlock(&VFS_DATA->lock);
 		return EBADF;
@@ -342,5 +342,5 @@
 
 	fibril_mutex_lock(&vfs_data->lock);
-	if ((fd >= 0) && (fd < MAX_OPEN_FILES)) {
+	if ((fd >= 0) && (fd < VFS_MAX_OPEN_FILES)) {
 		vfs_file_t *file = vfs_data->files[fd];
 		if (file != NULL) {
