Index: uspace/lib/c/Makefile
===================================================================
--- uspace/lib/c/Makefile	(revision 21d3201a912240b314cd578152eb84938b5b26d5)
+++ uspace/lib/c/Makefile	(revision 9c3038d4dbd35b5a7471af62fa120a4a1bcc39a8)
@@ -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 21d3201a912240b314cd578152eb84938b5b26d5)
+++ uspace/lib/c/generic/string.c	(revision 9c3038d4dbd35b5a7471af62fa120a4a1bcc39a8)
@@ -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 21d3201a912240b314cd578152eb84938b5b26d5)
+++ uspace/lib/c/include/string.h	(revision 9c3038d4dbd35b5a7471af62fa120a4a1bcc39a8)
@@ -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 21d3201a912240b314cd578152eb84938b5b26d5)
+++ uspace/lib/c/test/string.c	(revision 9c3038d4dbd35b5a7471af62fa120a4a1bcc39a8)
@@ -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);
