Index: uspace/lib/c/Makefile
===================================================================
--- uspace/lib/c/Makefile	(revision e199ab3efc73f51fb3708eeaa139d6cc533d1abc)
+++ uspace/lib/c/Makefile	(revision 68f11ddca33887bba2a17f8d05bf3a01b01a01a5)
@@ -34,5 +34,5 @@
 
 EXTRA_OUTPUT = $(START_FILES)
-EXTRA_CFLAGS += -fno-builtin
+EXTRA_CFLAGS += -fno-builtin -D_LIBC_SOURCE
 LIBRARY = libc
 SOVERSION = 0.0
Index: uspace/lib/c/generic/string.c
===================================================================
--- uspace/lib/c/generic/string.c	(revision e199ab3efc73f51fb3708eeaa139d6cc533d1abc)
+++ uspace/lib/c/generic/string.c	(revision 68f11ddca33887bba2a17f8d05bf3a01b01a01a5)
@@ -33,11 +33,9 @@
  */
 
-/* Prevent an error from being generated */
-#undef _HELENOS_SOURCE
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <str_error.h>
 #include <string.h>
-#define _HELENOS_SOURCE
-
-#include <stddef.h>
-#include <str_error.h>
 
 /** Copy string.
@@ -504,4 +502,71 @@
 }
 
+/** Return number of characters in string with length limit.
+ *
+ * @param s String
+ * @param maxlen Maximum number of characters to read
+ * @return Number of characters preceding the null character, at most @a maxlen.
+ */
+size_t strnlen(const char *s, size_t maxlen)
+{
+	size_t n;
+
+	n = 0;
+	while (n < maxlen && *s != '\0') {
+		++s;
+		++n;
+	}
+
+	return n;
+}
+
+/** Allocate a new duplicate of string.
+ *
+ * @param s String to duplicate
+ * @return New string or @c NULL on failure (in which case @c errno is set
+ *         to ENOMEM).
+ */
+char *strdup(const char *s)
+{
+	size_t sz;
+	char *dup;
+
+	sz = strlen(s);
+	dup = malloc(sz + 1);
+	if (dup == NULL) {
+		errno = ENOMEM;
+		return NULL;
+	}
+
+	strcpy(dup, s);
+	return dup;
+}
+
+/** Allocate a new duplicate of string with length limit.
+ *
+ * Creates a new duplicate of @a s. If @a s is longer than @a n characters,
+ * only @a n characters are copied and a null character is appended.
+ *
+ * @param s String to duplicate
+ * @param n Maximum number of characters to copy
+ * @return New string or @c NULL on failure (in which case @c errno is set
+ *         to ENOMEM).
+ */
+char *strndup(const char *s, size_t n)
+{
+	size_t sz;
+	char *dup;
+
+	sz = strnlen(s, n);
+	dup = malloc(sz + 1);
+	if (dup == NULL) {
+		errno = ENOMEM;
+		return NULL;
+	}
+
+	strcpy(dup, s);
+	return dup;
+}
+
 /** @}
  */
Index: uspace/lib/c/include/string.h
===================================================================
--- uspace/lib/c/include/string.h	(revision e199ab3efc73f51fb3708eeaa139d6cc533d1abc)
+++ uspace/lib/c/include/string.h	(revision 68f11ddca33887bba2a17f8d05bf3a01b01a01a5)
@@ -36,5 +36,6 @@
 #define LIBC_STRING_H_
 
-#if defined(_HELENOS_SOURCE) && !defined(_REALLY_WANT_STRING_H)
+#if defined(_HELENOS_SOURCE) && !defined(_REALLY_WANT_STRING_H) && \
+    !defined(_LIBC_SOURCE)
 #error Please use str.h and mem.h instead
 #endif
@@ -63,4 +64,10 @@
 extern size_t strlen(const char *);
 
+#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_LIBC_SOURCE)
+extern size_t strnlen(const char *, size_t);
+extern char *strdup(const char *);
+extern char *strndup(const char *, size_t);
+#endif
+
 #endif
 
Index: uspace/lib/c/test/string.c
===================================================================
--- uspace/lib/c/test/string.c	(revision e199ab3efc73f51fb3708eeaa139d6cc533d1abc)
+++ uspace/lib/c/test/string.c	(revision 68f11ddca33887bba2a17f8d05bf3a01b01a01a5)
@@ -722,3 +722,113 @@
 }
 
+/** strlen function with empty string and non-zero limit */
+PCUT_TEST(strnlen_empty_short)
+{
+	PCUT_ASSERT_INT_EQUALS(0, strnlen("", 1));
+}
+
+/** strlen function with empty string and zero limit */
+PCUT_TEST(strnlen_empty_eq)
+{
+	PCUT_ASSERT_INT_EQUALS(0, strnlen("", 0));
+}
+
+/** strlen function with non empty string below limit */
+PCUT_TEST(strnlen_nonempty_short)
+{
+	PCUT_ASSERT_INT_EQUALS(3, strnlen("abc", 5));
+}
+
+/** strlen function with non empty string just below limit */
+PCUT_TEST(strnlen_nonempty_just_short)
+{
+	PCUT_ASSERT_INT_EQUALS(3, strnlen("abc", 4));
+}
+
+/** strlen function with non empty string of length equal to limit */
+PCUT_TEST(strnlen_nonempty_eq)
+{
+	PCUT_ASSERT_INT_EQUALS(3, strnlen("abc", 3));
+}
+
+/** strlen function with non empty string of length above limit */
+PCUT_TEST(strnlen_nonempty_long)
+{
+	PCUT_ASSERT_INT_EQUALS(2, strnlen("abc", 2));
+}
+
+/** strdup function with empty string */
+PCUT_TEST(strdup_empty)
+{
+	char *d = strdup("");
+	PCUT_ASSERT_NOT_NULL(d);
+	PCUT_ASSERT_TRUE(d[0] == '\0');
+	free(d);
+}
+
+/** strdup function with non-empty string */
+PCUT_TEST(strdup_nonempty)
+{
+	char *d = strdup("abc");
+	PCUT_ASSERT_NOT_NULL(d);
+	PCUT_ASSERT_TRUE(d[0] == 'a');
+	PCUT_ASSERT_TRUE(d[1] == 'b');
+	PCUT_ASSERT_TRUE(d[2] == 'c');
+	PCUT_ASSERT_TRUE(d[3] == '\0');
+	free(d);
+}
+
+/** strndup function with empty string and non-zero limit */
+PCUT_TEST(strndup_empty_short)
+{
+	char *d = strndup("", 1);
+	PCUT_ASSERT_NOT_NULL(d);
+	PCUT_ASSERT_TRUE(d[0] == '\0');
+	free(d);
+}
+
+/** strndup function with empty string and zero limit */
+PCUT_TEST(strndup_empty_eq)
+{
+	char *d = strndup("", 0);
+	PCUT_ASSERT_NOT_NULL(d);
+	PCUT_ASSERT_TRUE(d[0] == '\0');
+	free(d);
+}
+
+/** strndup function with non-empty string of length below limit */
+PCUT_TEST(strndup_nonempty_short)
+{
+	char *d = strndup("abc", 5);
+	PCUT_ASSERT_NOT_NULL(d);
+	PCUT_ASSERT_TRUE(d[0] == 'a');
+	PCUT_ASSERT_TRUE(d[1] == 'b');
+	PCUT_ASSERT_TRUE(d[2] == 'c');
+	PCUT_ASSERT_TRUE(d[3] == '\0');
+	free(d);
+}
+
+/** strndup function with non-empty string of length equal to limit */
+PCUT_TEST(strndup_nonempty_eq)
+{
+	char *d = strndup("abc", 3);
+	PCUT_ASSERT_NOT_NULL(d);
+	PCUT_ASSERT_TRUE(d[0] == 'a');
+	PCUT_ASSERT_TRUE(d[1] == 'b');
+	PCUT_ASSERT_TRUE(d[2] == 'c');
+	PCUT_ASSERT_TRUE(d[3] == '\0');
+	free(d);
+}
+
+/** strndup function with non-empty string of length above limit */
+PCUT_TEST(strndup_nonempty_long)
+{
+	char *d = strndup("abc", 2);
+	PCUT_ASSERT_NOT_NULL(d);
+	PCUT_ASSERT_TRUE(d[0] == 'a');
+	PCUT_ASSERT_TRUE(d[1] == 'b');
+	PCUT_ASSERT_TRUE(d[2] == '\0');
+	free(d);
+}
+
 PCUT_EXPORT(string);
Index: uspace/lib/posix/Makefile
===================================================================
--- uspace/lib/posix/Makefile	(revision e199ab3efc73f51fb3708eeaa139d6cc533d1abc)
+++ uspace/lib/posix/Makefile	(revision 68f11ddca33887bba2a17f8d05bf3a01b01a01a5)
@@ -31,5 +31,5 @@
 LIBRARY = libposix
 
-EXTRA_CFLAGS = -Iinclude/posix
+EXTRA_CFLAGS = -Iinclude/posix -D_XOPEN_SOURCE
 
 EXPORT_FILES = \
Index: uspace/lib/posix/include/posix/string.h
===================================================================
--- uspace/lib/posix/include/posix/string.h	(revision e199ab3efc73f51fb3708eeaa139d6cc533d1abc)
+++ uspace/lib/posix/include/posix/string.h	(revision 68f11ddca33887bba2a17f8d05bf3a01b01a01a5)
@@ -59,6 +59,4 @@
 extern char *stpncpy(char *__restrict__ dest, const char *__restrict__ src, size_t n);
 extern void *memccpy(void *__restrict__ dest, const void *__restrict__ src, int c, size_t n);
-extern char *strdup(const char *s);
-extern char *strndup(const char *s, size_t n);
 
 /* Search Functions */
@@ -70,7 +68,4 @@
 /* Error Messages */
 extern int strerror_r(int errnum, char *buf, size_t bufsz);
-
-/* String Length */
-extern size_t strnlen(const char *s, size_t n);
 
 /* Signal Messages */
Index: uspace/lib/posix/src/string.c
===================================================================
--- uspace/lib/posix/src/string.c	(revision e199ab3efc73f51fb3708eeaa139d6cc533d1abc)
+++ uspace/lib/posix/src/string.c	(revision 68f11ddca33887bba2a17f8d05bf3a01b01a01a5)
@@ -135,38 +135,4 @@
 
 /**
- * Duplicate a string.
- *
- * @param s String to be duplicated.
- * @return Newly allocated copy of the string.
- */
-char *strdup(const char *s)
-{
-	return strndup(s, SIZE_MAX);
-}
-
-/**
- * Duplicate a specific number of bytes from a string.
- *
- * @param s String to be duplicated.
- * @param n Maximum length of the resulting string..
- * @return Newly allocated string copy of length at most n.
- */
-char *strndup(const char *s, size_t n)
-{
-	assert(s != NULL);
-
-	size_t len = strnlen(s, n);
-	char *dup = malloc(len + 1);
-	if (dup == NULL) {
-		return NULL;
-	}
-
-	memcpy(dup, s, len);
-	dup[len] = '\0';
-
-	return dup;
-}
-
-/**
  * Scan string for a first occurence of a character.
  *
@@ -225,25 +191,4 @@
 
 	return EOK;
-}
-
-/**
- * Get limited length of the string.
- *
- * @param s String which length shall be determined.
- * @param n Maximum number of bytes that can be examined to determine length.
- * @return The lower of either string length or n limit.
- */
-size_t strnlen(const char *s, size_t n)
-{
-	assert(s != NULL);
-
-	for (size_t sz = 0; sz < n; ++sz) {
-
-		if (s[sz] == '\0') {
-			return sz;
-		}
-	}
-
-	return n;
 }
 
