Index: uspace/lib/c/generic/adt/list.c
===================================================================
--- uspace/lib/c/generic/adt/list.c	(revision 9854a8faee04ea815f8612666a6e4dac63db2748)
+++ uspace/lib/c/generic/adt/list.c	(revision cffa82aac31c77f5d26f954922753c58edfef5f7)
@@ -53,5 +53,5 @@
  *
  */
-int list_member(const link_t *link, const list_t *list)
+bool list_member(const link_t *link, const list_t *list)
 {
 	bool found = false;
@@ -98,7 +98,7 @@
  * @return		Number of items in the list.
  */
-unsigned int list_count(const list_t *list)
+unsigned long list_count(const list_t *list)
 {
-	unsigned int count = 0;
+	unsigned long count = 0;
 	
 	link_t *link = list_first(list);
Index: uspace/lib/c/generic/async.c
===================================================================
--- uspace/lib/c/generic/async.c	(revision 9854a8faee04ea815f8612666a6e4dac63db2748)
+++ uspace/lib/c/generic/async.c	(revision cffa82aac31c77f5d26f954922753c58edfef5f7)
@@ -77,5 +77,5 @@
  *   }
  *
- *   my_client_connection(icallid, *icall)
+ *   port_handler(icallid, *icall)
  *   {
  *     if (want_refuse) {
@@ -123,4 +123,7 @@
 	list_t exch_list;
 	
+	/** Session interface */
+	iface_t iface;
+	
 	/** Exchange management style */
 	exch_mgmt_t mgmt;
@@ -189,8 +192,8 @@
 	/** If reply was received. */
 	bool done;
-
+	
 	/** If the message / reply should be discarded on arrival. */
 	bool forget;
-
+	
 	/** If already destroyed. */
 	bool destroyed;
@@ -232,8 +235,7 @@
 	/** Identification of the opening call. */
 	ipc_callid_t callid;
+	
 	/** Call data of the opening call. */
 	ipc_call_t call;
-	/** Local argument or NULL if none. */
-	void *carg;
 	
 	/** Identification of the closing call. */
@@ -241,6 +243,40 @@
 	
 	/** Fibril function that will be used to handle the connection. */
-	async_client_conn_t cfibril;
+	async_port_handler_t handler;
+	
+	/** Client data */
+	void *data;
 } connection_t;
+
+/** Interface data */
+typedef struct {
+	ht_link_t link;
+	
+	/** Interface ID */
+	iface_t iface;
+	
+	/** Futex protecting the hash table */
+	futex_t futex;
+	
+	/** Interface ports */
+	hash_table_t port_hash_table;
+	
+	/** Next available port ID */
+	port_id_t port_id_avail;
+} interface_t;
+
+/* Port data */
+typedef struct {
+	ht_link_t link;
+	
+	/** Port ID */
+	port_id_t id;
+	
+	/** Port connection handler */
+	async_port_handler_t handler;
+	
+	/** Client data */
+	void *data;
+} port_t;
 
 /* Notification data */
@@ -264,5 +300,5 @@
 {
 	struct timeval tv = { 0, 0 };
-
+	
 	to->inlist = false;
 	to->occurred = false;
@@ -287,7 +323,5 @@
 static amsg_t *amsg_create(void)
 {
-	amsg_t *msg;
-
-	msg = malloc(sizeof(amsg_t));
+	amsg_t *msg = malloc(sizeof(amsg_t));
 	if (msg) {
 		msg->done = false;
@@ -298,5 +332,5 @@
 		awaiter_initialize(&msg->wdata);
 	}
-
+	
 	return msg;
 }
@@ -335,7 +369,8 @@
 }
 
-/** Default fibril function that gets called to handle new connection.
- *
- * This function is defined as a weak symbol - to be redefined in user code.
+/** Default fallback fibril function.
+ *
+ * This fallback fibril function gets called on incomming
+ * connections that do not have a specific handler defined.
  *
  * @param callid Hash of the incoming call.
@@ -344,5 +379,5 @@
  *
  */
-static void default_client_connection(ipc_callid_t callid, ipc_call_t *call,
+static void default_fallback_port_handler(ipc_callid_t callid, ipc_call_t *call,
     void *arg)
 {
@@ -350,18 +385,114 @@
 }
 
-static async_client_conn_t client_connection = default_client_connection;
+static async_port_handler_t fallback_port_handler =
+    default_fallback_port_handler;
+static void *fallback_port_data = NULL;
+
+static hash_table_t interface_hash_table;
+
+static size_t interface_key_hash(void *key)
+{
+	iface_t iface = *(iface_t *) key;
+	return iface;
+}
+
+static size_t interface_hash(const ht_link_t *item)
+{
+	interface_t *interface = hash_table_get_inst(item, interface_t, link);
+	return interface_key_hash(&interface->iface);
+}
+
+static bool interface_key_equal(void *key, const ht_link_t *item)
+{
+	iface_t iface = *(iface_t *) key;
+	interface_t *interface = hash_table_get_inst(item, interface_t, link);
+	return iface == interface->iface;
+}
+
+/** Operations for the port hash table. */
+static hash_table_ops_t interface_hash_table_ops = {
+	.hash = interface_hash,
+	.key_hash = interface_key_hash,
+	.key_equal = interface_key_equal,
+	.equal = NULL,
+	.remove_callback = NULL
+};
+
+static size_t port_key_hash(void *key)
+{
+	port_id_t port_id = *(port_id_t *) key;
+	return port_id;
+}
+
+static size_t port_hash(const ht_link_t *item)
+{
+	port_t *port = hash_table_get_inst(item, port_t, link);
+	return port_key_hash(&port->id);
+}
+
+static bool port_key_equal(void *key, const ht_link_t *item)
+{
+	port_id_t port_id = *(port_id_t *) key;
+	port_t *port = hash_table_get_inst(item, port_t, link);
+	return port_id == port->id;
+}
+
+/** Operations for the port hash table. */
+static hash_table_ops_t port_hash_table_ops = {
+	.hash = port_hash,
+	.key_hash = port_key_hash,
+	.key_equal = port_key_equal,
+	.equal = NULL,
+	.remove_callback = NULL
+};
+
+static interface_t *async_new_interface(iface_t iface)
+{
+	interface_t *interface =
+	    (interface_t *) malloc(sizeof(interface_t));
+	if (!interface)
+		return NULL;
+	
+	bool ret = hash_table_create(&interface->port_hash_table, 0, 0,
+	    &port_hash_table_ops);
+	if (!ret) {
+		free(interface);
+		return NULL;
+	}
+	
+	interface->iface = iface;
+	futex_initialize(&interface->futex, 1);
+	interface->port_id_avail = 0;
+	
+	hash_table_insert(&interface_hash_table, &interface->link);
+	
+	return interface;
+}
+
+static port_t *async_new_port(interface_t *interface,
+    async_port_handler_t handler, void *data)
+{
+	port_t *port = (port_t *) malloc(sizeof(port_t));
+	if (!port)
+		return NULL;
+	
+	futex_down(&interface->futex);
+	
+	port_id_t id = interface->port_id_avail;
+	interface->port_id_avail++;
+	
+	port->id = id;
+	port->handler = handler;
+	port->data = data;
+	
+	hash_table_insert(&interface->port_hash_table, &port->link);
+	
+	futex_up(&interface->futex);
+	
+	return port;
+}
+
 static size_t notification_handler_stksz = FIBRIL_DFLT_STK_SIZE;
 
-/** Setter for client_connection function pointer.
- *
- * @param conn Function that will implement a new connection fibril.
- *
- */
-void async_set_client_connection(async_client_conn_t conn)
-{
-	assert(client_connection == default_client_connection);
-	client_connection = conn;
-}
-
 /** Set the stack size for the notification handler notification fibrils.
  *
@@ -387,4 +518,46 @@
  */
 static FIBRIL_CONDVAR_INITIALIZE(avail_phone_cv);
+
+int async_create_port(iface_t iface, async_port_handler_t handler,
+    void *data, port_id_t *port_id)
+{
+	if ((iface & IFACE_MOD_MASK) == IFACE_MOD_CALLBACK)
+		return EINVAL;
+	
+	interface_t *interface;
+	
+	futex_down(&async_futex);
+	
+	ht_link_t *link = hash_table_find(&interface_hash_table, &iface);
+	if (link)
+		interface = hash_table_get_inst(link, interface_t, link);
+	else
+		interface = async_new_interface(iface);
+	
+	if (!interface) {
+		futex_up(&async_futex);
+		return ENOMEM;
+	}
+	
+	port_t *port = async_new_port(interface, handler, data);
+	if (!port) {
+		futex_up(&async_futex);
+		return ENOMEM;
+	}
+	
+	*port_id = port->id;
+	
+	futex_up(&async_futex);
+	
+	return EOK;
+}
+
+void async_set_fallback_port_handler(async_port_handler_t handler, void *data)
+{
+	assert(handler != NULL);
+	
+	fallback_port_handler = handler;
+	fallback_port_data = data;
+}
 
 static hash_table_t client_hash_table;
@@ -457,4 +630,258 @@
 	.remove_callback = NULL
 };
+
+static client_t *async_client_get(task_id_t client_id, bool create)
+{
+	client_t *client = NULL;
+	
+	futex_down(&async_futex);
+	ht_link_t *link = hash_table_find(&client_hash_table, &client_id);
+	if (link) {
+		client = hash_table_get_inst(link, client_t, link);
+		atomic_inc(&client->refcnt);
+	} else if (create) {
+		client = malloc(sizeof(client_t));
+		if (client) {
+			client->in_task_id = client_id;
+			client->data = async_client_data_create();
+			
+			atomic_set(&client->refcnt, 1);
+			hash_table_insert(&client_hash_table, &client->link);
+		}
+	}
+	
+	futex_up(&async_futex);
+	return client;
+}
+
+static void async_client_put(client_t *client)
+{
+	bool destroy;
+	
+	futex_down(&async_futex);
+	
+	if (atomic_predec(&client->refcnt) == 0) {
+		hash_table_remove(&client_hash_table, &client->in_task_id);
+		destroy = true;
+	} else
+		destroy = false;
+	
+	futex_up(&async_futex);
+	
+	if (destroy) {
+		if (client->data)
+			async_client_data_destroy(client->data);
+		
+		free(client);
+	}
+}
+
+/** Wrapper for client connection fibril.
+ *
+ * When a new connection arrives, a fibril with this implementing
+ * function is created.
+ *
+ * @param arg Connection structure pointer.
+ *
+ * @return Always zero.
+ *
+ */
+static int connection_fibril(void *arg)
+{
+	assert(arg);
+	
+	/*
+	 * Setup fibril-local connection pointer.
+	 */
+	fibril_connection = (connection_t *) arg;
+	
+	/*
+	 * Add our reference for the current connection in the client task
+	 * tracking structure. If this is the first reference, create and
+	 * hash in a new tracking structure.
+	 */
+	
+	client_t *client = async_client_get(fibril_connection->in_task_id, true);
+	if (!client) {
+		ipc_answer_0(fibril_connection->callid, ENOMEM);
+		return 0;
+	}
+	
+	fibril_connection->client = client;
+	
+	/*
+	 * Call the connection handler function.
+	 */
+	fibril_connection->handler(fibril_connection->callid,
+	    &fibril_connection->call, fibril_connection->data);
+	
+	/*
+	 * Remove the reference for this client task connection.
+	 */
+	async_client_put(client);
+	
+	/*
+	 * Remove myself from the connection hash table.
+	 */
+	futex_down(&async_futex);
+	hash_table_remove(&conn_hash_table, &fibril_connection->in_phone_hash);
+	futex_up(&async_futex);
+	
+	/*
+	 * Answer all remaining messages with EHANGUP.
+	 */
+	while (!list_empty(&fibril_connection->msg_queue)) {
+		msg_t *msg =
+		    list_get_instance(list_first(&fibril_connection->msg_queue),
+		    msg_t, link);
+		
+		list_remove(&msg->link);
+		ipc_answer_0(msg->callid, EHANGUP);
+		free(msg);
+	}
+	
+	/*
+	 * If the connection was hung-up, answer the last call,
+	 * i.e. IPC_M_PHONE_HUNGUP.
+	 */
+	if (fibril_connection->close_callid)
+		ipc_answer_0(fibril_connection->close_callid, EOK);
+	
+	free(fibril_connection);
+	return 0;
+}
+
+/** Create a new fibril for a new connection.
+ *
+ * Create new fibril for connection, fill in connection structures
+ * and insert it into the hash table, so that later we can easily
+ * do routing of messages to particular fibrils.
+ *
+ * @param in_task_id    Identification of the incoming connection.
+ * @param in_phone_hash Identification of the incoming connection.
+ * @param callid        Hash of the opening IPC_M_CONNECT_ME_TO call.
+ *                      If callid is zero, the connection was opened by
+ *                      accepting the IPC_M_CONNECT_TO_ME call and this
+ *                      function is called directly by the server.
+ * @param call          Call data of the opening call.
+ * @param handler       Connection handler.
+ * @param data          Client argument to pass to the connection handler.
+ *
+ * @return New fibril id or NULL on failure.
+ *
+ */
+static fid_t async_new_connection(task_id_t in_task_id, sysarg_t in_phone_hash,
+    ipc_callid_t callid, ipc_call_t *call, async_port_handler_t handler,
+    void *data)
+{
+	connection_t *conn = malloc(sizeof(*conn));
+	if (!conn) {
+		if (callid)
+			ipc_answer_0(callid, ENOMEM);
+		
+		return (uintptr_t) NULL;
+	}
+	
+	conn->in_task_id = in_task_id;
+	conn->in_phone_hash = in_phone_hash;
+	list_initialize(&conn->msg_queue);
+	conn->callid = callid;
+	conn->close_callid = 0;
+	conn->handler = handler;
+	conn->data = data;
+	
+	if (call)
+		conn->call = *call;
+	
+	/* We will activate the fibril ASAP */
+	conn->wdata.active = true;
+	conn->wdata.fid = fibril_create(connection_fibril, conn);
+	
+	if (conn->wdata.fid == 0) {
+		free(conn);
+		
+		if (callid)
+			ipc_answer_0(callid, ENOMEM);
+		
+		return (uintptr_t) NULL;
+	}
+	
+	/* Add connection to the connection hash table */
+	
+	futex_down(&async_futex);
+	hash_table_insert(&conn_hash_table, &conn->link);
+	futex_up(&async_futex);
+	
+	fibril_add_ready(conn->wdata.fid);
+	
+	return conn->wdata.fid;
+}
+
+/** Wrapper for making IPC_M_CONNECT_TO_ME calls using the async framework.
+ *
+ * Ask through phone for a new connection to some service.
+ *
+ * @param exch    Exchange for sending the message.
+ * @param iface   Callback interface.
+ * @param arg1    User defined argument.
+ * @param arg2    User defined argument.
+ * @param handler Callback handler.
+ * @param data    Handler data.
+ * @param port_id ID of the newly created port.
+ *
+ * @return Zero on success or a negative error code.
+ *
+ */
+int async_create_callback_port(async_exch_t *exch, iface_t iface, sysarg_t arg1,
+    sysarg_t arg2, async_port_handler_t handler, void *data, port_id_t *port_id)
+{
+	if ((iface & IFACE_MOD_CALLBACK) != IFACE_MOD_CALLBACK)
+		return EINVAL;
+	
+	if (exch == NULL)
+		return ENOENT;
+	
+	ipc_call_t answer;
+	aid_t req = async_send_3(exch, IPC_M_CONNECT_TO_ME, iface, arg1, arg2,
+	    &answer);
+	
+	sysarg_t ret;
+	async_wait_for(req, &ret);
+	if (ret != EOK)
+		return (int) ret;
+	
+	sysarg_t phone_hash = IPC_GET_ARG5(answer);
+	interface_t *interface;
+	
+	futex_down(&async_futex);
+	
+	ht_link_t *link = hash_table_find(&interface_hash_table, &iface);
+	if (link)
+		interface = hash_table_get_inst(link, interface_t, link);
+	else
+		interface = async_new_interface(iface);
+	
+	if (!interface) {
+		futex_up(&async_futex);
+		return ENOMEM;
+	}
+	
+	port_t *port = async_new_port(interface, handler, data);
+	if (!port) {
+		futex_up(&async_futex);
+		return ENOMEM;
+	}
+	
+	*port_id = port->id;
+	
+	futex_up(&async_futex);
+	
+	fid_t fid = async_new_connection(answer.in_task_id, phone_hash,
+	    0, NULL, handler, data);
+	if (fid == (uintptr_t) NULL)
+		return ENOMEM;
+	
+	return EOK;
+}
 
 static size_t notification_key_hash(void *key)
@@ -866,5 +1293,6 @@
 	}
 	
-	msg_t *msg = list_get_instance(list_first(&conn->msg_queue), msg_t, link);
+	msg_t *msg = list_get_instance(list_first(&conn->msg_queue),
+	    msg_t, link);
 	list_remove(&msg->link);
 	
@@ -877,50 +1305,4 @@
 }
 
-static client_t *async_client_get(task_id_t client_id, bool create)
-{
-	client_t *client = NULL;
-
-	futex_down(&async_futex);
-	ht_link_t *link = hash_table_find(&client_hash_table, &client_id);
-	if (link) {
-		client = hash_table_get_inst(link, client_t, link);
-		atomic_inc(&client->refcnt);
-	} else if (create) {
-		client = malloc(sizeof(client_t));
-		if (client) {
-			client->in_task_id = client_id;
-			client->data = async_client_data_create();
-		
-			atomic_set(&client->refcnt, 1);
-			hash_table_insert(&client_hash_table, &client->link);
-		}
-	}
-
-	futex_up(&async_futex);
-	return client;
-}
-
-static void async_client_put(client_t *client)
-{
-	bool destroy;
-
-	futex_down(&async_futex);
-	
-	if (atomic_predec(&client->refcnt) == 0) {
-		hash_table_remove(&client_hash_table, &client->in_task_id);
-		destroy = true;
-	} else
-		destroy = false;
-	
-	futex_up(&async_futex);
-	
-	if (destroy) {
-		if (client->data)
-			async_client_data_destroy(client->data);
-		
-		free(client);
-	}
-}
-
 void *async_get_client_data(void)
 {
@@ -934,9 +1316,10 @@
 	if (!client)
 		return NULL;
+	
 	if (!client->data) {
 		async_client_put(client);
 		return NULL;
 	}
-
+	
 	return client->data;
 }
@@ -945,155 +1328,34 @@
 {
 	client_t *client = async_client_get(client_id, false);
-
+	
 	assert(client);
 	assert(client->data);
-
+	
 	/* Drop the reference we got in async_get_client_data_by_hash(). */
 	async_client_put(client);
-
+	
 	/* Drop our own reference we got at the beginning of this function. */
 	async_client_put(client);
 }
 
-/** Wrapper for client connection fibril.
- *
- * When a new connection arrives, a fibril with this implementing function is
- * created. It calls client_connection() and does the final cleanup.
- *
- * @param arg Connection structure pointer.
- *
- * @return Always zero.
- *
- */
-static int connection_fibril(void *arg)
-{
-	assert(arg);
-	
-	/*
-	 * Setup fibril-local connection pointer.
-	 */
-	fibril_connection = (connection_t *) arg;
-	
-	/*
-	 * Add our reference for the current connection in the client task
-	 * tracking structure. If this is the first reference, create and
-	 * hash in a new tracking structure.
-	 */
-
-	client_t *client = async_client_get(fibril_connection->in_task_id, true);
-	if (!client) {
-		ipc_answer_0(fibril_connection->callid, ENOMEM);
-		return 0;
-	}
-
-	fibril_connection->client = client;
-	
-	/*
-	 * Call the connection handler function.
-	 */
-	fibril_connection->cfibril(fibril_connection->callid,
-	    &fibril_connection->call, fibril_connection->carg);
-	
-	/*
-	 * Remove the reference for this client task connection.
-	 */
-	async_client_put(client);
-	
-	/*
-	 * Remove myself from the connection hash table.
-	 */
+static port_t *async_find_port(iface_t iface, port_id_t port_id)
+{
+	port_t *port = NULL;
+	
 	futex_down(&async_futex);
-	hash_table_remove(&conn_hash_table, &fibril_connection->in_phone_hash);
+	
+	ht_link_t *link = hash_table_find(&interface_hash_table, &iface);
+	if (link) {
+		interface_t *interface =
+		    hash_table_get_inst(link, interface_t, link);
+		
+		link = hash_table_find(&interface->port_hash_table, &port_id);
+		if (link)
+			port = hash_table_get_inst(link, port_t, link);
+	}
+	
 	futex_up(&async_futex);
 	
-	/*
-	 * Answer all remaining messages with EHANGUP.
-	 */
-	while (!list_empty(&fibril_connection->msg_queue)) {
-		msg_t *msg =
-		    list_get_instance(list_first(&fibril_connection->msg_queue),
-		    msg_t, link);
-		
-		list_remove(&msg->link);
-		ipc_answer_0(msg->callid, EHANGUP);
-		free(msg);
-	}
-	
-	/*
-	 * If the connection was hung-up, answer the last call,
-	 * i.e. IPC_M_PHONE_HUNGUP.
-	 */
-	if (fibril_connection->close_callid)
-		ipc_answer_0(fibril_connection->close_callid, EOK);
-	
-	free(fibril_connection);
-	return 0;
-}
-
-/** Create a new fibril for a new connection.
- *
- * Create new fibril for connection, fill in connection structures and insert
- * it into the hash table, so that later we can easily do routing of messages to
- * particular fibrils.
- *
- * @param in_task_id    Identification of the incoming connection.
- * @param in_phone_hash Identification of the incoming connection.
- * @param callid        Hash of the opening IPC_M_CONNECT_ME_TO call.
- *                      If callid is zero, the connection was opened by
- *                      accepting the IPC_M_CONNECT_TO_ME call and this function
- *                      is called directly by the server.
- * @param call          Call data of the opening call.
- * @param cfibril       Fibril function that should be called upon opening the
- *                      connection.
- * @param carg          Extra argument to pass to the connection fibril
- *
- * @return New fibril id or NULL on failure.
- *
- */
-fid_t async_new_connection(task_id_t in_task_id, sysarg_t in_phone_hash,
-    ipc_callid_t callid, ipc_call_t *call,
-    async_client_conn_t cfibril, void *carg)
-{
-	connection_t *conn = malloc(sizeof(*conn));
-	if (!conn) {
-		if (callid)
-			ipc_answer_0(callid, ENOMEM);
-		
-		return (uintptr_t) NULL;
-	}
-	
-	conn->in_task_id = in_task_id;
-	conn->in_phone_hash = in_phone_hash;
-	list_initialize(&conn->msg_queue);
-	conn->callid = callid;
-	conn->close_callid = 0;
-	conn->carg = carg;
-	
-	if (call)
-		conn->call = *call;
-	
-	/* We will activate the fibril ASAP */
-	conn->wdata.active = true;
-	conn->cfibril = cfibril;
-	conn->wdata.fid = fibril_create(connection_fibril, conn);
-	
-	if (conn->wdata.fid == 0) {
-		free(conn);
-		
-		if (callid)
-			ipc_answer_0(callid, ENOMEM);
-		
-		return (uintptr_t) NULL;
-	}
-	
-	/* Add connection to the connection hash table */
-	
-	futex_down(&async_futex);
-	hash_table_insert(&conn_hash_table, &conn->link);
-	futex_up(&async_futex);
-	
-	fibril_add_ready(conn->wdata.fid);
-	
-	return conn->wdata.fid;
+	return port;
 }
 
@@ -1111,5 +1373,5 @@
 	assert(call);
 	
-	/* Unrouted call - take some default action */
+	/* Kernel notification */
 	if ((callid & IPC_CALLID_NOTIFICATION)) {
 		process_notification(callid, call);
@@ -1117,10 +1379,31 @@
 	}
 	
-	switch (IPC_GET_IMETHOD(*call)) {
-	case IPC_M_CLONE_ESTABLISH:
-	case IPC_M_CONNECT_ME_TO:
+	/* New connection */
+	if (IPC_GET_IMETHOD(*call) == IPC_M_CONNECT_ME_TO) {
+		iface_t iface = (iface_t) IPC_GET_ARG1(*call);
+		sysarg_t in_phone_hash = IPC_GET_ARG5(*call);
+		
+		async_notification_handler_t handler = fallback_port_handler;
+		void *data = fallback_port_data;
+		
+		// TODO: Currently ignores all ports but the first one
+		port_t *port = async_find_port(iface, 0);
+		if (port) {
+			handler = port->handler;
+			data = port->data;
+		}
+		
+		async_new_connection(call->in_task_id, in_phone_hash, callid,
+		    call, handler, data);
+		return;
+	}
+	
+	/* Cloned connection */
+	if (IPC_GET_IMETHOD(*call) == IPC_M_CLONE_ESTABLISH) {
+		// TODO: Currently ignores ports altogether
+		
 		/* Open new connection with fibril, etc. */
 		async_new_connection(call->in_task_id, IPC_GET_ARG5(*call),
-		    callid, call, client_connection, NULL);
+		    callid, call, fallback_port_handler, fallback_port_data);
 		return;
 	}
@@ -1283,4 +1566,8 @@
 void __async_init(void)
 {
+	if (!hash_table_create(&interface_hash_table, 0, 0,
+	    &interface_hash_table_ops))
+		abort();
+	
 	if (!hash_table_create(&client_hash_table, 0, 0, &client_hash_table_ops))
 		abort();
@@ -1297,4 +1584,5 @@
 		abort();
 	
+	session_ns->iface = 0;
 	session_ns->mgmt = EXCHANGE_ATOMIC;
 	session_ns->phone = PHONE_NS;
@@ -1343,5 +1631,5 @@
 	
 	msg->done = true;
-
+	
 	if (msg->forget) {
 		assert(msg->wdata.active);
@@ -1351,5 +1639,5 @@
 		fibril_add_ready(msg->wdata.fid);
 	}
-
+	
 	futex_up(&async_futex);
 }
@@ -1443,8 +1731,8 @@
 	
 	futex_down(&async_futex);
-
+	
 	assert(!msg->forget);
 	assert(!msg->destroyed);
-
+	
 	if (msg->done) {
 		futex_up(&async_futex);
@@ -1487,10 +1775,10 @@
 	
 	amsg_t *msg = (amsg_t *) amsgid;
-
+	
 	futex_down(&async_futex);
-
+	
 	assert(!msg->forget);
 	assert(!msg->destroyed);
-
+	
 	if (msg->done) {
 		futex_up(&async_futex);
@@ -1504,5 +1792,5 @@
 	if (timeout < 0)
 		timeout = 0;
-
+	
 	getuptime(&msg->wdata.to_event.expires);
 	tv_add_diff(&msg->wdata.to_event.expires, timeout);
@@ -1557,10 +1845,11 @@
 {
 	amsg_t *msg = (amsg_t *) amsgid;
-
+	
 	assert(msg);
 	assert(!msg->forget);
 	assert(!msg->destroyed);
-
+	
 	futex_down(&async_futex);
+	
 	if (msg->done) {
 		amsg_destroy(msg);
@@ -1569,4 +1858,5 @@
 		msg->forget = true;
 	}
+	
 	futex_up(&async_futex);
 }
@@ -1814,5 +2104,4 @@
  * @param arg2            User defined argument.
  * @param arg3            User defined argument.
- * @param client_receiver Connection handing routine.
  *
  * @return Zero on success or a negative error code.
@@ -1820,25 +2109,17 @@
  */
 int async_connect_to_me(async_exch_t *exch, sysarg_t arg1, sysarg_t arg2,
-    sysarg_t arg3, async_client_conn_t client_receiver, void *carg)
+    sysarg_t arg3)
 {
 	if (exch == NULL)
 		return ENOENT;
 	
-	sysarg_t phone_hash;
+	ipc_call_t answer;
+	aid_t req = async_send_3(exch, IPC_M_CONNECT_TO_ME, arg1, arg2, arg3,
+	    &answer);
+	
 	sysarg_t rc;
-
-	aid_t req;
-	ipc_call_t answer;
-	req = async_send_3(exch, IPC_M_CONNECT_TO_ME, arg1, arg2, arg3,
-	    &answer);
 	async_wait_for(req, &rc);
 	if (rc != EOK)
 		return (int) rc;
-
-	phone_hash = IPC_GET_ARG5(answer);
-
-	if (client_receiver != NULL)
-		async_new_connection(answer.in_task_id, phone_hash, 0, NULL,
-		    client_receiver, carg);
 	
 	return EOK;
@@ -1900,4 +2181,5 @@
 	}
 	
+	sess->iface = 0;
 	sess->mgmt = mgmt;
 	sess->phone = phone;
@@ -1969,5 +2251,4 @@
 	int phone = async_connect_me_to_internal(exch->phone, arg1, arg2, arg3,
 	    0);
-	
 	if (phone < 0) {
 		errno = phone;
@@ -1976,4 +2257,5 @@
 	}
 	
+	sess->iface = 0;
 	sess->mgmt = mgmt;
 	sess->phone = phone;
@@ -1992,4 +2274,55 @@
 }
 
+/** Wrapper for making IPC_M_CONNECT_ME_TO calls using the async framework.
+ *
+ * Ask through phone for a new connection to some service and block until
+ * success.
+ *
+ * @param exch  Exchange for sending the message.
+ * @param iface Connection interface.
+ * @param arg2  User defined argument.
+ * @param arg3  User defined argument.
+ *
+ * @return New session on success or NULL on error.
+ *
+ */
+async_sess_t *async_connect_me_to_iface(async_exch_t *exch, iface_t iface,
+    sysarg_t arg2, sysarg_t arg3)
+{
+	if (exch == NULL) {
+		errno = ENOENT;
+		return NULL;
+	}
+	
+	async_sess_t *sess = (async_sess_t *) malloc(sizeof(async_sess_t));
+	if (sess == NULL) {
+		errno = ENOMEM;
+		return NULL;
+	}
+	
+	int phone = async_connect_me_to_internal(exch->phone, iface, arg2,
+	    arg3, 0);
+	if (phone < 0) {
+		errno = phone;
+		free(sess);
+		return NULL;
+	}
+	
+	sess->iface = iface;
+	sess->phone = phone;
+	sess->arg1 = iface;
+	sess->arg2 = arg2;
+	sess->arg3 = arg3;
+	
+	fibril_mutex_initialize(&sess->remote_state_mtx);
+	sess->remote_state_data = NULL;
+	
+	list_initialize(&sess->exch_list);
+	fibril_mutex_initialize(&sess->mutex);
+	atomic_set(&sess->refcnt, 0);
+	
+	return sess;
+}
+
 /** Set arguments for new connections.
  *
@@ -2047,4 +2380,5 @@
 	}
 	
+	sess->iface = 0;
 	sess->mgmt = mgmt;
 	sess->phone = phone;
@@ -2063,4 +2397,55 @@
 }
 
+/** Wrapper for making IPC_M_CONNECT_ME_TO calls using the async framework.
+ *
+ * Ask through phone for a new connection to some service and block until
+ * success.
+ *
+ * @param exch  Exchange for sending the message.
+ * @param iface Connection interface.
+ * @param arg2  User defined argument.
+ * @param arg3  User defined argument.
+ *
+ * @return New session on success or NULL on error.
+ *
+ */
+async_sess_t *async_connect_me_to_blocking_iface(async_exch_t *exch, iface_t iface,
+    sysarg_t arg2, sysarg_t arg3)
+{
+	if (exch == NULL) {
+		errno = ENOENT;
+		return NULL;
+	}
+	
+	async_sess_t *sess = (async_sess_t *) malloc(sizeof(async_sess_t));
+	if (sess == NULL) {
+		errno = ENOMEM;
+		return NULL;
+	}
+	
+	int phone = async_connect_me_to_internal(exch->phone, iface, arg2,
+	    arg3, IPC_FLAG_BLOCKING);
+	if (phone < 0) {
+		errno = phone;
+		free(sess);
+		return NULL;
+	}
+	
+	sess->iface = iface;
+	sess->phone = phone;
+	sess->arg1 = iface;
+	sess->arg2 = arg2;
+	sess->arg3 = arg3;
+	
+	fibril_mutex_initialize(&sess->remote_state_mtx);
+	sess->remote_state_data = NULL;
+	
+	list_initialize(&sess->exch_list);
+	fibril_mutex_initialize(&sess->mutex);
+	atomic_set(&sess->refcnt, 0);
+	
+	return sess;
+}
+
 /** Connect to a task specified by id.
  *
@@ -2081,4 +2466,5 @@
 	}
 	
+	sess->iface = 0;
 	sess->mgmt = EXCHANGE_ATOMIC;
 	sess->phone = phone;
@@ -2158,5 +2544,9 @@
 		return NULL;
 	
-	async_exch_t *exch;
+	exch_mgmt_t mgmt = sess->mgmt;
+	if (sess->iface != 0)
+		mgmt = sess->iface & IFACE_EXCHANGE_MASK;
+	
+	async_exch_t *exch = NULL;
 	
 	fibril_mutex_lock(&async_sess_mutex);
@@ -2177,6 +2567,6 @@
 		 */
 		
-		if ((sess->mgmt == EXCHANGE_ATOMIC) ||
-		    (sess->mgmt == EXCHANGE_SERIALIZE)) {
+		if ((mgmt == EXCHANGE_ATOMIC) ||
+		    (mgmt == EXCHANGE_SERIALIZE)) {
 			exch = (async_exch_t *) malloc(sizeof(async_exch_t));
 			if (exch != NULL) {
@@ -2186,12 +2576,11 @@
 				exch->phone = sess->phone;
 			}
-		} else {  /* EXCHANGE_PARALLEL */
+		} else if (mgmt == EXCHANGE_PARALLEL) {
+			int phone;
+			
+		retry:
 			/*
 			 * Make a one-time attempt to connect a new data phone.
 			 */
-			
-			int phone;
-			
-retry:
 			phone = async_connect_me_to_internal(sess->phone, sess->arg1,
 			    sess->arg2, sess->arg3, 0);
@@ -2235,5 +2624,5 @@
 		atomic_inc(&sess->refcnt);
 		
-		if (sess->mgmt == EXCHANGE_SERIALIZE)
+		if (mgmt == EXCHANGE_SERIALIZE)
 			fibril_mutex_lock(&sess->mutex);
 	}
@@ -2255,7 +2644,11 @@
 	assert(sess != NULL);
 	
+	exch_mgmt_t mgmt = sess->mgmt;
+	if (sess->iface != 0)
+		mgmt = sess->iface & IFACE_EXCHANGE_MASK;
+	
 	atomic_dec(&sess->refcnt);
 	
-	if (sess->mgmt == EXCHANGE_SERIALIZE)
+	if (mgmt == EXCHANGE_SERIALIZE)
 		fibril_mutex_unlock(&sess->mutex);
 	
@@ -2694,26 +3087,26 @@
 	}
 	
-	void *_data;
+	void *arg_data;
 	
 	if (nullterm)
-		_data = malloc(size + 1);
+		arg_data = malloc(size + 1);
 	else
-		_data = malloc(size);
-	
-	if (_data == NULL) {
+		arg_data = malloc(size);
+	
+	if (arg_data == NULL) {
 		ipc_answer_0(callid, ENOMEM);
 		return ENOMEM;
 	}
 	
-	int rc = async_data_write_finalize(callid, _data, size);
+	int rc = async_data_write_finalize(callid, arg_data, size);
 	if (rc != EOK) {
-		free(_data);
+		free(arg_data);
 		return rc;
 	}
 	
 	if (nullterm)
-		((char *) _data)[size] = 0;
-	
-	*data = _data;
+		((char *) arg_data)[size] = 0;
+	
+	*data = arg_data;
 	if (received != NULL)
 		*received = size;
@@ -2813,4 +3206,5 @@
 	}
 	
+	sess->iface = 0;
 	sess->mgmt = mgmt;
 	sess->phone = phone;
@@ -2862,4 +3256,5 @@
 	}
 	
+	sess->iface = 0;
 	sess->mgmt = mgmt;
 	sess->phone = phone;
@@ -2907,4 +3302,5 @@
 		return NULL;
 	
+	sess->iface = 0;
 	sess->mgmt = mgmt;
 	sess->phone = phone;
@@ -2934,8 +3330,8 @@
 {
 	assert(callid);
-
+	
 	ipc_call_t call;
 	*callid = async_get_call(&call);
-
+	
 	if (IPC_GET_IMETHOD(call) != IPC_M_STATE_CHANGE_AUTHORIZE)
 		return false;
@@ -2947,5 +3343,5 @@
 	if (arg3)
 		*arg3 = IPC_GET_ARG3(call);
-
+	
 	return true;
 }
Index: uspace/lib/c/generic/bd.c
===================================================================
--- uspace/lib/c/generic/bd.c	(revision 9854a8faee04ea815f8612666a6e4dac63db2748)
+++ uspace/lib/c/generic/bd.c	(revision cffa82aac31c77f5d26f954922753c58edfef5f7)
@@ -57,5 +57,8 @@
 	async_exch_t *exch = async_exchange_begin(sess);
 	
-	int rc = async_connect_to_me(exch, 0, 0, 0, bd_cb_conn, bd);
+	port_id_t port;
+	int rc = async_create_callback_port(exch, INTERFACE_BLOCK_CB, 0, 0,
+	    bd_cb_conn, bd, &port);
+	
 	async_exchange_end(exch);
 	
Index: uspace/lib/c/generic/cfg.c
===================================================================
--- uspace/lib/c/generic/cfg.c	(revision 9854a8faee04ea815f8612666a6e4dac63db2748)
+++ 	(revision )
@@ -1,441 +1,0 @@
-/*
- * Copyright (c) 2011 Radim Vansa
- * 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 cfg.c
- * @brief Configuration files manipulation implementation.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <str.h>
-#include <errno.h>
-#include <assert.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <ctype.h>
-#include <cfg.h>
-
-/**
- * @param data Configuration file data
- *
- * @return Anonymous section in the configuration file.
- * @return NULL if there is no such section (it is empty)
- *
- */
-const cfg_section_t *cfg_anonymous(const cfg_file_t *data)
-{
-	assert(data != NULL);
-	
-	if (list_empty(&data->sections))
-		return NULL;
-	
-	link_t *link = list_first(&data->sections);
-	const cfg_section_t *section = cfg_section_instance(link);
-	if (section->title[0] != 0)
-		return NULL;
-	
-	return section;
-}
-
-/**
- * @param data Configuration file data
- *
- * @return True if the file contains no data
- *         (no sections, neither anonymous).
- * @return False otherwise.
- *
- */
-bool cfg_empty(const cfg_file_t *data)
-{
-	assert(data != NULL);
-	
-	if (list_empty(&data->sections))
-		return true;
-	
-	cfg_file_foreach(data, section) {
-		if (!list_empty(&section->entries))
-			return false;
-	}
-	
-	return true;
-}
-
-/** Read file contents into memory.
- *
- * @param path Path to the file
- * @param buf  Pointer to pointer to buffer where
- *             the file contents will be stored
- *
- * @return EOK if the file was successfully loaded.
- * @return ENOMEM if there was not enough memory to load the file
- * @return EIO if there was a problem with reading the file
- * @return Other error code if there was a problem openening the file
- *
- */
-static int cfg_read(const char *path, char **buf)
-{
-	assert(buf != NULL);
-	
-	int fd = open(path, O_RDONLY);
-	if (fd < 0)
-		return fd;
-	
-	size_t len = lseek(fd, 0, SEEK_END);
-	lseek(fd, 0, SEEK_SET);
-	
-	*buf = malloc(len + 1);
-	if (*buf == NULL) {
-		close(fd);
-		return ENOMEM;
-	}
-	
-	ssize_t rd = read_all(fd, *buf, len);
-	if (rd < 0) {
-		free(*buf);
-		close(fd);
-		return EIO;
-	}
-	
-	(*buf)[len] = 0;
-	close(fd);
-	
-	return EOK;
-}
-
-static inline void null_back(char *back)
-{
-	do {
-		*back = 0;
-		back--;
-	} while (isspace(*back));
-}
-
-/** Allocate and initialize a new entry.
- *
- * @param key   Entry key
- * @param value Entry value
- *
- * @return New entry
- * @return NULL if there was not enough memory
- *
- */
-static cfg_entry_t *cfg_new_entry(const char *key, const char *value)
-{
-	cfg_entry_t *entry = malloc(sizeof(cfg_entry_t));
-	if (entry == NULL)
-		return NULL;
-	
-	link_initialize(&entry->link);
-	entry->key = key;
-	entry->value = value;
-	
-	return entry;
-}
-
-/** Allocate and initialize a new section.
- *
- * @param title Section title
- *
- * @return New section
- * @return NULL if there was not enough memory
- *
- */
-static cfg_section_t *cfg_new_section(const char *title)
-{
-	cfg_section_t *sec = malloc(sizeof(cfg_section_t));
-	if (sec == NULL)
-		return NULL;
-	
-	link_initialize(&sec->link);
-	
-	if (title != NULL)
-		sec->title = title;
-	else
-		sec->title = "";
-	
-	list_initialize(&sec->entries);
-	sec->entry_count = 0;
-	
-	return sec;
-}
-
-/** Skip whitespaces
- *
- */
-static inline void skip_whitespaces(char **buffer)
-{
-	while (isspace(**buffer))
-		(*buffer)++;
-}
-
-static inline int starts_comment(char c)
-{
-	return ((c == ';') || (c == '#'));
-}
-
-/** Load file content into memory
- *
- * Parse the file into sections and entries
- * and initialize data with this info.
- *
- * @param path Path to the configuration file
- * @param data Configuration file data
- *
- * @return EOK if the file was successfully loaded
- * @return EBADF if the configuration file has bad format.
- * @return ENOMEM if there was not enough memory
- * @return Error code from cfg_read()
- *
- */
-int cfg_load(const char *path, cfg_file_t *data)
-{
-	char *buffer;
-	int res = cfg_read(path, &buffer);
-	if (res != EOK)
-		return res;
-	
-	list_initialize(&data->sections);
-	data->section_count = 0;
-	data->data = buffer;
-	
-	cfg_section_t *curr_section = NULL;
-	skip_whitespaces(&buffer);
-	
-	while (*buffer) {
-		while (starts_comment(*buffer)) {
-			while ((*buffer) && (*buffer != '\n'))
-				buffer++;
-			
-			skip_whitespaces(&buffer);
-		}
-		
-		if (*buffer == '[') {
-			buffer++;
-			skip_whitespaces(&buffer);
-			
-			const char *title = buffer;
-			while ((*buffer) && (*buffer != ']') && (*buffer != '\n'))
-				buffer++;
-			
-			if (*buffer != ']') {
-				cfg_unload(data);
-				return EBADF;
-			}
-			
-			null_back(buffer);
-			buffer++;
-			
-			cfg_section_t *sec = cfg_new_section(title);
-			if (sec == NULL) {
-				cfg_unload(data);
-				return ENOMEM;
-			}
-			
-			list_append(&sec->link, &data->sections);
-			data->section_count++;
-			curr_section = sec;
-		} else if (*buffer) {
-			const char *key = buffer;
-			while ((*buffer) && (*buffer != '=') && (*buffer != '\n'))
-				buffer++;
-			
-			if (*buffer != '=') {
-				cfg_unload(data);
-				return EBADF;
-			}
-			
-			/* null = and whitespaces before */
-			null_back(buffer);
-			buffer++;
-			skip_whitespaces(&buffer);
-			
-			while (starts_comment(*buffer)) {
-				while ((*buffer) && (*buffer != '\n'))
-					buffer++;
-				
-				skip_whitespaces(&buffer);
-			}
-			
-			const char *value = buffer;
-			/* Empty value is correct value */
-			if (*buffer) {
-				while ((*buffer) && (*buffer != '\n'))
-					buffer++;
-				
-				if (*buffer) {
-					null_back(buffer);
-					buffer++;
-				} else
-					null_back(buffer);
-			}
-			
-			/* Create anonymous section if not present */
-			if (curr_section == NULL) {
-				curr_section = cfg_new_section(NULL);
-				if (curr_section == NULL) {
-					cfg_unload(data);
-					return ENOMEM;
-				}
-				
-				list_append(&curr_section->link, &data->sections);
-			}
-			
-			cfg_entry_t *entry = cfg_new_entry(key, value);
-			if (entry == NULL) {
-				cfg_unload(data);
-				return ENOMEM;
-			}
-			
-			list_append(&entry->link, &curr_section->entries);
-			curr_section->entry_count++;
-		}
-		
-		skip_whitespaces(&buffer);
-	}
-	
-	return EOK;
-}
-
-/** Load file content into memory (with path)
- *
- * Parse the file (with path) into sections and entries
- * and initialize data with this info.
- *
- */
-int cfg_load_path(const char *path, const char *fname, cfg_file_t *data)
-{
-	size_t sz = str_size(path) + str_size(fname) + 2;
-	char *name = malloc(sz);
-	if (name == NULL)
-		return ENOMEM;
-	
-	snprintf(name, sz, "%s/%s", path, fname);
-	int rc = cfg_load(name, data);
-	
-	free(name);
-	
-	return rc;
-}
-
-/** Deallocate memory used by entry
- *
- */
-static void cfg_free_entry(const cfg_entry_t *entry)
-{
-	assert(entry != NULL);
-	free(entry);
-}
-
-/** Deallocate memory used by all entries
- *
- * Deallocate memory used by all entries within a section
- * and the memory used by the section itself.
- *
- */
-static void cfg_free_section(const cfg_section_t *section)
-{
-	assert(section != NULL);
-	
-	link_t *cur;
-	link_t *next;
-	
-	for (cur = section->entries.head.next;
-	    cur != &section->entries.head;
-	    cur = next) {
-		next = cur->next;
-		cfg_free_entry(cfg_entry_instance(cur));
-	}
-	
-	free(section);
-}
-
-/** Deallocate memory used by configuration data
- *
- * Deallocate all inner sections and entries.
- *
- */
-void cfg_unload(cfg_file_t *data)
-{
-	assert(data != NULL);
-	
-	link_t *cur, *next;
-	for (cur = data->sections.head.next;
-	    cur != &data->sections.head;
-	    cur = next) {
-		next = cur->next;
-		cfg_free_section(cfg_section_instance(cur));
-	}
-	
-	free(data->data);
-}
-
-/** Find a section in the configuration data
- *
- * @param data  Configuration data
- * @param title Title of the section to search for
- *
- * @return Found section
- * @return NULL if there is no section with such title
- *
- */
-const cfg_section_t *cfg_find_section(const cfg_file_t *data, const char *title)
-{
-	cfg_file_foreach(data, section) {
-		if (str_cmp(section->title, title) == 0)
-			return section;
-	}
-	
-	return NULL;
-}
-
-/** Find entry value in the configuration data
- *
- * @param section Section in which to search
- * @param key     Key of the entry we to search for
- *
- * @return Value of the entry
- * @return NULL if there is no entry with such key
- *
- */
-const char *cfg_find_value(const cfg_section_t *section, const char *key)
-{
-	cfg_section_foreach(section, entry) {
-		if (str_cmp(entry->key, key) == 0)
-			return entry->value;
-	}
-	
-	return NULL;
-}
-
-/** @}
- */
Index: uspace/lib/c/generic/clipboard.c
===================================================================
--- uspace/lib/c/generic/clipboard.c	(revision 9854a8faee04ea815f8612666a6e4dac63db2748)
+++ uspace/lib/c/generic/clipboard.c	(revision cffa82aac31c77f5d26f954922753c58edfef5f7)
@@ -61,6 +61,6 @@
 	
 	while (clip_sess == NULL)
-		clip_sess = service_connect_blocking(EXCHANGE_SERIALIZE,
-		    SERVICE_CLIPBOARD, 0, 0);
+		clip_sess = service_connect_blocking(SERVICE_CLIPBOARD,
+		    INTERFACE_CLIPBOARD, 0);
 	
 	fibril_mutex_unlock(&clip_mutex);
Index: uspace/lib/c/generic/corecfg.c
===================================================================
--- uspace/lib/c/generic/corecfg.c	(revision 9854a8faee04ea815f8612666a6e4dac63db2748)
+++ uspace/lib/c/generic/corecfg.c	(revision cffa82aac31c77f5d26f954922753c58edfef5f7)
@@ -50,5 +50,5 @@
 		return ENOENT;
 
-	corecfg_sess = loc_service_connect(EXCHANGE_SERIALIZE, corecfg_svc,
+	corecfg_sess = loc_service_connect(corecfg_svc, INTERFACE_CORECFG,
 	    IPC_FLAG_BLOCKING);
 	if (corecfg_sess == NULL)
Index: uspace/lib/c/generic/devman.c
===================================================================
--- uspace/lib/c/generic/devman.c	(revision 9854a8faee04ea815f8612666a6e4dac63db2748)
+++ uspace/lib/c/generic/devman.c	(revision cffa82aac31c77f5d26f954922753c58edfef5f7)
@@ -77,8 +77,8 @@
  *
  */
-async_exch_t *devman_exchange_begin_blocking(devman_interface_t iface)
+async_exch_t *devman_exchange_begin_blocking(iface_t iface)
 {
 	switch (iface) {
-	case DEVMAN_DRIVER:
+	case INTERFACE_DDF_DRIVER:
 		fibril_mutex_lock(&devman_driver_block_mutex);
 		
@@ -89,6 +89,6 @@
 			if (devman_driver_block_sess == NULL)
 				devman_driver_block_sess =
-				    service_connect_blocking(EXCHANGE_PARALLEL,
-				    SERVICE_DEVMAN, DEVMAN_DRIVER, 0);
+				    service_connect_blocking(SERVICE_DEVMAN,
+				    INTERFACE_DDF_DRIVER, 0);
 		}
 		
@@ -99,5 +99,5 @@
 		
 		return async_exchange_begin(devman_driver_block_sess);
-	case DEVMAN_CLIENT:
+	case INTERFACE_DDF_CLIENT:
 		fibril_mutex_lock(&devman_client_block_mutex);
 		
@@ -108,6 +108,6 @@
 			if (devman_client_block_sess == NULL)
 				devman_client_block_sess =
-				    service_connect_blocking(EXCHANGE_SERIALIZE,
-				    SERVICE_DEVMAN, DEVMAN_CLIENT, 0);
+				    service_connect_blocking(SERVICE_DEVMAN,
+				    INTERFACE_DDF_CLIENT, 0);
 		}
 		
@@ -130,14 +130,14 @@
  *
  */
-async_exch_t *devman_exchange_begin(devman_interface_t iface)
+async_exch_t *devman_exchange_begin(iface_t iface)
 {
 	switch (iface) {
-	case DEVMAN_DRIVER:
+	case INTERFACE_DDF_DRIVER:
 		fibril_mutex_lock(&devman_driver_mutex);
 		
 		if (devman_driver_sess == NULL)
 			devman_driver_sess =
-			    service_connect(EXCHANGE_PARALLEL, SERVICE_DEVMAN,
-			    DEVMAN_DRIVER, 0);
+			    service_connect(SERVICE_DEVMAN,
+			    INTERFACE_DDF_DRIVER, 0);
 		
 		fibril_mutex_unlock(&devman_driver_mutex);
@@ -147,11 +147,11 @@
 		
 		return async_exchange_begin(devman_driver_sess);
-	case DEVMAN_CLIENT:
+	case INTERFACE_DDF_CLIENT:
 		fibril_mutex_lock(&devman_client_mutex);
 		
 		if (devman_client_sess == NULL)
 			devman_client_sess =
-			    service_connect(EXCHANGE_SERIALIZE, SERVICE_DEVMAN,
-			    DEVMAN_CLIENT, 0);
+			    service_connect(SERVICE_DEVMAN,
+			    INTERFACE_DDF_CLIENT, 0);
 		
 		fibril_mutex_unlock(&devman_client_mutex);
@@ -179,5 +179,5 @@
 int devman_driver_register(const char *name)
 {
-	async_exch_t *exch = devman_exchange_begin_blocking(DEVMAN_DRIVER);
+	async_exch_t *exch = devman_exchange_begin_blocking(INTERFACE_DDF_DRIVER);
 	
 	ipc_call_t answer;
@@ -192,6 +192,6 @@
 	}
 	
-	exch = devman_exchange_begin(DEVMAN_DRIVER);
-	async_connect_to_me(exch, 0, 0, 0, NULL, NULL);
+	exch = devman_exchange_begin(INTERFACE_DDF_DRIVER);
+	async_connect_to_me(exch, 0, 0, 0);
 	devman_exchange_end(exch);
 	
@@ -217,6 +217,6 @@
     match_id_list_t *match_ids, devman_handle_t devh, devman_handle_t *funh)
 {
-	int match_count = list_count(&match_ids->ids);
-	async_exch_t *exch = devman_exchange_begin_blocking(DEVMAN_DRIVER);
+	unsigned long match_count = list_count(&match_ids->ids);
+	async_exch_t *exch = devman_exchange_begin_blocking(INTERFACE_DDF_DRIVER);
 	
 	ipc_call_t answer;
@@ -268,5 +268,5 @@
     const char *cat_name)
 {
-	async_exch_t *exch = devman_exchange_begin_blocking(DEVMAN_DRIVER);
+	async_exch_t *exch = devman_exchange_begin_blocking(INTERFACE_DDF_DRIVER);
 	
 	ipc_call_t answer;
@@ -287,15 +287,14 @@
 }
 
-async_sess_t *devman_device_connect(exch_mgmt_t mgmt, devman_handle_t handle,
-    unsigned int flags)
+async_sess_t *devman_device_connect(devman_handle_t handle, unsigned int flags)
 {
 	async_sess_t *sess;
 	
 	if (flags & IPC_FLAG_BLOCKING)
-		sess = service_connect_blocking(mgmt, SERVICE_DEVMAN,
-			    DEVMAN_CONNECT_TO_DEVICE, handle);
+		sess = service_connect_blocking(SERVICE_DEVMAN,
+		    INTERFACE_DEVMAN_DEVICE, handle);
 	else
-		sess = service_connect(mgmt, SERVICE_DEVMAN,
-			    DEVMAN_CONNECT_TO_DEVICE, handle);
+		sess = service_connect(SERVICE_DEVMAN,
+		    INTERFACE_DEVMAN_DEVICE, handle);
 	
 	return sess;
@@ -314,5 +313,5 @@
 	sysarg_t retval;
 	
-	exch = devman_exchange_begin_blocking(DEVMAN_DRIVER);
+	exch = devman_exchange_begin_blocking(INTERFACE_DDF_DRIVER);
 	retval = async_req_1_0(exch, DEVMAN_REMOVE_FUNCTION, (sysarg_t) funh);
 	devman_exchange_end(exch);
@@ -323,5 +322,5 @@
 int devman_drv_fun_online(devman_handle_t funh)
 {
-	async_exch_t *exch = devman_exchange_begin(DEVMAN_DRIVER);
+	async_exch_t *exch = devman_exchange_begin(INTERFACE_DDF_DRIVER);
 	if (exch == NULL)
 		return ENOMEM;
@@ -335,5 +334,5 @@
 int devman_drv_fun_offline(devman_handle_t funh)
 {
-	async_exch_t *exch = devman_exchange_begin(DEVMAN_DRIVER);
+	async_exch_t *exch = devman_exchange_begin(INTERFACE_DDF_DRIVER);
 	if (exch == NULL)
 		return ENOMEM;
@@ -345,15 +344,15 @@
 }
 
-async_sess_t *devman_parent_device_connect(exch_mgmt_t mgmt,
-    devman_handle_t handle, unsigned int flags)
+async_sess_t *devman_parent_device_connect(devman_handle_t handle,
+    unsigned int flags)
 {
 	async_sess_t *sess;
 	
 	if (flags & IPC_FLAG_BLOCKING)
-		sess = service_connect_blocking(mgmt, SERVICE_DEVMAN,
-			    DEVMAN_CONNECT_TO_PARENTS_DEVICE, handle);
+		sess = service_connect_blocking(SERVICE_DEVMAN,
+		    INTERFACE_DEVMAN_PARENT, handle);
 	else
-		sess = service_connect(mgmt, SERVICE_DEVMAN,
-			    DEVMAN_CONNECT_TO_PARENTS_DEVICE, handle);
+		sess = service_connect_blocking(SERVICE_DEVMAN,
+		    INTERFACE_DEVMAN_PARENT, handle);
 	
 	return sess;
@@ -366,7 +365,7 @@
 	
 	if (flags & IPC_FLAG_BLOCKING)
-		exch = devman_exchange_begin_blocking(DEVMAN_CLIENT);
+		exch = devman_exchange_begin_blocking(INTERFACE_DDF_CLIENT);
 	else {
-		exch = devman_exchange_begin(DEVMAN_CLIENT);
+		exch = devman_exchange_begin(INTERFACE_DDF_CLIENT);
 		if (exch == NULL)
 			return ENOMEM;
@@ -409,5 +408,5 @@
 	sysarg_t dretval;
 	
-	exch = devman_exchange_begin_blocking(DEVMAN_CLIENT);
+	exch = devman_exchange_begin_blocking(INTERFACE_DDF_CLIENT);
 	
 	ipc_call_t answer;
@@ -474,5 +473,5 @@
 int devman_fun_online(devman_handle_t funh)
 {
-	async_exch_t *exch = devman_exchange_begin(DEVMAN_CLIENT);
+	async_exch_t *exch = devman_exchange_begin(INTERFACE_DDF_CLIENT);
 	if (exch == NULL)
 		return ENOMEM;
@@ -486,5 +485,5 @@
 int devman_fun_offline(devman_handle_t funh)
 {
-	async_exch_t *exch = devman_exchange_begin(DEVMAN_CLIENT);
+	async_exch_t *exch = devman_exchange_begin(INTERFACE_DDF_CLIENT);
 	if (exch == NULL)
 		return ENOMEM;
@@ -499,5 +498,5 @@
     devman_handle_t *handle_buf, size_t buf_size, size_t *act_size)
 {
-	async_exch_t *exch = devman_exchange_begin_blocking(DEVMAN_CLIENT);
+	async_exch_t *exch = devman_exchange_begin_blocking(INTERFACE_DDF_CLIENT);
 
 	ipc_call_t answer;
@@ -578,5 +577,5 @@
 int devman_fun_get_child(devman_handle_t funh, devman_handle_t *devh)
 {
-	async_exch_t *exch = devman_exchange_begin(DEVMAN_CLIENT);
+	async_exch_t *exch = devman_exchange_begin(INTERFACE_DDF_CLIENT);
 	if (exch == NULL)
 		return ENOMEM;
@@ -598,5 +597,5 @@
 int devman_dev_get_parent(devman_handle_t devh, devman_handle_t *funh)
 {
-	async_exch_t *exch = devman_exchange_begin(DEVMAN_CLIENT);
+	async_exch_t *exch = devman_exchange_begin(INTERFACE_DDF_CLIENT);
 	if (exch == NULL)
 		return ENOMEM;
@@ -611,5 +610,5 @@
 int devman_fun_sid_to_handle(service_id_t sid, devman_handle_t *handle)
 {
-	async_exch_t *exch = devman_exchange_begin(DEVMAN_CLIENT);
+	async_exch_t *exch = devman_exchange_begin(INTERFACE_DDF_CLIENT);
 	if (exch == NULL)
 		return ENOMEM;
@@ -639,5 +638,5 @@
 	async_exch_t *exch;
 
-	exch = devman_exchange_begin(DEVMAN_CLIENT);
+	exch = devman_exchange_begin(INTERFACE_DDF_CLIENT);
 	if (exch == NULL)
 		return ENOMEM;
@@ -694,5 +693,5 @@
 {
 	sysarg_t state;
-	async_exch_t *exch = devman_exchange_begin(DEVMAN_CLIENT);
+	async_exch_t *exch = devman_exchange_begin(INTERFACE_DDF_CLIENT);
 	if (exch == NULL)
 		return ENOMEM;
@@ -711,5 +710,5 @@
 int devman_driver_load(devman_handle_t drvh)
 {
-	async_exch_t *exch = devman_exchange_begin(DEVMAN_CLIENT);
+	async_exch_t *exch = devman_exchange_begin(INTERFACE_DDF_CLIENT);
 	if (exch == NULL)
 		return ENOMEM;
Index: uspace/lib/c/generic/dhcp.c
===================================================================
--- uspace/lib/c/generic/dhcp.c	(revision 9854a8faee04ea815f8612666a6e4dac63db2748)
+++ uspace/lib/c/generic/dhcp.c	(revision cffa82aac31c77f5d26f954922753c58edfef5f7)
@@ -56,5 +56,5 @@
 		return ENOENT;
 
-	dhcp_sess = loc_service_connect(EXCHANGE_SERIALIZE, dhcp_svc,
+	dhcp_sess = loc_service_connect(dhcp_svc, INTERFACE_DHCP,
 	    IPC_FLAG_BLOCKING);
 	if (dhcp_sess == NULL)
Index: uspace/lib/c/generic/dnsr.c
===================================================================
--- uspace/lib/c/generic/dnsr.c	(revision 9854a8faee04ea815f8612666a6e4dac63db2748)
+++ uspace/lib/c/generic/dnsr.c	(revision cffa82aac31c77f5d26f954922753c58edfef5f7)
@@ -52,5 +52,5 @@
 		    IPC_FLAG_BLOCKING);
 		
-		dnsr_sess = loc_service_connect(EXCHANGE_SERIALIZE, dnsr_svc,
+		dnsr_sess = loc_service_connect(dnsr_svc, INTERFACE_DNSR,
 		    IPC_FLAG_BLOCKING);
 	}
Index: uspace/lib/c/generic/elf/elf_load.c
===================================================================
--- uspace/lib/c/generic/elf/elf_load.c	(revision 9854a8faee04ea815f8612666a6e4dac63db2748)
+++ uspace/lib/c/generic/elf/elf_load.c	(revision cffa82aac31c77f5d26f954922753c58edfef5f7)
@@ -97,5 +97,5 @@
 	int fd;
 	int rc;
-	
+
 	fd = open(file_name, O_RDONLY);
 	if (fd < 0) {
@@ -147,5 +147,5 @@
 	int i, rc;
 
-	rc = read_all(elf->fd, header, sizeof(elf_header_t));
+	rc = read(elf->fd, header, sizeof(elf_header_t));
 	if (rc != sizeof(elf_header_t)) {
 		DPRINTF("Read error.\n"); 
@@ -209,5 +209,5 @@
 		        + i * sizeof(elf_segment_header_t), SEEK_SET);
 
-		rc = read_all(elf->fd, &segment_hdr,
+		rc = read(elf->fd, &segment_hdr,
 		    sizeof(elf_segment_header_t));
 		if (rc != sizeof(elf_segment_header_t)) {
@@ -231,5 +231,5 @@
 		    + i * sizeof(elf_section_header_t), SEEK_SET);
 
-		rc = read_all(elf->fd, &section_hdr,
+		rc = read(elf->fd, &section_hdr,
 		    sizeof(elf_section_header_t));
 		if (rc != sizeof(elf_section_header_t)) {
@@ -399,5 +399,5 @@
 		if (now > left) now = left;
 
-		rc = read_all(elf->fd, dp, now);
+		rc = read(elf->fd, dp, now);
 
 		if (rc != (ssize_t) now) { 
Index: uspace/lib/c/generic/inet.c
===================================================================
--- uspace/lib/c/generic/inet.c	(revision 9854a8faee04ea815f8612666a6e4dac63db2748)
+++ uspace/lib/c/generic/inet.c	(revision cffa82aac31c77f5d26f954922753c58edfef5f7)
@@ -48,5 +48,9 @@
 	ipc_call_t answer;
 	aid_t req = async_send_0(exch, INET_CALLBACK_CREATE, &answer);
-	int rc = async_connect_to_me(exch, 0, 0, 0, inet_cb_conn, NULL);
+	
+	port_id_t port;
+	int rc = async_create_callback_port(exch, INTERFACE_INET_CB, 0, 0,
+	    inet_cb_conn, NULL, &port);
+	
 	async_exchange_end(exch);
 	
@@ -83,5 +87,5 @@
 		return ENOENT;
 	
-	inet_sess = loc_service_connect(EXCHANGE_SERIALIZE, inet_svc,
+	inet_sess = loc_service_connect(inet_svc, INTERFACE_INET,
 	    IPC_FLAG_BLOCKING);
 	if (inet_sess == NULL)
Index: uspace/lib/c/generic/inet/addr.c
===================================================================
--- uspace/lib/c/generic/inet/addr.c	(revision 9854a8faee04ea815f8612666a6e4dac63db2748)
+++ uspace/lib/c/generic/inet/addr.c	(revision cffa82aac31c77f5d26f954922753c58edfef5f7)
@@ -306,5 +306,5 @@
 		i++;
 
-		if (*cur == '\0')
+		if (*cur == '\0' || *cur == '/')
 			break;
 
@@ -317,4 +317,8 @@
 
 	if (prefix != NULL) {
+		if (*cur != '/')
+			return EINVAL;
+		cur++;
+
 		*prefix = strtoul(cur, &cur, 10);
 		if (*prefix > 32)
Index: uspace/lib/c/generic/inet/endpoint.c
===================================================================
--- uspace/lib/c/generic/inet/endpoint.c	(revision 9854a8faee04ea815f8612666a6e4dac63db2748)
+++ uspace/lib/c/generic/inet/endpoint.c	(revision cffa82aac31c77f5d26f954922753c58edfef5f7)
@@ -36,4 +36,10 @@
 #include <mem.h>
 
+/** Initialize endpoint structure.
+ *
+ * Sets any address, any port number.
+ *
+ * @param ep Endpoint
+ */
 void inet_ep_init(inet_ep_t *ep)
 {
@@ -41,4 +47,10 @@
 }
 
+/** Initialize endpoint pair structure.
+ *
+ * Sets any address, any port number for both local and remote sides.
+ *
+ * @param ep2 Endpoint pair
+ */
 void inet_ep2_init(inet_ep2_t *ep2)
 {
Index: uspace/lib/c/generic/inet/tcp.c
===================================================================
--- uspace/lib/c/generic/inet/tcp.c	(revision 9854a8faee04ea815f8612666a6e4dac63db2748)
+++ uspace/lib/c/generic/inet/tcp.c	(revision cffa82aac31c77f5d26f954922753c58edfef5f7)
@@ -44,10 +44,21 @@
 static int tcp_conn_fibril(void *);
 
-/** Incoming TCP connection info */
+/** Incoming TCP connection info
+ *
+ * Used to pass information about incoming TCP connection to the connection
+ * fibril
+ */
 typedef struct {
+	/** Listener who received the connection */
 	tcp_listener_t *lst;
+	/** Incoming connection */
 	tcp_conn_t *conn;
 } tcp_in_conn_t;
 
+/** Create callback connection from TCP service.
+ *
+ * @param tcp TCP service
+ * @return EOK on success or negative error code
+ */
 static int tcp_callback_create(tcp_t *tcp)
 {
@@ -55,5 +66,9 @@
 
 	aid_t req = async_send_0(exch, TCP_CALLBACK_CREATE, NULL);
-	int rc = async_connect_to_me(exch, 0, 0, 0, tcp_cb_conn, tcp);
+	
+	port_id_t port;
+	int rc = async_create_callback_port(exch, INTERFACE_TCP_CB, 0, 0,
+	    tcp_cb_conn, tcp, &port);
+	
 	async_exchange_end(exch);
 
@@ -67,4 +82,10 @@
 }
 
+/** Create TCP client instance.
+ *
+ * @param  rtcp Place to store pointer to new TCP client
+ * @return EOK on success, ENOMEM if out of memory, EIO if service
+ *         cannot be contacted
+ */
 int tcp_create(tcp_t **rtcp)
 {
@@ -91,5 +112,5 @@
 	}
 
-	tcp->sess = loc_service_connect(EXCHANGE_SERIALIZE, tcp_svcid,
+	tcp->sess = loc_service_connect(tcp_svcid, INTERFACE_TCP,
 	    IPC_FLAG_BLOCKING);
 	if (tcp->sess == NULL) {
@@ -111,4 +132,8 @@
 }
 
+/** Destroy TCP client instance.
+ *
+ * @param tcp TCP client
+ */
 void tcp_destroy(tcp_t *tcp)
 {
@@ -126,4 +151,14 @@
 }
 
+/** Create new TCP connection
+ *
+ * @param tcp   TCP client instance
+ * @param id    Connection ID
+ * @param cb    Callbacks
+ * @param arg   Callback argument
+ * @param rconn Place to store pointer to new connection
+ *
+ * @return EOK on success, ENOMEM if out of memory
+ */
 static int tcp_conn_new(tcp_t *tcp, sysarg_t id, tcp_cb_t *cb, void *arg,
     tcp_conn_t **rconn)
@@ -150,4 +185,26 @@
 }
 
+/** Create new TCP connection.
+ *
+ * Open a connection to the specified destination. This function returns
+ * even before the connection is established (or not). When the connection
+ * is established, @a cb->connected is called. If the connection fails,
+ * @a cb->conn_failed is called. Alternatively, the caller can call
+ * @c tcp_conn_wait_connected() to wait for connection to complete or fail.
+ * Other callbacks are available to monitor the changes in connection state.
+ *
+ * @a epp must specify the remote address and port. Both local address and
+ * port are optional. If local address is not specified, address selection
+ * will take place. If local port number is not specified, a suitable
+ * free dynamic port number will be allocated.
+ *
+ * @param tcp   TCP client
+ * @param epp   Internet endpoint pair
+ * @param cb    Callbacks
+ * @param arg   Argument to callbacks
+ * @param rconn Place to store pointer to new connection
+ *
+ * @return EOK on success or negative error code.
+ */
 int tcp_conn_create(tcp_t *tcp, inet_ep2_t *epp, tcp_cb_t *cb, void *arg,
     tcp_conn_t **rconn)
@@ -186,4 +243,11 @@
 }
 
+/** Destroy TCP connection.
+ *
+ * Destroy TCP connection. The caller should destroy all connections
+ * he created before destroying the TCP client and before terminating.
+ *
+ * @param conn TCP connection
+ */
 void tcp_conn_destroy(tcp_conn_t *conn)
 {
@@ -203,4 +267,12 @@
 }
 
+/** Get connection based on its ID.
+ *
+ * @param tcp   TCP client
+ * @param id    Connection ID
+ * @param rconn Place to store pointer to connection
+ *
+ * @return EOK on success, EINVAL if no connection with the given ID exists
+ */
 static int tcp_conn_get(tcp_t *tcp, sysarg_t id, tcp_conn_t **rconn)
 {
@@ -215,4 +287,9 @@
 }
 
+/** Get the user/callback argument for a connection.
+ *
+ * @param conn TCP connection
+ * @return User argument associated with connection
+ */
 void *tcp_conn_userptr(tcp_conn_t *conn)
 {
@@ -220,4 +297,25 @@
 }
 
+/** Create a TCP connection listener.
+ *
+ * A listener listens for connections on the set of endpoints specified
+ * by @a ep. Each time a new incoming connection is established,
+ * @a lcb->new_conn is called (and passed @a larg). Also, the new connection
+ * will have callbacks set to @a cb and argument to @a arg.
+ *
+ * @a ep must specify a valid port number. @a ep may specify an address
+ * or link to listen on. If it does not, the listener will listen on
+ * all links/addresses.
+ *
+ * @param tcp  TCP client
+ * @param ep   Internet endpoint
+ * @param lcb  Listener callbacks
+ * @param larg Listener callback argument
+ * @param cb   Connection callbacks for every new connection
+ * @param arg  Connection argument for every new connection
+ * @param rlst Place to store pointer to new listener
+ *
+ * @return EOK on success or negative error code
+ */
 int tcp_listener_create(tcp_t *tcp, inet_ep_t *ep, tcp_listen_cb_t *lcb,
     void *larg, tcp_cb_t *cb, void *arg, tcp_listener_t **rlst)
@@ -265,4 +363,8 @@
 }
 
+/** Destroy TCP connection listener.
+ *
+ * @param lst Listener
+ */
 void tcp_listener_destroy(tcp_listener_t *lst)
 {
@@ -282,4 +384,12 @@
 }
 
+/** Get TCP connection listener based on its ID.
+ *
+ * @param tcp TCP client
+ * @param id  Listener ID
+ * @param rlst Place to store pointer to listener
+ *
+ * @return EOK on success, EINVAL if no listener with the given ID is found
+ */
 static int tcp_listener_get(tcp_t *tcp, sysarg_t id, tcp_listener_t **rlst)
 {
@@ -294,4 +404,9 @@
 }
 
+/** Get callback/user argument associated with listener.
+ *
+ * @param lst Listener
+ * @return Callback/user argument
+ */
 void *tcp_listener_userptr(tcp_listener_t *lst)
 {
@@ -299,4 +414,14 @@
 }
 
+/** Wait until connection is either established or connection fails.
+ *
+ * Can be called after calling tcp_conn_create() to block until connection
+ * either completes or fails. If the connection fails, EIO is returned.
+ * In this case the connection still exists, but is in a failed
+ * state.
+ *
+ * @param conn Connection
+ * @return EOK if connection is established, EIO otherwise
+ */
 int tcp_conn_wait_connected(tcp_conn_t *conn)
 {
@@ -315,4 +440,12 @@
 }
 
+/** Send data over TCP connection.
+ *
+ * @param conn  Connection
+ * @param data  Data
+ * @param bytes Data size in bytes
+ *
+ * @return EOK on success or negative error code
+ */
 int tcp_conn_send(tcp_conn_t *conn, const void *data, size_t bytes)
 {
@@ -340,5 +473,11 @@
 }
 
-
+/** Send FIN.
+ *
+ * Send FIN, indicating no more data will be send over the connection.
+ *
+ * @param conn Connection
+ * @return EOK on success or negative error code
+ */
 int tcp_conn_send_fin(tcp_conn_t *conn)
 {
@@ -352,4 +491,9 @@
 }
 
+/** Push connection.
+ *
+ * @param conn Connection
+ * @return EOK on success or negative error code
+ */
 int tcp_conn_push(tcp_conn_t *conn)
 {
@@ -363,4 +507,9 @@
 }
 
+/** Reset connection.
+ *
+ * @param conn Connection
+ * @return EOK on success or negative error code
+ */
 int tcp_conn_reset(tcp_conn_t *conn)
 {
@@ -374,4 +523,21 @@
 }
 
+/** Read received data from connection without blocking.
+ *
+ * If any received data is pending on the connection, up to @a bsize bytes
+ * are copied to @a buf and the acutal number is stored in @a *nrecv.
+ * The entire buffer of @a bsize bytes is filled except when less data
+ * is currently available or FIN is received. EOK is returned.
+ *
+ * If no received data is pending, returns EAGAIN.
+ *
+ * @param conn Connection
+ * @param buf  Buffer
+ * @param bsize Buffer size
+ * @param nrecv Place to store actual number of received bytes
+ *
+ * @return EOK on success, EAGAIN if no received data is pending, or other
+ *         negative error code in case of other error
+ */
 int tcp_conn_recv(tcp_conn_t *conn, void *buf, size_t bsize, size_t *nrecv)
 {
@@ -408,5 +574,20 @@
 }
 
-int tcp_conn_recv_wait(tcp_conn_t *conn, void *buf, size_t bsize, size_t *nrecv)
+/** Read received data from connection with blocking.
+ *
+ * Wait for @a bsize bytes of data to be received and copy them to
+ * @a buf. Less data may be returned if FIN is received on the connection.
+ * The actual If any received data is written to @a *nrecv and EOK
+ * is returned on success.
+ *
+ * @param conn Connection
+ * @param buf  Buffer
+ * @param bsize Buffer size
+ * @param nrecv Place to store actual number of received bytes
+ *
+ * @return EOK on success or negative error code
+ */
+int tcp_conn_recv_wait(tcp_conn_t *conn, void *buf, size_t bsize,
+    size_t *nrecv)
 {
 	async_exch_t *exch;
@@ -450,4 +631,10 @@
 }
 
+/** Connection established event.
+ *
+ * @param tcp TCP client
+ * @param iid Call ID
+ * @param icall Call data
+ */
 static void tcp_ev_connected(tcp_t *tcp, ipc_callid_t iid, ipc_call_t *icall)
 {
@@ -472,4 +659,10 @@
 }
 
+/** Connection failed event.
+ *
+ * @param tcp TCP client
+ * @param iid Call ID
+ * @param icall Call data
+ */
 static void tcp_ev_conn_failed(tcp_t *tcp, ipc_callid_t iid, ipc_call_t *icall)
 {
@@ -494,4 +687,10 @@
 }
 
+/** Connection reset event.
+ *
+ * @param tcp TCP client
+ * @param iid Call ID
+ * @param icall Call data
+ */
 static void tcp_ev_conn_reset(tcp_t *tcp, ipc_callid_t iid, ipc_call_t *icall)
 {
@@ -516,4 +715,10 @@
 }
 
+/** Data available event.
+ *
+ * @param tcp TCP client
+ * @param iid Call ID
+ * @param icall Call data
+ */
 static void tcp_ev_data(tcp_t *tcp, ipc_callid_t iid, ipc_call_t *icall)
 {
@@ -539,4 +744,10 @@
 }
 
+/** Urgent data event.
+ *
+ * @param tcp TCP client
+ * @param iid Call ID
+ * @param icall Call data
+ */
 static void tcp_ev_urg_data(tcp_t *tcp, ipc_callid_t iid, ipc_call_t *icall)
 {
@@ -544,4 +755,10 @@
 }
 
+/** New connection event.
+ *
+ * @param tcp TCP client
+ * @param iid Call ID
+ * @param icall Call data
+ */
 static void tcp_ev_new_conn(tcp_t *tcp, ipc_callid_t iid, ipc_call_t *icall)
 {
@@ -590,4 +807,10 @@
 }
 
+/** Callback connection handler.
+ *
+ * @param iid Connect call ID
+ * @param icall Connect call data
+ * @param arg Argument, TCP client
+ */
 static void tcp_cb_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
 {
@@ -636,5 +859,8 @@
 }
 
-/** Fibril for handling incoming TCP connection in background */
+/** Fibril for handling incoming TCP connection in background.
+ *
+ * @param arg Argument, incoming connection information (@c tcp_in_conn_t)
+ */
 static int tcp_conn_fibril(void *arg)
 {
Index: uspace/lib/c/generic/inet/udp.c
===================================================================
--- uspace/lib/c/generic/inet/udp.c	(revision 9854a8faee04ea815f8612666a6e4dac63db2748)
+++ uspace/lib/c/generic/inet/udp.c	(revision cffa82aac31c77f5d26f954922753c58edfef5f7)
@@ -43,4 +43,9 @@
 static void udp_cb_conn(ipc_callid_t, ipc_call_t *, void *);
 
+/** Create callback connection from UDP service.
+ *
+ * @param udp UDP service
+ * @return EOK on success or negative error code
+ */
 static int udp_callback_create(udp_t *udp)
 {
@@ -48,5 +53,9 @@
 
 	aid_t req = async_send_0(exch, UDP_CALLBACK_CREATE, NULL);
-	int rc = async_connect_to_me(exch, 0, 0, 0, udp_cb_conn, udp);
+	
+	port_id_t port;
+	int rc = async_create_callback_port(exch, INTERFACE_UDP_CB, 0, 0,
+	    udp_cb_conn, udp, &port);
+	
 	async_exchange_end(exch);
 
@@ -60,4 +69,10 @@
 }
 
+/** Create UDP client instance.
+ *
+ * @param  rudp Place to store pointer to new UDP client
+ * @return EOK on success, ENOMEM if out of memory, EIO if service
+ *         cannot be contacted
+ */
 int udp_create(udp_t **rudp)
 {
@@ -83,5 +98,5 @@
 	}
 
-	udp->sess = loc_service_connect(EXCHANGE_SERIALIZE, udp_svcid,
+	udp->sess = loc_service_connect(udp_svcid, INTERFACE_UDP,
 	    IPC_FLAG_BLOCKING);
 	if (udp->sess == NULL) {
@@ -103,4 +118,8 @@
 }
 
+/** Destroy UDP client instance.
+ *
+ * @param udp UDP client
+ */
 void udp_destroy(udp_t *udp)
 {
@@ -118,5 +137,28 @@
 }
 
-int udp_assoc_create(udp_t *udp, inet_ep2_t *ep2, udp_cb_t *cb, void *arg,
+/** Create new UDP association.
+ *
+ * Create a UDP association that allows sending and receiving messages.
+ *
+ * @a epp may specify remote address and port, in which case only messages
+ * from that remote endpoint will be received. Also, that remote endpoint
+ * is used as default when @c NULL is passed as destination to
+ * udp_assoc_send_msg.
+ *
+ * @a epp may specify a local link or address. If it does not, the association
+ * will listen on all local links/addresses. If @a epp does not specify
+ * a local port number, a free dynamic port number will be allocated.
+ *
+ * The caller is informed about incoming data by invoking @a cb->recv_msg
+ *
+ * @param udp    UDP client
+ * @param epp    Internet endpoint pair
+ * @param cb     Callbacks
+ * @param arg    Argument to callbacks
+ * @param rassoc Place to store pointer to new association
+ *
+ * @return EOK on success or negative error code.
+ */
+int udp_assoc_create(udp_t *udp, inet_ep2_t *epp, udp_cb_t *cb, void *arg,
     udp_assoc_t **rassoc)
 {
@@ -131,5 +173,5 @@
 	exch = async_exchange_begin(udp->sess);
 	aid_t req = async_send_0(exch, UDP_ASSOC_CREATE, &answer);
-	sysarg_t rc = async_data_write_start(exch, (void *)ep2,
+	sysarg_t rc = async_data_write_start(exch, (void *)epp,
 	    sizeof(inet_ep2_t));
 	async_exchange_end(exch);
@@ -161,4 +203,11 @@
 }
 
+/** Destroy UDP association.
+ *
+ * Destroy UDP association. The caller should destroy all associations
+ * he created before destroying the UDP client and before terminating.
+ *
+ * @param assoc UDP association
+ */
 void udp_assoc_destroy(udp_assoc_t *assoc)
 {
@@ -178,4 +227,13 @@
 }
 
+/** Send message via UDP association.
+ *
+ * @param assoc Association
+ * @param dest	Destination endpoint or @c NULL to use association's remote ep.
+ * @param data	Message data
+ * @param bytes Message size in bytes
+ *
+ * @return EOK on success or negative error code
+ */
 int udp_assoc_send_msg(udp_assoc_t *assoc, inet_ep_t *dest, void *data,
     size_t bytes)
@@ -211,4 +269,9 @@
 }
 
+/** Get the user/callback argument for an association.
+ *
+ * @param assoc UDP association
+ * @return User argument associated with association
+ */
 void *udp_assoc_userptr(udp_assoc_t *assoc)
 {
@@ -216,4 +279,13 @@
 }
 
+/** Get size of received message in bytes.
+ *
+ * Assuming jumbo messages can be received, the caller first needs to determine
+ * the size of the received message by calling this function, then they can
+ * read the message piece-wise using udp_rmsg_read().
+ *
+ * @param rmsg Received message
+ * @return Size of received message in bytes
+ */
 size_t udp_rmsg_size(udp_rmsg_t *rmsg)
 {
@@ -221,4 +293,13 @@
 }
 
+/** Read part of received message.
+ *
+ * @param rmsg  Received message
+ * @param off   Start offset
+ * @param buf   Buffer for storing data
+ * @param bsize Buffer size
+ *
+ * @return EOK on success or negative error code.
+ */
 int udp_rmsg_read(udp_rmsg_t *rmsg, size_t off, void *buf, size_t bsize)
 {
@@ -245,4 +326,12 @@
 }
 
+/** Get remote endpoint of received message.
+ *
+ * Place the remote endpoint (the one from which the message was supposedly
+ * sent) to @a ep.
+ *
+ * @param rmsg Received message
+ * @param ep   Place to store remote endpoint
+ */
 void udp_rmsg_remote_ep(udp_rmsg_t *rmsg, inet_ep_t *ep)
 {
@@ -250,4 +339,9 @@
 }
 
+/** Get type of received ICMP error message.
+ *
+ * @param rerr Received error message
+ * @return Error message type
+ */
 uint8_t udp_rerr_type(udp_rerr_t *rerr)
 {
@@ -255,4 +349,9 @@
 }
 
+/** Get code of received ICMP error message.
+ *
+ * @param rerr Received error message
+ * @return Error message code
+ */
 uint8_t udp_rerr_code(udp_rerr_t *rerr)
 {
@@ -260,4 +359,11 @@
 }
 
+/** Get information about the next received message from UDP service.
+ *
+ * @param udp  UDP client
+ * @param rmsg Place to store message information
+ *
+ * @return EOK on success or negative error code
+ */
 static int udp_rmsg_info(udp_t *udp, udp_rmsg_t *rmsg)
 {
@@ -288,4 +394,9 @@
 }
 
+/** Discard next received message in UDP service.
+ *
+ * @param udp UDP client
+ * @return EOK on success or negative error code
+ */
 static int udp_rmsg_discard(udp_t *udp)
 {
@@ -299,4 +410,12 @@
 }
 
+/** Get association based on its ID.
+ *
+ * @param udp    UDP client
+ * @param id     Association ID
+ * @param rassoc Place to store pointer to association
+ *
+ * @return EOK on success, EINVAL if no association with the given ID exists
+ */
 static int udp_assoc_get(udp_t *udp, sysarg_t id, udp_assoc_t **rassoc)
 {
@@ -311,4 +430,13 @@
 }
 
+/** Handle 'data' event, i.e. some message(s) arrived.
+ *
+ * For each received message, get information about it, call @c recv_msg
+ * callback and discard it.
+ *
+ * @param udp UDP client
+ * @param iid IPC message ID
+ * @param icall IPC message
+ */
 static void udp_ev_data(udp_t *udp, ipc_callid_t iid, ipc_call_t *icall)
 {
@@ -340,4 +468,10 @@
 }
 
+/** UDP service callback connection.
+ *
+ * @param iid Connect message ID
+ * @param icall Connect message
+ * @param arg Argument, UDP client
+ */
 static void udp_cb_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
 {
Index: uspace/lib/c/generic/inetcfg.c
===================================================================
--- uspace/lib/c/generic/inetcfg.c	(revision 9854a8faee04ea815f8612666a6e4dac63db2748)
+++ uspace/lib/c/generic/inetcfg.c	(revision cffa82aac31c77f5d26f954922753c58edfef5f7)
@@ -120,10 +120,10 @@
 	assert(inetcfg_sess == NULL);
 	
-	rc = loc_service_get_id(SERVICE_NAME_INETCFG, &inet_svc,
+	rc = loc_service_get_id(SERVICE_NAME_INET, &inet_svc,
 	    IPC_FLAG_BLOCKING);
 	if (rc != EOK)
 		return ENOENT;
 	
-	inetcfg_sess = loc_service_connect(EXCHANGE_SERIALIZE, inet_svc,
+	inetcfg_sess = loc_service_connect(inet_svc, INTERFACE_INETCFG,
 	    IPC_FLAG_BLOCKING);
 	if (inetcfg_sess == NULL)
Index: uspace/lib/c/generic/inetping.c
===================================================================
--- uspace/lib/c/generic/inetping.c	(revision 9854a8faee04ea815f8612666a6e4dac63db2748)
+++ uspace/lib/c/generic/inetping.c	(revision cffa82aac31c77f5d26f954922753c58edfef5f7)
@@ -53,10 +53,10 @@
 	inetping_ev_ops = ev_ops;
 
-	rc = loc_service_get_id(SERVICE_NAME_INETPING, &inetping_svc,
+	rc = loc_service_get_id(SERVICE_NAME_INET, &inetping_svc,
 	    IPC_FLAG_BLOCKING);
 	if (rc != EOK)
 		return ENOENT;
 
-	inetping_sess = loc_service_connect(EXCHANGE_SERIALIZE, inetping_svc,
+	inetping_sess = loc_service_connect(inetping_svc, INTERFACE_INETPING,
 	    IPC_FLAG_BLOCKING);
 	if (inetping_sess == NULL)
@@ -65,5 +65,8 @@
 	async_exch_t *exch = async_exchange_begin(inetping_sess);
 
-	rc = async_connect_to_me(exch, 0, 0, 0, inetping_cb_conn, NULL);
+	port_id_t port;
+	rc = async_create_callback_port(exch, INTERFACE_INETPING_CB, 0, 0,
+	    inetping_cb_conn, NULL, &port);
+	
 	async_exchange_end(exch);
 
Index: uspace/lib/c/generic/io/console.c
===================================================================
--- uspace/lib/c/generic/io/console.c	(revision 9854a8faee04ea815f8612666a6e4dac63db2748)
+++ uspace/lib/c/generic/io/console.c	(revision cffa82aac31c77f5d26f954922753c58edfef5f7)
@@ -49,5 +49,5 @@
 		return NULL;
 	
-	ctrl->input_sess = fsession(EXCHANGE_SERIALIZE, ifile);
+	ctrl->input_sess = vfs_fsession(ifile, INTERFACE_CONSOLE);
 	if (!ctrl->input_sess) {
 		free(ctrl);
@@ -55,5 +55,5 @@
 	}
 	
-	ctrl->output_sess = fsession(EXCHANGE_SERIALIZE, ofile);
+	ctrl->output_sess = vfs_fsession(ofile, INTERFACE_CONSOLE);
 	if (!ctrl->output_sess) {
 		free(ctrl);
Index: uspace/lib/c/generic/io/input.c
===================================================================
--- uspace/lib/c/generic/io/input.c	(revision 9854a8faee04ea815f8612666a6e4dac63db2748)
+++ uspace/lib/c/generic/io/input.c	(revision cffa82aac31c77f5d26f954922753c58edfef5f7)
@@ -58,5 +58,8 @@
 	async_exch_t *exch = async_exchange_begin(sess);
 
-	int rc = async_connect_to_me(exch, 0, 0, 0, input_cb_conn, input);
+	port_id_t port;
+	int rc = async_create_callback_port(exch, INTERFACE_INPUT_CB, 0, 0,
+	    input_cb_conn, input, &port);
+	
 	async_exchange_end(exch);
 
Index: uspace/lib/c/generic/io/io.c
===================================================================
--- uspace/lib/c/generic/io/io.c	(revision 9854a8faee04ea815f8612666a6e4dac63db2748)
+++ uspace/lib/c/generic/io/io.c	(revision cffa82aac31c77f5d26f954922753c58edfef5f7)
@@ -231,5 +231,5 @@
 	if (stream->buf == NULL) {
 		errno = ENOMEM;
-		return -1;
+		return EOF;
 	}
 	
@@ -299,5 +299,6 @@
 }
 
-int fclose(FILE *stream)
+
+static int _fclose_nofree(FILE *stream)
 {
 	int rc = 0;
@@ -312,4 +313,16 @@
 	
 	list_remove(&stream->link);
+	
+	if (rc != 0) {
+		/* errno was set by close() */
+		return EOF;
+	}
+	
+	return 0;
+}
+
+int fclose(FILE *stream)
+{
+	int rc = _fclose_nofree(stream);
 	
 	if ((stream != &stdin_null)
@@ -318,12 +331,30 @@
 		free(stream);
 	
-	stream = NULL;
-	
-	if (rc != 0) {
-		/* errno was set by close() */
-		return EOF;
-	}
-	
-	return 0;
+	return rc;
+}
+
+FILE *freopen(const char *path, const char *mode, FILE *stream)
+{
+	FILE *nstr;
+	
+	if (path == NULL) {
+		/* Changing mode is not supported */
+		return NULL;
+	}
+	
+	(void) _fclose_nofree(stream);
+	nstr = fopen(path, mode);
+	if (nstr == NULL) {
+		free(stream);
+		return NULL;
+	}
+	
+	list_remove(&nstr->link);
+	*stream = *nstr;
+	list_append(&stream->link, &files);
+	
+	free(nstr);
+	
+	return stream;
 }
 
@@ -334,4 +365,7 @@
  * @param nmemb  Number of records to read.
  * @param stream Pointer to the stream.
+ *
+ * @return Number of elements successfully read. On error this is less than
+ *         nmemb, stream error indicator is set and errno is set.
  */
 static size_t _fread(void *buf, size_t size, size_t nmemb, FILE *stream)
@@ -348,9 +382,10 @@
 		ssize_t rd = read(stream->fd, buf + done, left);
 		
-		if (rd < 0)
+		if (rd < 0) {
+			/* errno was set by read() */
 			stream->error = true;
-		else if (rd == 0)
+		} else if (rd == 0) {
 			stream->eof = true;
-		else {
+		} else {
 			left -= rd;
 			done += rd;
@@ -367,4 +402,7 @@
  * @param nmemb  Number of records to write.
  * @param stream Pointer to the stream.
+ *
+ * @return Number of elements successfully written. On error this is less than
+ *         nmemb, stream error indicator is set and errno is set.
  */
 static size_t _fwrite(const void *buf, size_t size, size_t nmemb, FILE *stream)
@@ -372,4 +410,5 @@
 	size_t left;
 	size_t done;
+	int rc;
 
 	if (size == 0 || nmemb == 0)
@@ -381,15 +420,29 @@
 	while ((left > 0) && (!stream->error)) {
 		ssize_t wr;
+		size_t uwr;
 		
-		if (stream->kio)
-			wr = kio_write(buf + done, left);
-		else
+		if (stream->kio) {
+			uwr = 0;
+			rc = kio_write(buf + done, left, &uwr);
+			if (rc != EOK)
+				errno = rc;
+		} else {
 			wr = write(stream->fd, buf + done, left);
+			if (wr >= 0) {
+				uwr = (size_t)wr;
+				rc = EOK;
+			} else {
+				/* errno was set by write */
+				uwr = 0;
+				rc = errno;
+			}
+		}
 		
-		if (wr <= 0)
+		if (rc != EOK) {
+			/* errno was set above */
 			stream->error = true;
-		else {
-			left -= wr;
-			done += wr;
+		} else {
+			left -= uwr;
+			done += uwr;
 		}
 	}
@@ -401,5 +454,8 @@
 }
 
-/** Read some data in stream buffer. */
+/** Read some data in stream buffer.
+ *
+ * On error, stream error indicator is set and errno is set.
+ */
 static void _ffillbuf(FILE *stream)
 {
@@ -410,4 +466,5 @@
 	rc = read(stream->fd, stream->buf, stream->buf_size);
 	if (rc < 0) {
+		/* errno was set by read() */
 		stream->error = true;
 		return;
@@ -434,10 +491,21 @@
 
 	/* If buffer has prefetched read data, we need to seek back. */
-	if (bytes_used > 0 && stream->buf_state == _bs_read)
-		lseek(stream->fd, - (ssize_t) bytes_used, SEEK_CUR);
+	if (bytes_used > 0 && stream->buf_state == _bs_read) {
+		off64_t rc;
+		rc = lseek(stream->fd, - (ssize_t) bytes_used, SEEK_CUR);
+		if (rc == (off64_t)-1) {
+			/* errno was set by lseek */
+			stream->error = 1;
+			return;
+		}
+	}
 
 	/* If buffer has unwritten data, we need to write them out. */
-	if (bytes_used > 0 && stream->buf_state == _bs_write)
+	if (bytes_used > 0 && stream->buf_state == _bs_write) {
 		(void) _fwrite(stream->buf_tail, 1, bytes_used, stream);
+		/* On error stream error indicator and errno are set by _fwrite */
+		if (stream->error)
+			return;
+	}
 
 	stream->buf_head = stream->buf;
@@ -466,8 +534,19 @@
 		return 0;
 
+	bytes_left = size * nmemb;
+	total_read = 0;
+	dp = (uint8_t *) dest;
+
+	/* Bytes from ungetc() buffer */
+	while (stream->ungetc_chars > 0 && bytes_left > 0) {
+		*dp++ = stream->ungetc_buf[--stream->ungetc_chars];
+		++total_read;
+		--bytes_left;
+	}
+
 	/* If not buffered stream, read in directly. */
 	if (stream->btype == _IONBF) {
-		now = _fread(dest, size, nmemb, stream);
-		return now;
+		total_read += _fread(dest, 1, bytes_left, stream);
+		return total_read / size;
 	}
 
@@ -482,14 +561,12 @@
 	}
 
-	bytes_left = size * nmemb;
-	total_read = 0;
-	dp = (uint8_t *) dest;
-
 	while ((!stream->error) && (!stream->eof) && (bytes_left > 0)) {
 		if (stream->buf_head == stream->buf_tail)
 			_ffillbuf(stream);
 
-		if (stream->error || stream->eof)
+		if (stream->error || stream->eof) {
+			/* On error errno was set by _ffillbuf() */
 			break;
+		}
 
 		data_avail = stream->buf_head - stream->buf_tail;
@@ -546,5 +623,4 @@
 	if (stream->buf_state == _bs_read)
 		_fflushbuf(stream);
-
 
 	/* Perform lazy allocation of stream buffer. */
@@ -584,5 +660,6 @@
 			/* Only need to drain buffer. */
 			_fflushbuf(stream);
-			need_flush = false;
+			if (!stream->error)
+				need_flush = false;
 		}
 	}
@@ -618,5 +695,8 @@
 int fputs(const char *str, FILE *stream)
 {
-	return fwrite(str, str_size(str), 1, stream);
+	(void) fwrite(str, str_size(str), 1, stream);
+	if (ferror(stream))
+		return EOF;
+	return 0;
 }
 
@@ -674,14 +754,38 @@
 }
 
+int ungetc(int c, FILE *stream)
+{
+	if (c == EOF)
+		return EOF;
+
+	if (stream->ungetc_chars >= UNGETC_MAX)
+		return EOF;
+
+	stream->ungetc_buf[stream->ungetc_chars++] =
+	    (uint8_t)c;
+
+	stream->eof = false;
+	return (uint8_t)c;
+}
+
 int fseek(FILE *stream, off64_t offset, int whence)
 {
 	off64_t rc;
 
+	if (stream->error)
+		return EOF;
+
 	_fflushbuf(stream);
+	if (stream->error) {
+		/* errno was set by _fflushbuf() */
+		return EOF;
+	}
+
+	stream->ungetc_chars = 0;
 
 	rc = lseek(stream->fd, offset, whence);
 	if (rc == (off64_t) (-1)) {
-		/* errno has been set by lseek64. */
-		return -1;
+		/* errno has been set by lseek() */
+		return EOF;
 	}
 
@@ -692,6 +796,22 @@
 off64_t ftell(FILE *stream)
 {
+	off64_t pos;
+	
+	if (stream->error)
+		return EOF;
+	
 	_fflushbuf(stream);
-	return lseek(stream->fd, 0, SEEK_CUR);
+	if (stream->error) {
+		/* errno was set by _fflushbuf() */
+		return EOF;
+	}
+
+	pos = lseek(stream->fd, 0, SEEK_CUR);
+	if (pos == (off64_t) -1) {
+		/* errno was set by lseek */
+		return (off64_t) -1;
+	}
+	
+	return pos - stream->ungetc_chars;
 }
 
@@ -703,9 +823,16 @@
 int fflush(FILE *stream)
 {
+	if (stream->error)
+		return EOF;
+	
 	_fflushbuf(stream);
+	if (stream->error) {
+		/* errno was set by _fflushbuf() */
+		return EOF;
+	}
 	
 	if (stream->kio) {
 		kio_update();
-		return EOK;
+		return 0;
 	}
 	
@@ -716,8 +843,13 @@
 		 */
 		stream->need_sync = false;
-		return fsync(stream->fd);
-	}
-	
-	return ENOENT;
+		if (fsync(stream->fd) != 0) {
+			/* errno was set by fsync() */
+			return EOF;
+		}
+
+		return 0;
+	}
+	
+	return 0;
 }
 
@@ -742,5 +874,5 @@
 	if (stream->kio) {
 		errno = EBADF;
-		return -1;
+		return EOF;
 	}
 	
@@ -748,9 +880,9 @@
 }
 
-async_sess_t *fsession(exch_mgmt_t mgmt, FILE *stream)
+async_sess_t *vfs_fsession(FILE *stream, iface_t iface)
 {
 	if (stream->fd >= 0) {
 		if (stream->sess == NULL)
-			stream->sess = fd_session(mgmt, stream->fd);
+			stream->sess = vfs_fd_session(stream->fd, iface);
 		
 		return stream->sess;
@@ -760,5 +892,5 @@
 }
 
-int fhandle(FILE *stream, int *handle)
+int vfs_fhandle(FILE *stream, int *handle)
 {
 	if (stream->fd >= 0) {
Index: uspace/lib/c/generic/io/kio.c
===================================================================
--- uspace/lib/c/generic/io/kio.c	(revision 9854a8faee04ea815f8612666a6e4dac63db2748)
+++ uspace/lib/c/generic/io/kio.c	(revision cffa82aac31c77f5d26f954922753c58edfef5f7)
@@ -43,12 +43,11 @@
 #include <io/printf_core.h>
 
-size_t kio_write(const void *buf, size_t size)
+int kio_write(const void *buf, size_t size, size_t *nwritten)
 {
-	ssize_t ret = (ssize_t) __SYSCALL3(SYS_KIO, KIO_WRITE, (sysarg_t) buf, size);
+	int rc = (int) __SYSCALL3(SYS_KIO, KIO_WRITE, (sysarg_t) buf, size);
 	
-	if (ret >= 0)
-		return (size_t) ret;
-	
-	return 0;
+	if (rc == EOK)
+		*nwritten = size;
+	return rc;
 }
 
@@ -84,5 +83,8 @@
 static int kio_vprintf_str_write(const char *str, size_t size, void *data)
 {
-	size_t wr = kio_write(str, size);
+	size_t wr;
+	
+	wr = 0;
+	(void) kio_write(str, size, &wr);
 	return str_nlength(str, wr);
 }
@@ -92,4 +94,5 @@
 	size_t offset = 0;
 	size_t chars = 0;
+	size_t wr;
 	
 	while (offset < size) {
@@ -98,5 +101,5 @@
 		
 		if (chr_encode(str[chars], buf, &sz, STR_BOUNDS(1)) == EOK)
-			kio_write(buf, sz);
+			kio_write(buf, sz, &wr);
 		
 		chars++;
Index: uspace/lib/c/generic/io/log.c
===================================================================
--- uspace/lib/c/generic/io/log.c	(revision 9854a8faee04ea815f8612666a6e4dac63db2748)
+++ uspace/lib/c/generic/io/log.c	(revision cffa82aac31c77f5d26f954922753c58edfef5f7)
@@ -166,5 +166,6 @@
 		return ENOMEM;
 
-	logger_session = service_connect_blocking(EXCHANGE_SERIALIZE, SERVICE_LOGGER, LOGGER_INTERFACE_WRITER, 0);
+	logger_session = service_connect_blocking(SERVICE_LOGGER,
+	    INTERFACE_LOGGER_WRITER, 0);
 	if (logger_session == NULL) {
 		return ENOMEM;
Index: uspace/lib/c/generic/io/logctl.c
===================================================================
--- uspace/lib/c/generic/io/logctl.c	(revision 9854a8faee04ea815f8612666a6e4dac63db2748)
+++ uspace/lib/c/generic/io/logctl.c	(revision cffa82aac31c77f5d26f954922753c58edfef5f7)
@@ -48,6 +48,6 @@
 
 	if (logger_session == NULL) {
-		logger_session = service_connect_blocking(EXCHANGE_SERIALIZE,
-		    SERVICE_LOGGER, LOGGER_INTERFACE_CONTROL, 0);
+		logger_session = service_connect_blocking(SERVICE_LOGGER,
+		    INTERFACE_LOGGER_CONTROL, 0);
 		if (logger_session == NULL)
 			return ENOMEM;
Index: uspace/lib/c/generic/iplink.c
===================================================================
--- uspace/lib/c/generic/iplink.c	(revision 9854a8faee04ea815f8612666a6e4dac63db2748)
+++ uspace/lib/c/generic/iplink.c	(revision cffa82aac31c77f5d26f954922753c58edfef5f7)
@@ -59,6 +59,9 @@
 	
 	async_exch_t *exch = async_exchange_begin(sess);
-	
-	int rc = async_connect_to_me(exch, 0, 0, 0, iplink_cb_conn, iplink);
+
+	port_id_t port;
+	int rc = async_create_callback_port(exch, INTERFACE_IPLINK_CB, 0, 0,
+	    iplink_cb_conn, iplink, &port);
+	
 	async_exchange_end(exch);
 	
Index: uspace/lib/c/generic/irc.c
===================================================================
--- uspace/lib/c/generic/irc.c	(revision 9854a8faee04ea815f8612666a6e4dac63db2748)
+++ uspace/lib/c/generic/irc.c	(revision cffa82aac31c77f5d26f954922753c58edfef5f7)
@@ -51,6 +51,5 @@
 	assert(irc_sess == NULL);
 
-	irc_sess = service_connect_blocking(EXCHANGE_SERIALIZE,
-	    SERVICE_IRC, 0, 0);
+	irc_sess = service_connect_blocking(SERVICE_IRC, INTERFACE_IRC, 0);
 
 	if (irc_sess == NULL)
Index: uspace/lib/c/generic/loader.c
===================================================================
--- uspace/lib/c/generic/loader.c	(revision 9854a8faee04ea815f8612666a6e4dac63db2748)
+++ uspace/lib/c/generic/loader.c	(revision cffa82aac31c77f5d26f954922753c58edfef5f7)
@@ -69,5 +69,5 @@
 	
 	async_sess_t *sess =
-	    service_connect_blocking(EXCHANGE_SERIALIZE, SERVICE_LOAD, 0, 0);
+	    service_connect_blocking(SERVICE_LOADER, INTERFACE_LOADER, 0);
 	if (sess == NULL) {
 		free(ldr);
@@ -124,5 +124,5 @@
 		return ENOMEM;
 	
-	if (!getcwd(cwd, MAX_PATH_LEN + 1))
+	if (getcwd(cwd, MAX_PATH_LEN + 1) == NULL)
 		str_cpy(cwd, MAX_PATH_LEN + 1, "/");
 	
@@ -162,5 +162,5 @@
 {
 	size_t pa_len;
-	char *pa = absolutize(path, &pa_len);
+	char *pa = vfs_absolutize(path, &pa_len);
 	if (!pa)
 		return ENOMEM;
Index: uspace/lib/c/generic/loc.c
===================================================================
--- uspace/lib/c/generic/loc.c	(revision 9854a8faee04ea815f8612666a6e4dac63db2748)
+++ uspace/lib/c/generic/loc.c	(revision cffa82aac31c77f5d26f954922753c58edfef5f7)
@@ -107,9 +107,13 @@
 	if (!loc_callback_created) {
 		async_exch_t *exch =
-		    loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
+		    loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
 		
 		ipc_call_t answer;
 		aid_t req = async_send_0(exch, LOC_CALLBACK_CREATE, &answer);
-		int rc = async_connect_to_me(exch, 0, 0, 0, loc_cb_conn, NULL);
+		
+		port_id_t port;
+		int rc = async_create_callback_port(exch, INTERFACE_LOC_CB, 0, 0,
+		    loc_cb_conn, NULL, &port);
+		
 		loc_exchange_end(exch);
 		
@@ -135,8 +139,8 @@
  *
  */
-async_exch_t *loc_exchange_begin_blocking(loc_interface_t iface)
+async_exch_t *loc_exchange_begin_blocking(iface_t iface)
 {
 	switch (iface) {
-	case LOC_PORT_SUPPLIER:
+	case INTERFACE_LOC_SUPPLIER:
 		fibril_mutex_lock(&loc_supp_block_mutex);
 		
@@ -147,6 +151,6 @@
 			if (loc_supp_block_sess == NULL)
 				loc_supp_block_sess =
-				    service_connect_blocking(EXCHANGE_SERIALIZE,
-				    SERVICE_LOC, LOC_PORT_SUPPLIER, 0);
+				    service_connect_blocking(SERVICE_LOC,
+				    INTERFACE_LOC_SUPPLIER, 0);
 		}
 		
@@ -157,5 +161,5 @@
 		
 		return async_exchange_begin(loc_supp_block_sess);
-	case LOC_PORT_CONSUMER:
+	case INTERFACE_LOC_CONSUMER:
 		fibril_mutex_lock(&loc_cons_block_mutex);
 		
@@ -166,6 +170,6 @@
 			if (loc_cons_block_sess == NULL)
 				loc_cons_block_sess =
-				    service_connect_blocking(EXCHANGE_SERIALIZE,
-				    SERVICE_LOC, LOC_PORT_CONSUMER, 0);
+				    service_connect_blocking(SERVICE_LOC,
+				    INTERFACE_LOC_CONSUMER, 0);
 		}
 		
@@ -188,14 +192,14 @@
  *
  */
-async_exch_t *loc_exchange_begin(loc_interface_t iface)
+async_exch_t *loc_exchange_begin(iface_t iface)
 {
 	switch (iface) {
-	case LOC_PORT_SUPPLIER:
+	case INTERFACE_LOC_SUPPLIER:
 		fibril_mutex_lock(&loc_supplier_mutex);
 		
 		if (loc_supplier_sess == NULL)
 			loc_supplier_sess =
-			    service_connect(EXCHANGE_SERIALIZE, SERVICE_LOC,
-			    LOC_PORT_SUPPLIER, 0);
+			    service_connect(SERVICE_LOC,
+			    INTERFACE_LOC_SUPPLIER, 0);
 		
 		fibril_mutex_unlock(&loc_supplier_mutex);
@@ -205,11 +209,11 @@
 		
 		return async_exchange_begin(loc_supplier_sess);
-	case LOC_PORT_CONSUMER:
+	case INTERFACE_LOC_CONSUMER:
 		fibril_mutex_lock(&loc_consumer_mutex);
 		
 		if (loc_consumer_sess == NULL)
 			loc_consumer_sess =
-			    service_connect(EXCHANGE_SERIALIZE, SERVICE_LOC,
-			    LOC_PORT_CONSUMER, 0);
+			    service_connect(SERVICE_LOC,
+			    INTERFACE_LOC_CONSUMER, 0);
 		
 		fibril_mutex_unlock(&loc_consumer_mutex);
@@ -237,5 +241,5 @@
 int loc_server_register(const char *name)
 {
-	async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_SUPPLIER);
+	async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_SUPPLIER);
 	
 	ipc_call_t answer;
@@ -250,6 +254,6 @@
 	}
 	
-	exch = loc_exchange_begin(LOC_PORT_SUPPLIER);
-	async_connect_to_me(exch, 0, 0, 0, NULL, NULL);
+	exch = loc_exchange_begin(INTERFACE_LOC_SUPPLIER);
+	async_connect_to_me(exch, 0, 0, 0);
 	loc_exchange_end(exch);
 	
@@ -260,24 +264,14 @@
 /** Register new service.
  *
- * The @p interface is used when forwarding connection to the server.
- * If not 0, the first argument is the interface and the second argument
- * is the service ID.
- *
- * When the interface is zero (default), the first argument is directly
- * the handle (to ensure backward compatibility).
- *
- * @param      fqsn      Fully qualified service name
- * @param[out] sid       Service ID of new service
- * @param      interface Interface when forwarding
- *
- */
-int loc_service_register_with_iface(const char *fqsn,
-    service_id_t *sid, sysarg_t interface)
-{
-	async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_SUPPLIER);
+ * @param      fqsn  Fully qualified service name
+ * @param[out] sid   Service ID of new service
+ *
+ */
+int loc_service_register(const char *fqsn, service_id_t *sid)
+{
+	async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_SUPPLIER);
 	
 	ipc_call_t answer;
-	aid_t req = async_send_2(exch, LOC_SERVICE_REGISTER, interface, 0,
-	    &answer);
+	aid_t req = async_send_0(exch, LOC_SERVICE_REGISTER, &answer);
 	sysarg_t retval = async_data_write_start(exch, fqsn, str_size(fqsn));
 	
@@ -304,15 +298,4 @@
 }
 
-/** Register new service.
- *
- * @param fqsn Fully qualified service name
- * @param sid  Output: ID of new service
- *
- */
-int loc_service_register(const char *fqdn, service_id_t *sid)
-{
-	return loc_service_register_with_iface(fqdn, sid, 0);
-}
-
 /** Unregister service.
  *
@@ -324,5 +307,5 @@
 	sysarg_t retval;
 	
-	exch = loc_exchange_begin_blocking(LOC_PORT_SUPPLIER);
+	exch = loc_exchange_begin_blocking(INTERFACE_LOC_SUPPLIER);
 	retval = async_req_1_0(exch, LOC_SERVICE_UNREGISTER, sid);
 	loc_exchange_end(exch);
@@ -337,7 +320,7 @@
 	
 	if (flags & IPC_FLAG_BLOCKING)
-		exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
+		exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
 	else {
-		exch = loc_exchange_begin(LOC_PORT_CONSUMER);
+		exch = loc_exchange_begin(INTERFACE_LOC_CONSUMER);
 		if (exch == NULL)
 			return errno;
@@ -390,5 +373,5 @@
 	
 	*name = NULL;
-	exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
+	exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
 	
 	ipc_call_t answer;
@@ -470,7 +453,7 @@
 	
 	if (flags & IPC_FLAG_BLOCKING)
-		exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
+		exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
 	else {
-		exch = loc_exchange_begin(LOC_PORT_CONSUMER);
+		exch = loc_exchange_begin(INTERFACE_LOC_CONSUMER);
 		if (exch == NULL)
 			return errno;
@@ -519,7 +502,7 @@
 	
 	if (flags & IPC_FLAG_BLOCKING)
-		exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
+		exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
 	else {
-		exch = loc_exchange_begin(LOC_PORT_CONSUMER);
+		exch = loc_exchange_begin(INTERFACE_LOC_CONSUMER);
 		if (exch == NULL)
 			return errno;
@@ -556,5 +539,5 @@
 loc_object_type_t loc_id_probe(service_id_t handle)
 {
-	async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
+	async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
 	
 	sysarg_t type;
@@ -569,5 +552,5 @@
 }
 
-async_sess_t *loc_service_connect(exch_mgmt_t mgmt, service_id_t handle,
+async_sess_t *loc_service_connect(service_id_t handle, iface_t iface,
     unsigned int flags)
 {
@@ -575,9 +558,7 @@
 	
 	if (flags & IPC_FLAG_BLOCKING)
-		sess = service_connect_blocking(mgmt, SERVICE_LOC,
-		    LOC_CONNECT_TO_SERVICE, handle);
+		sess = service_connect_blocking(SERVICE_LOC, iface, handle);
 	else
-		sess = service_connect(mgmt, SERVICE_LOC,
-		    LOC_CONNECT_TO_SERVICE, handle);
+		sess = service_connect(SERVICE_LOC, iface, handle);
 	
 	return sess;
@@ -586,5 +567,5 @@
 int loc_null_create(void)
 {
-	async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
+	async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
 	
 	sysarg_t null_id;
@@ -601,5 +582,5 @@
 void loc_null_destroy(int null_id)
 {
-	async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
+	async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
 	async_req_1_0(exch, LOC_NULL_DESTROY, (sysarg_t) null_id);
 	loc_exchange_end(exch);
@@ -627,5 +608,5 @@
 	sysarg_t retval;
 	
-	exch = loc_exchange_begin_blocking(LOC_PORT_SUPPLIER);
+	exch = loc_exchange_begin_blocking(INTERFACE_LOC_SUPPLIER);
 	retval = async_req_2_0(exch, LOC_SERVICE_ADD_TO_CAT, svc_id, cat_id);
 	loc_exchange_end(exch);
@@ -648,5 +629,5 @@
 size_t loc_count_namespaces(void)
 {
-	async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
+	async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
 	size_t size = loc_count_namespaces_internal(exch);
 	loc_exchange_end(exch);
@@ -657,5 +638,5 @@
 size_t loc_count_services(service_id_t ns_handle)
 {
-	async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
+	async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
 	size_t size = loc_count_services_internal(exch, ns_handle);
 	loc_exchange_end(exch);
@@ -668,5 +649,5 @@
 	/* Loop until read is succesful */
 	while (true) {
-		async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
+		async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
 		size_t count = loc_count_namespaces_internal(exch);
 		loc_exchange_end(exch);
@@ -679,5 +660,5 @@
 			return 0;
 		
-		exch = loc_exchange_begin(LOC_PORT_CONSUMER);
+		exch = loc_exchange_begin(INTERFACE_LOC_CONSUMER);
 		
 		ipc_call_t answer;
@@ -717,5 +698,5 @@
 	/* Loop until read is succesful */
 	while (true) {
-		async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
+		async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
 		size_t count = loc_count_services_internal(exch, ns_handle);
 		loc_exchange_end(exch);
@@ -728,5 +709,5 @@
 			return 0;
 		
-		exch = loc_exchange_begin(LOC_PORT_CONSUMER);
+		exch = loc_exchange_begin(INTERFACE_LOC_CONSUMER);
 		
 		ipc_call_t answer;
@@ -765,5 +746,5 @@
     sysarg_t *id_buf, size_t buf_size, size_t *act_size)
 {
-	async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
+	async_exch_t *exch = loc_exchange_begin_blocking(INTERFACE_LOC_CONSUMER);
 
 	ipc_call_t answer;
Index: uspace/lib/c/generic/ns.c
===================================================================
--- uspace/lib/c/generic/ns.c	(revision 9854a8faee04ea815f8612666a6e4dac63db2748)
+++ uspace/lib/c/generic/ns.c	(revision cffa82aac31c77f5d26f954922753c58edfef5f7)
@@ -40,8 +40,8 @@
 #include "private/ns.h"
 
-int service_register(sysarg_t service)
+int service_register(service_t service)
 {
 	async_exch_t *exch = async_exchange_begin(session_ns);
-	int rc = async_connect_to_me(exch, service, 0, 0, NULL, NULL);
+	int rc = async_connect_to_me(exch, 0, service, 0);
 	async_exchange_end(exch);
 	
@@ -49,6 +49,6 @@
 }
 
-async_sess_t *service_connect(exch_mgmt_t mgmt, services_t service, sysarg_t arg2,
-    sysarg_t arg3)
+
+async_sess_t *service_connect(service_t service, iface_t iface, sysarg_t arg3)
 {
 	async_exch_t *exch = async_exchange_begin(session_ns);
@@ -57,5 +57,5 @@
 	
 	async_sess_t *sess =
-	    async_connect_me_to(mgmt, exch, service, arg2, arg3);
+	    async_connect_me_to_iface(exch, iface, service, arg3);
 	async_exchange_end(exch);
 	
@@ -68,17 +68,15 @@
 	 * first argument for non-initial connections.
 	 */
-	async_sess_args_set(sess, arg2, arg3, 0);
+	async_sess_args_set(sess, iface, arg3, 0);
 	
 	return sess;
 }
 
-async_sess_t *service_connect_blocking(exch_mgmt_t mgmt, services_t service,
-    sysarg_t arg2, sysarg_t arg3)
+async_sess_t *service_connect_blocking(service_t service, iface_t iface,
+    sysarg_t arg3)
 {
 	async_exch_t *exch = async_exchange_begin(session_ns);
-	if (!exch)
-		return NULL;
 	async_sess_t *sess =
-	    async_connect_me_to_blocking(mgmt, exch, service, arg2, arg3);
+	    async_connect_me_to_blocking_iface(exch, iface, service, arg3);
 	async_exchange_end(exch);
 	
@@ -91,43 +89,9 @@
 	 * first argument for non-initial connections.
 	 */
-	async_sess_args_set(sess, arg2, arg3, 0);
+	async_sess_args_set(sess, iface, arg3, 0);
 	
 	return sess;
 }
 
-/** Create bidirectional connection with a service
- *
- * @param[in] service         Service.
- * @param[in] arg1            First parameter.
- * @param[in] arg2            Second parameter.
- * @param[in] arg3            Third parameter.
- * @param[in] client_receiver Message receiver.
- *
- * @return Session to the service.
- * @return Other error codes as defined by async_connect_to_me().
- *
- */
-async_sess_t *service_bind(services_t service, sysarg_t arg1, sysarg_t arg2,
-    sysarg_t arg3, async_client_conn_t client_receiver)
-{
-	/* Connect to the needed service */
-	async_sess_t *sess =
-	    service_connect_blocking(EXCHANGE_SERIALIZE, service, 0, 0);
-	if (sess != NULL) {
-		/* Request callback connection */
-		async_exch_t *exch = async_exchange_begin(sess);
-		int rc = async_connect_to_me(exch, arg1, arg2, arg3,
-		    client_receiver, NULL);
-		async_exchange_end(exch);
-		
-		if (rc != EOK) {
-			async_hangup(sess);
-			errno = rc;
-			return NULL;
-		}
-	}
-	
-	return sess;
-}
 
 int ns_ping(void)
Index: uspace/lib/c/generic/private/stdio.h
===================================================================
--- uspace/lib/c/generic/private/stdio.h	(revision 9854a8faee04ea815f8612666a6e4dac63db2748)
+++ uspace/lib/c/generic/private/stdio.h	(revision cffa82aac31c77f5d26f954922753c58edfef5f7)
@@ -39,4 +39,7 @@
 #include <stdio.h>
 #include <async.h>
+
+/** Maximum characters that can be pushed back by ungetc() */
+#define UNGETC_MAX 1
 
 struct _IO_FILE {
@@ -82,4 +85,10 @@
 	/** Points to end of occupied space when in read mode. */
 	uint8_t *buf_tail;
+
+	/** Pushed back characters */
+	uint8_t ungetc_buf[UNGETC_MAX];
+
+	/** Number of pushed back characters */
+	int ungetc_chars;
 };
 
Index: uspace/lib/c/generic/task.c
===================================================================
--- uspace/lib/c/generic/task.c	(revision 9854a8faee04ea815f8612666a6e4dac63db2748)
+++ uspace/lib/c/generic/task.c	(revision cffa82aac31c77f5d26f954922753c58edfef5f7)
@@ -112,15 +112,15 @@
 	int fd_stderr;
 	
-	if ((stdin != NULL) && (fhandle(stdin, &fd_stdin) == EOK))
+	if ((stdin != NULL) && (vfs_fhandle(stdin, &fd_stdin) == EOK))
 		files[0] = &fd_stdin;
 	else
 		files[0] = NULL;
 	
-	if ((stdout != NULL) && (fhandle(stdout, &fd_stdout) == EOK))
+	if ((stdout != NULL) && (vfs_fhandle(stdout, &fd_stdout) == EOK))
 		files[1] = &fd_stdout;
 	else
 		files[1] = NULL;
 	
-	if ((stderr != NULL) && (fhandle(stderr, &fd_stderr) == EOK))
+	if ((stderr != NULL) && (vfs_fhandle(stderr, &fd_stderr) == EOK))
 		files[2] = &fd_stderr;
 	else
Index: uspace/lib/c/generic/time.c
===================================================================
--- uspace/lib/c/generic/time.c	(revision 9854a8faee04ea815f8612666a6e4dac63db2748)
+++ uspace/lib/c/generic/time.c	(revision cffa82aac31c77f5d26f954922753c58edfef5f7)
@@ -611,6 +611,6 @@
 			goto fallback;
 		
-		clock_conn = loc_service_connect(EXCHANGE_SERIALIZE,
-		    svc_id, IPC_FLAG_BLOCKING);
+		clock_conn = loc_service_connect(svc_id, INTERFACE_DDF,
+		    IPC_FLAG_BLOCKING);
 		if (!clock_conn)
 			goto fallback;
Index: uspace/lib/c/generic/vbd.c
===================================================================
--- uspace/lib/c/generic/vbd.c	(revision 9854a8faee04ea815f8612666a6e4dac63db2748)
+++ uspace/lib/c/generic/vbd.c	(revision cffa82aac31c77f5d26f954922753c58edfef5f7)
@@ -33,4 +33,5 @@
  */
 
+#include <abi/ipc/interfaces.h>
 #include <errno.h>
 #include <ipc/services.h>
@@ -65,5 +66,5 @@
 	}
 
-	vbd->sess = loc_service_connect(EXCHANGE_SERIALIZE, vbd_svcid,
+	vbd->sess = loc_service_connect(vbd_svcid, INTERFACE_VBD,
 	    IPC_FLAG_BLOCKING);
 	if (vbd->sess == NULL) {
Index: uspace/lib/c/generic/vfs/vfs.c
===================================================================
--- uspace/lib/c/generic/vfs/vfs.c	(revision 9854a8faee04ea815f8612666a6e4dac63db2748)
+++ uspace/lib/c/generic/vfs/vfs.c	(revision cffa82aac31c77f5d26f954922753c58edfef5f7)
@@ -75,6 +75,6 @@
 	
 	while (vfs_sess == NULL)
-		vfs_sess = service_connect_blocking(EXCHANGE_PARALLEL, SERVICE_VFS,
-		    0, 0);
+		vfs_sess = service_connect_blocking(SERVICE_VFS, INTERFACE_VFS,
+		    0);
 	
 	fibril_mutex_unlock(&vfs_mutex);
@@ -93,5 +93,5 @@
 }
 
-char *absolutize(const char *path, size_t *retlen)
+char *vfs_absolutize(const char *path, size_t *retlen)
 {
 	char *ncwd_path;
@@ -101,10 +101,10 @@
 	size_t size = str_size(path);
 	if (*path != '/') {
-		if (!cwd_path) {
+		if (cwd_path == NULL) {
 			fibril_mutex_unlock(&cwd_mutex);
 			return NULL;
 		}
 		ncwd_path_nc = malloc(cwd_size + 1 + size + 1);
-		if (!ncwd_path_nc) {
+		if (ncwd_path_nc == NULL) {
 			fibril_mutex_unlock(&cwd_mutex);
 			return NULL;
@@ -115,5 +115,5 @@
 	} else {
 		ncwd_path_nc = malloc(size + 1);
-		if (!ncwd_path_nc) {
+		if (ncwd_path_nc == NULL) {
 			fibril_mutex_unlock(&cwd_mutex);
 			return NULL;
@@ -123,5 +123,5 @@
 	str_append(ncwd_path_nc, cwd_size + 1 + size + 1, path);
 	ncwd_path = canonify(ncwd_path_nc, retlen);
-	if (!ncwd_path) {
+	if (ncwd_path == NULL) {
 		fibril_mutex_unlock(&cwd_mutex);
 		free(ncwd_path_nc);
@@ -135,5 +135,5 @@
 	ncwd_path = str_dup(ncwd_path);
 	free(ncwd_path_nc);
-	if (!ncwd_path) {
+	if (ncwd_path == NULL) {
 		fibril_mutex_unlock(&cwd_mutex);
 		return NULL;
@@ -143,5 +143,5 @@
 }
 
-int mount(const char *fs_name, const char *mp, const char *fqsn,
+int vfs_mount(const char *fs_name, const char *mp, const char *fqsn,
     const char *opts, unsigned int flags, unsigned int instance)
 {
@@ -171,6 +171,6 @@
 	
 	size_t mpa_size;
-	char *mpa = absolutize(mp, &mpa_size);
-	if (!mpa) {
+	char *mpa = vfs_absolutize(mp, &mpa_size);
+	if (mpa == NULL) {
 		if (null_id != -1)
 			loc_null_destroy(null_id);
@@ -255,5 +255,5 @@
 }
 
-int unmount(const char *mp)
+int vfs_unmount(const char *mp)
 {
 	sysarg_t rc;
@@ -263,6 +263,6 @@
 	char *mpa;
 	
-	mpa = absolutize(mp, &mpa_size);
-	if (!mpa)
+	mpa = vfs_absolutize(mp, &mpa_size);
+	if (mpa == NULL)
 		return ENOMEM;
 	
@@ -289,5 +289,16 @@
 }
 
-static int open_internal(const char *abs, size_t abs_size, int lflag, int oflag)
+/** Open file (internal).
+ *
+ * @param abs Absolute path to file
+ * @param abs_size Size of @a abs string
+ * @param lflag L_xxx flags
+ * @param oflag O_xxx flags
+ * @param fd Place to store new file descriptor
+ *
+ * @return EOK on success, non-zero error code on error
+ */
+static int open_internal(const char *abs, size_t abs_size, int lflag, int oflag,
+    int *fd)
 {
 	async_exch_t *exch = vfs_exchange_begin();
@@ -315,20 +326,44 @@
 	    return (int) rc;
 	
-	return (int) IPC_GET_ARG1(answer);
-}
-
+	*fd = (int) IPC_GET_ARG1(answer);
+	return EOK;
+}
+
+/** Open file.
+ *
+ * @param path File path
+ * @param oflag O_xxx flags
+ * @param mode File mode (only with O_CREAT)
+ *
+ * @return Nonnegative file descriptor on success. On error -1 is returned
+ *         and errno is set.
+ */
 int open(const char *path, int oflag, ...)
 {
 	size_t abs_size;
-	char *abs = absolutize(path, &abs_size);
-	if (!abs)
-		return ENOMEM;
-	
-	int ret = open_internal(abs, abs_size, L_FILE, oflag);
+	char *abs = vfs_absolutize(path, &abs_size);
+	int fd = -1;
+	
+	if (abs == NULL) {
+		errno = ENOMEM;
+		return -1;
+	}
+	
+	int rc = open_internal(abs, abs_size, L_FILE, oflag, &fd);
 	free(abs);
 	
-	return ret;
-}
-
+	if (rc != EOK) {
+		errno = rc;
+		return -1;
+	}
+	
+	return fd;
+}
+
+/** Close file.
+ *
+ * @param fildes File descriptor
+ * @return Zero on success. On error -1 is returned and errno is set.
+ */
 int close(int fildes)
 {
@@ -339,8 +374,27 @@
 	vfs_exchange_end(exch);
 	
-	return (int) rc;
-}
-
-ssize_t read(int fildes, void *buf, size_t nbyte)
+	if (rc != EOK) {
+		errno = rc;
+		return -1;
+	}
+	
+	return 0;
+}
+
+/** Read bytes from file.
+ *
+ * Read up to @a nbyte bytes from file. The actual number of bytes read
+ * may be lower, but greater than zero if there are any bytes available.
+ * If there are no bytes available for reading, then the function will
+ * return success with zero bytes read.
+ *
+ * @param fildes File descriptor
+ * @param buf Buffer
+ * @param nbyte Maximum number of bytes to read
+ * @param nread Place to store actual number of bytes read (0 or more)
+ *
+ * @return EOK on success, non-zero error code on error.
+ */
+static int _read_short(int fildes, void *buf, size_t nbyte, ssize_t *nread)
 {
 	sysarg_t rc;
@@ -357,22 +411,38 @@
 	if (rc != EOK) {
 		vfs_exchange_end(exch);
-
+		
 		sysarg_t rc_orig;
 		async_wait_for(req, &rc_orig);
-
+		
 		if (rc_orig == EOK)
-			return (ssize_t) rc;
+			return rc;
 		else
-			return (ssize_t) rc_orig;
-	}
+			return rc_orig;
+	}
+	
 	vfs_exchange_end(exch);
 	async_wait_for(req, &rc);
-	if (rc == EOK)
-		return (ssize_t) IPC_GET_ARG1(answer);
-	else
+	
+	if (rc != EOK)
 		return rc;
-}
-
-ssize_t write(int fildes, const void *buf, size_t nbyte) 
+	
+	*nread = (ssize_t) IPC_GET_ARG1(answer);
+	return EOK;
+}
+
+/** Write bytes to file.
+ *
+ * Write up to @a nbyte bytes from file. The actual number of bytes written
+ * may be lower, but greater than zero.
+ *
+ * @param fildes File descriptor
+ * @param buf Buffer
+ * @param nbyte Maximum number of bytes to write
+ * @param nread Place to store actual number of bytes written (0 or more)
+ *
+ * @return EOK on success, non-zero error code on error.
+ */
+static int _write_short(int fildes, const void *buf, size_t nbyte,
+    ssize_t *nwritten)
 {
 	sysarg_t rc;
@@ -389,25 +459,28 @@
 	if (rc != EOK) {
 		vfs_exchange_end(exch);
-
+		
 		sysarg_t rc_orig;
 		async_wait_for(req, &rc_orig);
-
+		
 		if (rc_orig == EOK)
-			return (ssize_t) rc;
+			return rc;
 		else
-			return (ssize_t) rc_orig;
-	}
+			return rc_orig;
+	}
+	
 	vfs_exchange_end(exch);
 	async_wait_for(req, &rc);
-	if (rc == EOK)
-		return (ssize_t) IPC_GET_ARG1(answer);
-	else
-		return -1;
-}
-
-/** Read entire buffer.
- *
- * In face of short reads this function continues reading until either
- * the entire buffer is read or no more data is available (at end of file).
+	
+	if (rc != EOK)
+		return rc;
+	
+	*nwritten = (ssize_t) IPC_GET_ARG1(answer);
+	return EOK;
+}
+
+/** Read data.
+ *
+ * Read up to @a nbytes bytes from file if available. This function always reads
+ * all the available bytes up to @a nbytes.
  *
  * @param fildes	File descriptor
@@ -415,26 +488,29 @@
  * @param nbytes	Number of bytes to read
  *
- * @return		On success, positive number of bytes read.
- *			On failure, negative error code from read().
- */
-ssize_t read_all(int fildes, void *buf, size_t nbyte)
+ * @return		On success, nonnegative number of bytes read.
+ *			On failure, -1 and sets errno.
+ */
+ssize_t read(int fildes, void *buf, size_t nbyte)
 {
 	ssize_t cnt = 0;
 	size_t nread = 0;
 	uint8_t *bp = (uint8_t *) buf;
-
+	int rc;
+	
 	do {
 		bp += cnt;
 		nread += cnt;
-		cnt = read(fildes, bp, nbyte - nread);
-	} while (cnt > 0 && (nbyte - nread - cnt) > 0);
-
-	if (cnt < 0)
-		return cnt;
-
+		rc = _read_short(fildes, bp, nbyte - nread, &cnt);
+	} while (rc == EOK && cnt > 0 && (nbyte - nread - cnt) > 0);
+	
+	if (rc != EOK) {
+		errno = rc;
+		return -1;
+	}
+	
 	return nread + cnt;
 }
 
-/** Write entire buffer.
+/** Write data.
  *
  * This function fails if it cannot write exactly @a len bytes to the file.
@@ -444,28 +520,33 @@
  * @param nbytes	Number of bytes to write
  *
- * @return		EOK on error, return value from write() if writing
- *			failed.
- */
-ssize_t write_all(int fildes, const void *buf, size_t nbyte)
+ * @return		On success, nonnegative number of bytes written.
+ *			On failure, -1 and sets errno.
+ */
+ssize_t write(int fildes, const void *buf, size_t nbyte)
 {
 	ssize_t cnt = 0;
 	ssize_t nwritten = 0;
 	const uint8_t *bp = (uint8_t *) buf;
+	int rc;
 
 	do {
 		bp += cnt;
 		nwritten += cnt;
-		cnt = write(fildes, bp, nbyte - nwritten);
-	} while (cnt > 0 && ((ssize_t )nbyte - nwritten - cnt) > 0);
-
-	if (cnt < 0)
-		return cnt;
-
-	if ((ssize_t)nbyte - nwritten - cnt > 0)
-		return EIO;
+		rc = _write_short(fildes, bp, nbyte - nwritten, &cnt);
+	} while (rc == EOK && ((ssize_t )nbyte - nwritten - cnt) > 0);
+
+	if (rc != EOK) {
+		errno = rc;
+		return -1;
+	}
 
 	return nbyte;
 }
 
+/** Synchronize file.
+ *
+ * @param fildes File descriptor
+ * @return 0 on success. On error returns -1 and sets errno.
+ */
 int fsync(int fildes)
 {
@@ -474,7 +555,21 @@
 	vfs_exchange_end(exch);
 	
-	return (int) rc;
-}
-
+	if (rc != EOK) {
+		errno = rc;
+		return -1;
+	}
+	
+	return 0;
+}
+
+/** Seek to a position.
+ *
+ * @param fildes File descriptor
+ * @param offset Offset
+ * @param whence SEEK_SET, SEEK_CUR or SEEK_END
+ *
+ * @return On success the nonnegative offset from start of file. On error
+ *         returns (off64_t)-1 and sets errno.
+ */
 off64_t lseek(int fildes, off64_t offset, int whence)
 {
@@ -489,10 +584,21 @@
 	vfs_exchange_end(exch);
 	
-	if (rc != EOK)
+	if (rc != EOK) {
+		errno = rc;
 		return (off64_t) -1;
+	}
 	
 	return (off64_t) MERGE_LOUP32(newoff_lo, newoff_hi);
 }
 
+/** Truncate file to a specified length.
+ *
+ * Truncate file so that its size is exactly @a length
+ *
+ * @param fildes File descriptor
+ * @param length Length
+ *
+ * @return 0 on success, -1 on error and sets errno.
+ */
 int ftruncate(int fildes, aoff64_t length)
 {
@@ -504,7 +610,19 @@
 	vfs_exchange_end(exch);
 	
-	return (int) rc;
-}
-
+	if (rc != EOK) {
+		errno = rc;
+		return -1;
+	}
+	
+	return 0;
+}
+
+/** Get file status.
+ *
+ * @param fildes File descriptor
+ * @param stat Place to store file information
+ *
+ * @return 0 on success, -1 on error and sets errno.
+ */
 int fstat(int fildes, struct stat *stat)
 {
@@ -518,19 +636,36 @@
 	if (rc != EOK) {
 		vfs_exchange_end(exch);
-
+		
 		sysarg_t rc_orig;
 		async_wait_for(req, &rc_orig);
-
-		if (rc_orig == EOK)
-			return (ssize_t) rc;
-		else
-			return (ssize_t) rc_orig;
-	}
+		
+		if (rc_orig != EOK)
+			rc = rc_orig;
+		if (rc != EOK) {
+			errno = rc;
+			return -1;
+		}
+		
+		return 0;
+	}
+	
 	vfs_exchange_end(exch);
 	async_wait_for(req, &rc);
-
-	return rc;
-}
-
+	
+	if (rc != EOK) {
+		errno = rc;
+		return -1;
+	}
+	
+	return 0;
+}
+
+/** Get file status.
+ *
+ * @param path Path to file
+ * @param stat Place to store file information
+ *
+ * @return 0 on success, -1 on error and sets errno.
+ */
 int stat(const char *path, struct stat *stat)
 {
@@ -540,7 +675,9 @@
 	
 	size_t pa_size;
-	char *pa = absolutize(path, &pa_size);
-	if (!pa)
-		return ENOMEM;
+	char *pa = vfs_absolutize(path, &pa_size);
+	if (pa == NULL) {
+		errno = ENOMEM;
+		return -1;
+	}
 	
 	async_exch_t *exch = vfs_exchange_begin();
@@ -552,4 +689,195 @@
 		free(pa);
 		async_wait_for(req, &rc_orig);
+		if (rc_orig != EOK)
+			rc = rc_orig;
+		if (rc != EOK) {
+			errno = rc;
+			return -1;
+		}
+	}
+	rc = async_data_read_start(exch, stat, sizeof(struct stat));
+	if (rc != EOK) {
+		vfs_exchange_end(exch);
+		free(pa);
+		async_wait_for(req, &rc_orig);
+		if (rc_orig != EOK)
+			rc = rc_orig;
+		if (rc != EOK) {
+			errno = rc;
+			return -1;
+		}
+	}
+	vfs_exchange_end(exch);
+	free(pa);
+	async_wait_for(req, &rc);
+	if (rc != EOK) {
+		errno = rc;
+		return -1;
+	}
+	return 0;
+}
+
+/** Open directory.
+ *
+ * @param dirname Directory pathname
+ *
+ * @return Non-NULL pointer on success. On error returns @c NULL and sets errno.
+ */
+DIR *opendir(const char *dirname)
+{
+	DIR *dirp = malloc(sizeof(DIR));
+	int fd = -1;
+	
+	if (dirp == NULL) {
+		errno = ENOMEM;
+		return NULL;
+	}
+	
+	size_t abs_size;
+	char *abs = vfs_absolutize(dirname, &abs_size);
+	if (abs == NULL) {
+		free(dirp);
+		errno = ENOMEM;
+		return NULL;
+	}
+	
+	int rc = open_internal(abs, abs_size, L_DIRECTORY, 0, &fd);
+	free(abs);
+	
+	if (rc != EOK) {
+		free(dirp);
+		errno = rc;
+		return NULL;
+	}
+	
+	dirp->fd = fd;
+	return dirp;
+}
+
+/** Read directory entry.
+ *
+ * @param dirp Open directory
+ * @return Non-NULL pointer to directory entry on success. On error returns
+ *         @c NULL and sets errno.
+ */
+struct dirent *readdir(DIR *dirp)
+{
+	int rc;
+	ssize_t len;
+	
+	rc = _read_short(dirp->fd, &dirp->res.d_name[0], NAME_MAX + 1, &len);
+	if (rc != EOK) {
+		errno = rc;
+		return NULL;
+	}
+	
+	(void) len;
+	return &dirp->res;
+}
+
+/** Rewind directory position to the beginning.
+ *
+ * @param dirp Open directory
+ */
+void rewinddir(DIR *dirp)
+{
+	(void) lseek(dirp->fd, 0, SEEK_SET);
+}
+
+/** Close directory.
+ *
+ * @param dirp Open directory
+ * @return 0 on success. On error returns -1 and sets errno.
+ */
+int closedir(DIR *dirp)
+{
+	int rc;
+	
+	rc = close(dirp->fd);
+	free(dirp);
+
+	/* On error errno was set by close() */
+	return rc;
+}
+
+/** Create directory.
+ *
+ * @param path Path
+ * @param mode File mode
+ * @return 0 on success. On error returns -1 and sets errno.
+ */
+int mkdir(const char *path, mode_t mode)
+{
+	sysarg_t rc;
+	aid_t req;
+	
+	size_t pa_size;
+	char *pa = vfs_absolutize(path, &pa_size);
+	if (pa == NULL) {
+		errno = ENOMEM;
+		return -1;
+	}
+	
+	async_exch_t *exch = vfs_exchange_begin();
+	
+	req = async_send_1(exch, VFS_IN_MKDIR, mode, NULL);
+	rc = async_data_write_start(exch, pa, pa_size);
+	if (rc != EOK) {
+		vfs_exchange_end(exch);
+		free(pa);
+		
+		sysarg_t rc_orig;
+		async_wait_for(req, &rc_orig);
+		
+		if (rc_orig != EOK)
+			rc = rc_orig;
+		
+		if (rc != EOK) {
+			errno = rc;
+			return -1;
+		}
+		
+		return 0;
+	}
+	
+	vfs_exchange_end(exch);
+	free(pa);
+	async_wait_for(req, &rc);
+	
+	if (rc != EOK) {
+		errno = rc;
+		return -1;
+	}
+	
+	return 0;
+}
+
+/** Unlink a file or directory.
+ *
+ * @param path Path to file or empty directory
+ * @param lflag L_xxx flag (L_NONE, L_FILE or L_DIRECTORY)
+ * @return EOK on success, non-zero error code on error
+ */
+static int _unlink(const char *path, int lflag)
+{
+	sysarg_t rc;
+	aid_t req;
+	
+	size_t pa_size;
+	char *pa = vfs_absolutize(path, &pa_size);
+	if (pa == NULL)
+		return ENOMEM;
+	
+	async_exch_t *exch = vfs_exchange_begin();
+	
+	req = async_send_1(exch, VFS_IN_UNLINK, lflag, NULL);
+	rc = async_data_write_start(exch, pa, pa_size);
+	if (rc != EOK) {
+		vfs_exchange_end(exch);
+		free(pa);
+
+		sysarg_t rc_orig;
+		async_wait_for(req, &rc_orig);
+
 		if (rc_orig == EOK)
 			return (int) rc;
@@ -557,14 +885,4 @@
 			return (int) rc_orig;
 	}
-	rc = async_data_read_start(exch, stat, sizeof(struct stat));
-	if (rc != EOK) {
-		vfs_exchange_end(exch);
-		free(pa);
-		async_wait_for(req, &rc_orig);
-		if (rc_orig == EOK)
-			return (int) rc;
-		else
-			return (int) rc_orig;
-	}
 	vfs_exchange_end(exch);
 	free(pa);
@@ -573,123 +891,47 @@
 }
 
-DIR *opendir(const char *dirname)
-{
-	DIR *dirp = malloc(sizeof(DIR));
-	if (!dirp)
-		return NULL;
-	
-	size_t abs_size;
-	char *abs = absolutize(dirname, &abs_size);
-	if (!abs) {
-		free(dirp);
-		return NULL;
-	}
-	
-	int ret = open_internal(abs, abs_size, L_DIRECTORY, 0);
-	free(abs);
-	
-	if (ret < 0) {
-		free(dirp);
-		return NULL;
-	}
-	
-	dirp->fd = ret;
-	return dirp;
-}
-
-struct dirent *readdir(DIR *dirp)
-{
-	ssize_t len = read(dirp->fd, &dirp->res.d_name[0], NAME_MAX + 1);
-	if (len <= 0)
-		return NULL;
-	return &dirp->res;
-}
-
-void rewinddir(DIR *dirp)
-{
-	(void) lseek(dirp->fd, 0, SEEK_SET);
-}
-
-int closedir(DIR *dirp)
-{
-	(void) close(dirp->fd);
-	free(dirp);
+/** Unlink file or directory.
+ *
+ * @param path Path
+ * @return EOk on success, error code on error
+ */
+int unlink(const char *path)
+{
+	int rc;
+
+	rc = _unlink(path, L_NONE);
+	if (rc != EOK) {
+		errno = rc;
+		return -1;
+	}
+
 	return 0;
 }
 
-int mkdir(const char *path, mode_t mode)
-{
-	sysarg_t rc;
-	aid_t req;
-	
-	size_t pa_size;
-	char *pa = absolutize(path, &pa_size);
-	if (!pa)
-		return ENOMEM;
-	
-	async_exch_t *exch = vfs_exchange_begin();
-	
-	req = async_send_1(exch, VFS_IN_MKDIR, mode, NULL);
-	rc = async_data_write_start(exch, pa, pa_size);
-	if (rc != EOK) {
-		vfs_exchange_end(exch);
-		free(pa);
-
-		sysarg_t rc_orig;
-		async_wait_for(req, &rc_orig);
-
-		if (rc_orig == EOK)
-			return (int) rc;
-		else
-			return (int) rc_orig;
-	}
-	vfs_exchange_end(exch);
-	free(pa);
-	async_wait_for(req, &rc);
-	return rc;
-}
-
-static int _unlink(const char *path, int lflag)
-{
-	sysarg_t rc;
-	aid_t req;
-	
-	size_t pa_size;
-	char *pa = absolutize(path, &pa_size);
-	if (!pa)
-		return ENOMEM;
-	
-	async_exch_t *exch = vfs_exchange_begin();
-	
-	req = async_send_1(exch, VFS_IN_UNLINK, lflag, NULL);
-	rc = async_data_write_start(exch, pa, pa_size);
-	if (rc != EOK) {
-		vfs_exchange_end(exch);
-		free(pa);
-
-		sysarg_t rc_orig;
-		async_wait_for(req, &rc_orig);
-
-		if (rc_orig == EOK)
-			return (int) rc;
-		else
-			return (int) rc_orig;
-	}
-	vfs_exchange_end(exch);
-	free(pa);
-	async_wait_for(req, &rc);
-	return rc;
-}
-
-int unlink(const char *path)
-{
-	return _unlink(path, L_NONE);
-}
-
+/** Remove empty directory.
+ *
+ * @param path Path
+ * @return 0 on success. On error returns -1 and sets errno.
+ */
 int rmdir(const char *path)
 {
-	return _unlink(path, L_DIRECTORY);
-}
-
+	int rc;
+
+	rc = _unlink(path, L_DIRECTORY);
+	if (rc != EOK) {
+		errno = rc;
+		return -1;
+	}
+
+	return 0;
+}
+
+/** Rename directory entry.
+ *
+ * @param old Old name
+ * @param new New name
+ *
+ * @return 0 on success. On error returns -1 and sets errno.
+ */
 int rename(const char *old, const char *new)
 {
@@ -699,13 +941,16 @@
 	
 	size_t olda_size;
-	char *olda = absolutize(old, &olda_size);
-	if (!olda)
-		return ENOMEM;
+	char *olda = vfs_absolutize(old, &olda_size);
+	if (olda == NULL) {
+		errno = ENOMEM;
+		return -1;
+	}
 
 	size_t newa_size;
-	char *newa = absolutize(new, &newa_size);
-	if (!newa) {
+	char *newa = vfs_absolutize(new, &newa_size);
+	if (newa == NULL) {
 		free(olda);
-		return ENOMEM;
+		errno = ENOMEM;
+		return -1;
 	}
 	
@@ -719,8 +964,11 @@
 		free(newa);
 		async_wait_for(req, &rc_orig);
-		if (rc_orig == EOK)
-			return (int) rc;
-		else
-			return (int) rc_orig;
+		if (rc_orig != EOK)
+			rc = rc_orig;
+		if (rc != EOK) {
+			errno = rc;
+			return -1;
+		}
+		return 0;
 	}
 	rc = async_data_write_start(exch, newa, newa_size);
@@ -730,8 +978,11 @@
 		free(newa);
 		async_wait_for(req, &rc_orig);
-		if (rc_orig == EOK)
-			return (int) rc;
-		else
-			return (int) rc_orig;
+		if (rc_orig != EOK)
+			rc = rc_orig;
+		if (rc != EOK) {
+			errno = rc;
+			return -1;
+		}
+		return 0;
 	}
 	vfs_exchange_end(exch);
@@ -739,7 +990,18 @@
 	free(newa);
 	async_wait_for(req, &rc);
-	return rc;
-}
-
+
+	if (rc != EOK) {
+		errno = rc;
+		return -1;
+	}
+
+	return 0;
+}
+
+/** Remove directory entry.
+ *
+ * @param path Path
+ * @return 0 on success. On error returns -1 and sets errno.
+ */
 int remove(const char *path)
 {
@@ -747,16 +1009,26 @@
 }
 
+/** Change working directory.
+ *
+ * @param path Path
+ * @return 0 on success. On error returns -1 and sets errno.
+ */
 int chdir(const char *path)
 {
 	size_t abs_size;
-	char *abs = absolutize(path, &abs_size);
-	if (!abs)
-		return ENOMEM;
-	
-	int fd = open_internal(abs, abs_size, L_DIRECTORY, O_DESC);
-	
-	if (fd < 0) {
+	char *abs = vfs_absolutize(path, &abs_size);
+	int fd = -1;
+	
+	if (abs == NULL) {
+		errno = ENOMEM;
+		return -1;
+	}
+	
+	int rc = open_internal(abs, abs_size, L_DIRECTORY, O_DESC, &fd);
+	
+	if (rc != EOK) {
 		free(abs);
-		return ENOENT;
+		errno = rc;
+		return -1;
 	}
 	
@@ -765,5 +1037,4 @@
 	if (cwd_fd >= 0)
 		close(cwd_fd);
-	
 	
 	if (cwd_path)
@@ -775,11 +1046,19 @@
 	
 	fibril_mutex_unlock(&cwd_mutex);
-	return EOK;
-}
-
+	return 0;
+}
+
+/** Get current working directory path.
+ *
+ * @param buf Buffer
+ * @param size Size of @a buf
+ * @return On success returns @a buf. On failure returns @c NULL and sets errno.
+ */
 char *getcwd(char *buf, size_t size)
 {
-	if (size == 0)
+	if (size == 0) {
+		errno = EINVAL;
 		return NULL;
+	}
 	
 	fibril_mutex_lock(&cwd_mutex);
@@ -787,4 +1066,5 @@
 	if ((cwd_size == 0) || (size < cwd_size + 1)) {
 		fibril_mutex_unlock(&cwd_mutex);
+		errno = ERANGE;
 		return NULL;
 	}
@@ -796,21 +1076,34 @@
 }
 
-async_sess_t *fd_session(exch_mgmt_t mgmt, int fildes)
+/** Open session to service represented by a special file.
+ *
+ * Given that the file referred to by @a fildes represents a service,
+ * open a session to that service.
+ *
+ * @param fildes File descriptor
+ * @param iface Interface to connect to (XXX Should be automatic)
+ * @return On success returns session pointer. On error returns @c NULL.
+ */
+async_sess_t *vfs_fd_session(int fildes, iface_t iface)
 {
 	struct stat stat;
 	int rc = fstat(fildes, &stat);
-	if (rc != 0) {
-		errno = rc;
+	if (rc != 0)
 		return NULL;
-	}
-	
-	if (!stat.service) {
-		errno = ENOENT;
+	
+	if (stat.service == 0)
 		return NULL;
-	}
-	
-	return loc_service_connect(mgmt, stat.service, 0);
-}
-
+	
+	return loc_service_connect(stat.service, iface, 0);
+}
+
+/** Duplicate open file.
+ *
+ * Duplicate open file under a new file descriptor.
+ *
+ * @param oldfd Old file descriptor
+ * @param newfd New file descriptor
+ * @return 0 on success. On error -1 is returned and errno is set
+ */
 int dup2(int oldfd, int newfd)
 {
@@ -823,10 +1116,15 @@
 	
 	if (rc == EOK)
-		return (int) ret;
-	
-	return (int) rc;
-}
-
-int fd_wait(void)
+		rc = ret;
+	
+	if (rc != EOK) {
+		errno = rc;
+		return -1;
+	}
+	
+	return 0;
+}
+
+int vfs_fd_wait(void)
 {
 	async_exch_t *exch = vfs_exchange_begin();
@@ -843,5 +1141,5 @@
 }
 
-int get_mtab_list(list_t *mtab_list)
+int vfs_get_mtab_list(list_t *mtab_list)
 {
 	sysarg_t rc;
@@ -863,5 +1161,5 @@
 
 		mtab_ent = malloc(sizeof(mtab_ent_t));
-		if (!mtab_ent) {
+		if (mtab_ent == NULL) {
 			rc = ENOMEM;
 			goto exit;
@@ -904,4 +1202,10 @@
 }
 
+/** Get filesystem statistics.
+ *
+ * @param path Mount point path
+ * @param st Buffer for storing information
+ * @return 0 on success. On error -1 is returned and errno is set.
+ */
 int statfs(const char *path, struct statfs *st)
 {
@@ -910,7 +1214,9 @@
 	size_t pa_size;
 
-	char *pa = absolutize(path, &pa_size);
-	if (!pa)
-		return ENOMEM;
+	char *pa = vfs_absolutize(path, &pa_size);
+	if (pa == NULL) {
+		errno = ENOMEM;
+		return -1;
+	}
 
 	async_exch_t *exch = vfs_exchange_begin();
@@ -927,5 +1233,12 @@
 	free(pa);
 	async_wait_for(req, &rc_orig);
-	return (int) (rc_orig != EOK ? rc_orig : rc);
+	rc = (rc_orig != EOK ? rc_orig : rc);
+
+	if (rc != EOK) {
+		errno = rc;
+		return -1;
+	}
+
+	return 0;
 }
 
Index: uspace/lib/c/generic/vol.c
===================================================================
--- uspace/lib/c/generic/vol.c	(revision 9854a8faee04ea815f8612666a6e4dac63db2748)
+++ uspace/lib/c/generic/vol.c	(revision cffa82aac31c77f5d26f954922753c58edfef5f7)
@@ -33,4 +33,5 @@
  */
 
+#include <abi/ipc/interfaces.h>
 #include <errno.h>
 #include <ipc/services.h>
@@ -60,9 +61,9 @@
 	rc = loc_service_get_id(SERVICE_NAME_VOLSRV, &vol_svcid, 0);
 	if (rc != EOK) {
-		rc = EIO;
+		rc = ENOENT;
 		goto error;
 	}
 
-	vol->sess = loc_service_connect(EXCHANGE_SERIALIZE, vol_svcid, 0);
+	vol->sess = loc_service_connect(vol_svcid, INTERFACE_VOL, 0);
 	if (vol->sess == NULL) {
 		rc = EIO;
