Index: uspace/lib/c/generic/loc.c
===================================================================
--- uspace/lib/c/generic/loc.c	(revision 16dc8870242df10ae64ee7bcbf125aa8607cb7fb)
+++ uspace/lib/c/generic/loc.c	(revision 278ac72d2dae454404705248646f24d3dd51f94c)
@@ -589,12 +589,11 @@
 }
 
-static int loc_category_get_svcs_internal(category_id_t cat_id,
-    service_id_t *id_buf, size_t buf_size, size_t *act_size)
+static int loc_category_get_ids_once(sysarg_t method, sysarg_t arg1,
+    sysarg_t *id_buf, size_t buf_size, size_t *act_size)
 {
 	async_exch_t *exch = loc_exchange_begin_blocking(LOC_PORT_CONSUMER);
 
 	ipc_call_t answer;
-	aid_t req = async_send_1(exch, LOC_CATEGORY_GET_SVCS, cat_id,
-	    &answer);
+	aid_t req = async_send_1(exch, method, arg1, &answer);
 	int rc = async_data_read_start(exch, id_buf, buf_size);
 	
@@ -614,4 +613,57 @@
 	
 	*act_size = IPC_GET_ARG1(answer);
+	return EOK;
+}
+
+/** Get list of IDs.
+ *
+ * Returns an allocated array of service IDs.
+ *
+ * @param method	IPC method
+ * @param arg1		IPC argument 1
+ * @param data		Place to store pointer to array of IDs
+ * @param count		Place to store number of IDs
+ * @return 		EOK on success or negative error code
+ */
+static int loc_get_ids_internal(sysarg_t method, sysarg_t arg1,
+    sysarg_t **data, size_t *count)
+{
+	service_id_t *ids;
+	size_t act_size;
+	size_t alloc_size;
+	int rc;
+
+	*data = NULL;
+	act_size = 0;	/* silence warning */
+
+	rc = loc_category_get_ids_once(method, arg1, NULL, 0,
+	    &act_size);
+	if (rc != EOK)
+		return rc;
+
+	alloc_size = act_size;
+	ids = malloc(alloc_size);
+	if (ids == NULL)
+		return ENOMEM;
+
+	while (true) {
+		rc = loc_category_get_ids_once(method, arg1, ids, alloc_size,
+		    &act_size);
+		if (rc != EOK)
+			return rc;
+
+		if (act_size <= alloc_size)
+			break;
+
+		alloc_size *= 2;
+		free(ids);
+
+		ids = malloc(alloc_size);
+		if (ids == NULL)
+			return ENOMEM;
+	}
+
+	*count = act_size / sizeof(category_id_t);
+	*data = ids;
 	return EOK;
 }
@@ -626,43 +678,22 @@
  * @return 		EOK on success or negative error code
  */
-int loc_category_get_svcs(category_id_t cat_id, category_id_t **data,
+int loc_category_get_svcs(category_id_t cat_id, service_id_t **data,
     size_t *count)
 {
-	service_id_t *ids;
-	size_t act_size;
-	size_t alloc_size;
-	int rc;
-
-	*data = NULL;
-	act_size = 0;	/* silence warning */
-
-	rc = loc_category_get_svcs_internal(cat_id, NULL, 0, &act_size);
-	if (rc != EOK)
-		return rc;
-
-	alloc_size = act_size;
-	ids = malloc(alloc_size);
-	if (ids == NULL)
-		return ENOMEM;
-
-	while (true) {
-		rc = loc_category_get_svcs_internal(cat_id, ids, alloc_size,
-		    &act_size);
-		if (rc != EOK)
-			return rc;
-
-		if (act_size <= alloc_size)
-			break;
-
-		alloc_size *= 2;
-		free(ids);
-
-		ids = malloc(alloc_size);
-		if (ids == NULL)
-			return ENOMEM;
-	}
-
-	*count = act_size / sizeof(category_id_t);
-	*data = ids;
-	return EOK;
-}
+	return loc_get_ids_internal(LOC_CATEGORY_GET_SVCS, cat_id,
+	    data, count);
+}
+
+/** Get list of categories.
+ *
+ * Returns an allocated array of category IDs.
+ *
+ * @param data		Place to store pointer to array of IDs
+ * @param count		Place to store number of IDs
+ * @return 		EOK on success or negative error code
+ */
+int loc_get_categories(category_id_t **data, size_t *count)
+{
+	return loc_get_ids_internal(LOC_GET_CATEGORIES, 0,
+	    data, count);
+}
Index: uspace/lib/c/include/ipc/loc.h
===================================================================
--- uspace/lib/c/include/ipc/loc.h	(revision 16dc8870242df10ae64ee7bcbf125aa8607cb7fb)
+++ uspace/lib/c/include/ipc/loc.h	(revision 278ac72d2dae454404705248646f24d3dd51f94c)
@@ -63,4 +63,5 @@
 	LOC_GET_NAMESPACE_COUNT,
 	LOC_GET_SERVICE_COUNT,
+	LOC_GET_CATEGORIES,
 	LOC_GET_NAMESPACES,
 	LOC_GET_SERVICES
Index: uspace/lib/c/include/loc.h
===================================================================
--- uspace/lib/c/include/loc.h	(revision 16dc8870242df10ae64ee7bcbf125aa8607cb7fb)
+++ uspace/lib/c/include/loc.h	(revision 278ac72d2dae454404705248646f24d3dd51f94c)
@@ -70,4 +70,6 @@
 extern size_t loc_get_namespaces(loc_sdesc_t **);
 extern size_t loc_get_services(service_id_t, loc_sdesc_t **);
+extern int loc_get_categories(category_id_t **, size_t *);
+
 
 #endif
Index: uspace/srv/loc/category.c
===================================================================
--- uspace/srv/loc/category.c	(revision 16dc8870242df10ae64ee7bcbf125aa8607cb7fb)
+++ uspace/srv/loc/category.c	(revision 278ac72d2dae454404705248646f24d3dd51f94c)
@@ -54,4 +54,35 @@
 	list_append(&cat->cat_list, &cdir->categories);
 }
+
+/** Get list of categories. */
+int categ_dir_get_categories(categ_dir_t *cdir, category_id_t *id_buf,
+    size_t buf_size, size_t *act_size)
+{
+	size_t act_cnt;
+	size_t buf_cnt;
+
+	assert(fibril_mutex_is_locked(&cdir->mutex));
+
+	buf_cnt = buf_size / sizeof(category_id_t);
+
+	act_cnt = list_count(&cdir->categories);
+	*act_size = act_cnt * sizeof(category_id_t);
+
+	if (buf_size % sizeof(category_id_t) != 0)
+		return EINVAL;
+
+	size_t pos = 0;
+	list_foreach(cdir->categories, item) {
+		category_t *cat =
+		    list_get_instance(item, category_t, cat_list);
+
+		if (pos < buf_cnt)
+			id_buf[pos] = cat->id;
+		pos++;
+	}
+
+	return EOK;
+}
+
 
 /** Initialize category structure. */
Index: uspace/srv/loc/category.h
===================================================================
--- uspace/srv/loc/category.h	(revision 16dc8870242df10ae64ee7bcbf125aa8607cb7fb)
+++ uspace/srv/loc/category.h	(revision 278ac72d2dae454404705248646f24d3dd51f94c)
@@ -69,4 +69,6 @@
 extern void categ_dir_init(categ_dir_t *);
 extern void categ_dir_add_cat(categ_dir_t *, category_t *);
+extern int categ_dir_get_categories(categ_dir_t *, service_id_t *, size_t,
+    size_t *);
 extern category_t *category_new(const char *);
 extern int category_add_service(category_t *, loc_service_t *);
Index: uspace/srv/loc/loc.c
===================================================================
--- uspace/srv/loc/loc.c	(revision 16dc8870242df10ae64ee7bcbf125aa8607cb7fb)
+++ uspace/srv/loc/loc.c	(revision 278ac72d2dae454404705248646f24d3dd51f94c)
@@ -755,4 +755,43 @@
 }
 
+static void loc_get_categories(ipc_callid_t iid, ipc_call_t *icall)
+{
+	ipc_callid_t callid;
+	size_t size;
+	size_t act_size;
+	int rc;
+	
+	if (!async_data_read_receive(&callid, &size)) {
+		async_answer_0(callid, EREFUSED);
+		async_answer_0(iid, EREFUSED);
+		return;
+	}
+	
+	category_id_t *id_buf = (category_id_t *) malloc(size);
+	if (id_buf == NULL) {
+		fibril_mutex_unlock(&cdir.mutex);
+		async_answer_0(callid, ENOMEM);
+		async_answer_0(iid, ENOMEM);
+		return;
+	}
+	
+	fibril_mutex_lock(&cdir.mutex);
+	
+	rc = categ_dir_get_categories(&cdir, id_buf, size, &act_size);
+	if (rc != EOK) {
+		fibril_mutex_unlock(&cdir.mutex);
+		async_answer_0(callid, rc);
+		async_answer_0(iid, rc);
+		return;
+	}
+	
+	fibril_mutex_unlock(&cdir.mutex);
+	
+	sysarg_t retval = async_data_read_finalize(callid, id_buf, size);
+	free(id_buf);
+	
+	async_answer_1(iid, retval, act_size);
+}
+
 static void loc_get_namespaces(ipc_callid_t iid, ipc_call_t *icall)
 {
@@ -1181,4 +1220,7 @@
 		case LOC_GET_SERVICE_COUNT:
 			loc_get_service_count(callid, &call);
+			break;
+		case LOC_GET_CATEGORIES:
+			loc_get_categories(callid, &call);
 			break;
 		case LOC_GET_NAMESPACES:
