[PATCH 09/23] libusbg: Add error handling to usbg_init() and related functions.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Assumption that all malloc() and read()/write() finish correctly
is too bold. Errors should be handled and propagated to upper
layers of library and returned to user.

Signed-off-by: Krzysztof Opasiak <k.opasiak@xxxxxxxxxxx>

Conflicts:

	src/usbg.c
---
 examples/gadget-acm-ecm.c |    5 +-
 examples/show-gadgets.c   |    5 +-
 include/usbg/usbg.h       |   19 ++-
 src/usbg.c                |  389 +++++++++++++++++++++++++++++++--------------
 4 files changed, 290 insertions(+), 128 deletions(-)

diff --git a/examples/gadget-acm-ecm.c b/examples/gadget-acm-ecm.c
index 5b027b6..5ab42cf 100644
--- a/examples/gadget-acm-ecm.c
+++ b/examples/gadget-acm-ecm.c
@@ -34,6 +34,7 @@ int main(void)
 	usbg_config *c;
 	usbg_function *f_acm0, *f_acm1, *f_ecm;
 	int ret = -EINVAL;
+	int usbg_ret;
 
 	usbg_gadget_attrs g_attrs = {
 			0x0200, /* bcdUSB */
@@ -56,8 +57,8 @@ int main(void)
 			"CDC 2xACM+ECM"
 	};
 
-	s = usbg_init("/sys/kernel/config");
-	if (!s) {
+	usbg_ret = usbg_init("/sys/kernel/config", &s);
+	if (usbg_ret != USBG_SUCCESS) {
 		fprintf(stderr, "Error on USB gadget init\n");
 		goto out1;
 	}
diff --git a/examples/show-gadgets.c b/examples/show-gadgets.c
index 2665262..4d79a09 100644
--- a/examples/show-gadgets.c
+++ b/examples/show-gadgets.c
@@ -125,9 +125,10 @@ int main(void)
 	usbg_gadget *g;
 	usbg_function *f;
 	usbg_config *c;
+	int usbg_ret;
 
-	s = usbg_init("/sys/kernel/config");
-	if (!s) {
+	usbg_ret = usbg_init("/sys/kernel/config", &s);
+	if (usbg_ret != USBG_SUCCESS) {
 		fprintf(stderr, "Error on USB gadget init\n");
 		return -EINVAL;
 	}
diff --git a/include/usbg/usbg.h b/include/usbg/usbg.h
index 562fdc5..ffef084 100644
--- a/include/usbg/usbg.h
+++ b/include/usbg/usbg.h
@@ -175,14 +175,29 @@ typedef union {
 	usbg_f_phonet_attrs phonet;
 } usbg_function_attrs;
 
+/**
+ * @typedef usbg_error
+ * @brief Errors which could be returned by library functions
+ */
+typedef enum  {
+	USBG_SUCCESS = 0,
+	USBG_ERROR_NO_MEM = -1,
+	USBG_ERROR_NO_ACCESS = -2,
+	USBG_ERROR_INVALID_PARAM = -3,
+	USBG_ERROR_NOT_FOUND = -4,
+	USBG_ERROR_IO = -5,
+	USBG_ERROR_OTHER_ERROR = -99
+} usbg_error;
+
 /* Library init and cleanup */
 
 /**
  * @brief Initialize the libusbg library state
  * @param configfs_path Path to the mounted configfs filesystem
- * @return Pointer to a state structure
+ * @param Pointer to be filled with pointer to usbg_state
+ * @return 0 on success, usbg_error on error
  */
-extern usbg_state *usbg_init(char *configfs_path);
+extern int usbg_init(char *configfs_path, usbg_state **state);
 
 /**
  * @brief Clean up the libusbg library state
diff --git a/src/usbg.c b/src/usbg.c
index 255074f..5cc5975 100644
--- a/src/usbg.c
+++ b/src/usbg.c
@@ -133,6 +133,35 @@ const char *function_names[] =
 		} \
 	} while (0)
 
+static int usbg_translate_error(int error)
+{
+	int ret;
+
+	switch (error) {
+	case ENOMEM:
+		ret = USBG_ERROR_NO_MEM;
+		break;
+	case EACCES:
+		ret = USBG_ERROR_NO_ACCESS;
+		break;
+	case ENOENT:
+	case ENOTDIR:
+		ret = USBG_ERROR_NOT_FOUND;
+		break;
+	case EINVAL:
+	case USBG_ERROR_INVALID_PARAM:
+		ret = USBG_ERROR_INVALID_PARAM;
+		break;
+	case EIO:
+		ret = USBG_ERROR_IO;
+		break;
+	default:
+		ret = USBG_ERROR_OTHER_ERROR;
+	}
+
+	return ret;
+}
+
 static int usbg_lookup_function_type(char *name)
 {
 	int i = 0;
@@ -169,52 +198,59 @@ static int file_select(const struct dirent *dent)
 		return 1;
 }
 
-static char *usbg_read_buf(char *path, char *name, char *file, char *buf)
+static int usbg_read_buf(char *path, char *name, char *file, char *buf)
 {
 	char p[USBG_MAX_STR_LENGTH];
 	FILE *fp;
-	char *ret = NULL;
+	int ret = USBG_SUCCESS;
 
 	sprintf(p, "%s/%s/%s", path, name, file);
 
 	fp = fopen(p, "r");
-	if (!fp)
-		goto out;
+	if (fp) {
+		/* Successfully opened */
+		if (!fgets(buf, USBG_MAX_STR_LENGTH, fp)) {
+			ERROR("read error");
+			ret = USBG_ERROR_IO;
+		}
 
-	ret = fgets(buf, USBG_MAX_STR_LENGTH, fp);
-	if (ret == NULL) {
-		ERROR("read error");
 		fclose(fp);
-		return ret;
+	} else {
+		/* Set error correctly */
+		ret = usbg_translate_error(errno);
 	}
 
-	fclose(fp);
-
-out:
 	return ret;
 }
 
-static int usbg_read_int(char *path, char *name, char *file, int base)
+static int usbg_read_int(char *path, char *name, char *file, int base,
+		int *dest)
 {
 	char buf[USBG_MAX_STR_LENGTH];
+	char *pos;
+	int ret;
 
-	if (usbg_read_buf(path, name, file, buf))
-		return strtol(buf, NULL, base);
-	else
-		return 0;
+	ret = usbg_read_buf(path, name, file, buf);
+	if (ret == USBG_SUCCESS) {
+		*dest = strtol(buf, &pos, base);
+		if (!pos)
+			ret = USBG_ERROR_OTHER_ERROR;
+	}
 
+	return ret;
 }
 
-#define usbg_read_dec(p, n, f)	usbg_read_int(p, n, f, 10)
-#define usbg_read_hex(p, n, f)	usbg_read_int(p, n, f, 16)
+#define usbg_read_dec(p, n, f, d)	usbg_read_int(p, n, f, 10, d)
+#define usbg_read_hex(p, n, f, d)	usbg_read_int(p, n, f, 16, d)
 
-static void usbg_read_string(char *path, char *name, char *file, char *buf)
+static int usbg_read_string(char *path, char *name, char *file, char *buf)
 {
 	char *p = NULL;
+	int ret;
 
-	p = usbg_read_buf(path, name, file, buf);
+	ret = usbg_read_buf(path, name, file, buf);
 	/* Check whether read was successful */
-	if (p != NULL) {
+	if (ret == USBG_SUCCESS) {
 		if ((p = strchr(buf, '\n')) != NULL)
 				*p = '\0';
 	} else {
@@ -222,6 +258,7 @@ static void usbg_read_string(char *path, char *name, char *file, char *buf)
 		*buf = '\0';
 	}
 
+	return ret;
 }
 
 static void usbg_write_buf(char *path, char *name, char *file, char *buf)
@@ -315,6 +352,7 @@ static void usbg_free_state(usbg_state *s)
 	free(s);
 }
 
+
 static void usbg_parse_function_attrs(usbg_function *f,
 		usbg_function_attrs *f_attrs)
 {
@@ -325,7 +363,7 @@ static void usbg_parse_function_attrs(usbg_function *f,
 	case F_SERIAL:
 	case F_ACM:
 	case F_OBEX:
-		f_attrs->serial.port_num = usbg_read_dec(f->path, f->name, "port_num");
+		usbg_read_dec(f->path, f->name, "port_num", &(f_attrs->serial.port_num));
 		break;
 	case F_ECM:
 	case F_SUBSET:
@@ -343,7 +381,7 @@ static void usbg_parse_function_attrs(usbg_function *f,
 			f_attrs->net.host_addr = *addr;
 
 		usbg_read_string(f->path, f->name, "ifname", f_attrs->net.ifname);
-		f_attrs->net.qmult = usbg_read_dec(f->path, f->name, "qmult");
+		usbg_read_dec(f->path, f->name, "qmult", &(f_attrs->net.qmult));
 		break;
 	case F_PHONET:
 		usbg_read_string(f->path, f->name, "ifname", f_attrs->phonet.ifname);
@@ -357,33 +395,47 @@ static int usbg_parse_functions(char *path, usbg_gadget *g)
 {
 	usbg_function *f;
 	int i, n;
+	int ret = USBG_SUCCESS;
+
 	struct dirent **dent;
 	char fpath[USBG_MAX_PATH_LENGTH];
 
 	sprintf(fpath, "%s/%s/%s", path, g->name, FUNCTIONS_DIR);
 
-	TAILQ_INIT(&g->functions);
-
 	n = scandir(fpath, &dent, file_select, alphasort);
-	for (i=0; i < n; i++) {
-		f = malloc(sizeof(usbg_function));
-		f->parent = g;
-		strcpy(f->name, dent[i]->d_name);
-		strcpy(f->path, fpath);
-		f->type = usbg_lookup_function_type(strtok(dent[i]->d_name, "."));
-		TAILQ_INSERT_TAIL(&g->functions, f, fnode);
-		free(dent[i]);
+	if (n >= 0) {
+		for (i = 0; i < n; i++) {
+			if (ret == USBG_SUCCESS) {
+				f = malloc(sizeof(usbg_function));
+				if (f) {
+					f->parent = g;
+					strcpy(f->name, dent[i]->d_name);
+					strcpy(f->path, fpath);
+					f->type = usbg_lookup_function_type(
+							strtok(dent[i]->d_name, "."));
+					TAILQ_INSERT_TAIL(&g->functions, f, fnode);
+				} else {
+					ret = USBG_ERROR_NO_MEM;
+				}
+			}
+			free(dent[i]);
+		}
+		free(dent);
+	} else {
+		ret = usbg_translate_error(errno);
 	}
-	free(dent);
 
-	return 0;
+	return ret;
 }
 
 static void usbg_parse_config_attrs(char *path, char *name,
 		usbg_config_attrs *c_attrs)
 {
-	c_attrs->bMaxPower = usbg_read_dec(path, name, "MaxPower");
-	c_attrs->bmAttributes = usbg_read_hex(path, name, "bmAttributes");
+	int buf;
+	usbg_read_dec(path, name, "MaxPower", &buf);
+	c_attrs->bMaxPower = (uint8_t)buf;
+	usbg_read_hex(path, name, "bmAttributes", &buf);
+	c_attrs->bmAttributes = (uint8_t)buf;
 }
 
 static usbg_config_strs *usbg_parse_config_strs(char *path, char *name,
@@ -406,9 +458,10 @@ static usbg_config_strs *usbg_parse_config_strs(char *path, char *name,
 	return c_strs;
 }
 
-static void usbg_parse_config_bindings(usbg_config *c)
+static int usbg_parse_config_bindings(usbg_config *c)
 {
 	int i, n, nmb;
+	int ret = USBG_SUCCESS;
 	struct dirent **dent;
 	char bpath[USBG_MAX_PATH_LENGTH];
 	char file_name[USBG_MAX_PATH_LENGTH];
@@ -420,76 +473,134 @@ static void usbg_parse_config_bindings(usbg_config *c)
 
 	sprintf(bpath, "%s/%s", c->path, c->name);
 
-	TAILQ_INIT(&c->bindings);
-
 	n = scandir(bpath, &dent, bindings_select, alphasort);
-	for (i = 0; i < n; i++) {
-		sprintf(file_name, "%s/%s", bpath, dent[i]->d_name);
-		nmb = readlink(file_name, target, USBG_MAX_PATH_LENGTH);
-		if (nmb < 0)
-			ERRORNO("bytes %d contents %s\n", n, target);
-
-		/* readlink() don't add this, so we have to do it manually */
-		target[nmb] = '\0';
-		/* Target contains a full path
-		 *  but we need only function dir name */
+	if (n >= 0) {
+		for (i = 0; i < n; i++) {
+			sprintf(file_name, "%s/%s", bpath, dent[i]->d_name);
+			nmb = readlink(file_name, target, USBG_MAX_PATH_LENGTH);
+			if (nmb >= 0) {
+				/* readlink() don't add this,
+				 * so we have to do it manually */
+				target[nmb] = '\0';
+				/* Target contains a full path
+				 * but we need only function dir name */
 				target_name = strrchr(target, '/') + 1;
 
-		TAILQ_FOREACH(f, &g->functions, fnode)
-		{
-			/* Check if this is our target function */
-			if (strcmp(f->name, target_name) == 0) {
+				f = usbg_get_function(g, target_name);
+
 				b = malloc(sizeof(usbg_binding));
-				strcpy(b->name, dent[i]->d_name);
-				strcpy(b->path, bpath);
-				b->target = f;
-				TAILQ_INSERT_TAIL(&c->bindings, b, bnode);
-				break;
+				if (b) {
+					strcpy(b->name, dent[i]->d_name);
+					strcpy(b->path, bpath);
+					b->target = f;
+					TAILQ_INSERT_TAIL(&c->bindings, b, bnode);
+				} else {
+					ret = USBG_ERROR_NO_MEM;
+				}
+			} else {
+				ret = usbg_translate_error(errno);
 			}
+
+			free(dent[i]);
 		}
-		free(dent[i]);
+		free(dent);
+	} else {
+		ret = usbg_translate_error(errno);
 	}
-	free(dent);
+
+	return ret;
 }
 
 static int usbg_parse_configs(char *path, usbg_gadget *g)
 {
 	usbg_config *c;
 	int i, n;
+	int ret = USBG_SUCCESS;
 	struct dirent **dent;
 	char cpath[USBG_MAX_PATH_LENGTH];
 
 	sprintf(cpath, "%s/%s/%s", path, g->name, CONFIGS_DIR);
 
-	TAILQ_INIT(&g->configs);
-
 	n = scandir(cpath, &dent, file_select, alphasort);
-	for (i=0; i < n; i++) {
-		c = malloc(sizeof(usbg_config));
-		c->parent = g;
-		strcpy(c->name, dent[i]->d_name);
-		strcpy(c->path, cpath);
-		usbg_parse_config_bindings(c);
-		TAILQ_INSERT_TAIL(&g->configs, c, cnode);
-		free(dent[i]);
+	if (n >= 0) {
+		for (i = 0; i < n; i++) {
+			if (ret == USBG_SUCCESS) {
+				c = malloc(sizeof(usbg_config));
+				if (c) {
+					c->parent = g;
+					strcpy(c->name, dent[i]->d_name);
+					strcpy(c->path, cpath);
+					TAILQ_INIT(&c->bindings);
+					ret = usbg_parse_config_bindings(c);
+					if (ret == USBG_SUCCESS)
+						TAILQ_INSERT_TAIL(&g->configs, c, cnode);
+					else
+						usbg_free_config(c);
+				} else {
+					ret = USBG_ERROR_NO_MEM;
+				}
+			}
+			free(dent[i]);
+		}
+		free(dent);
+	} else {
+		ret = usbg_translate_error(errno);
 	}
-	free(dent);
 
-	return 0;
+	return ret;
 }
 
-static void usbg_parse_gadget_attrs(char *path, char *name,
+static int usbg_parse_gadget_attrs(char *path, char *name,
 		usbg_gadget_attrs *g_attrs)
 {
+	int buf, ret;
+
 	/* Actual attributes */
-	g_attrs->bcdUSB = (uint16_t)usbg_read_hex(path, name, "bcdUSB");
-	g_attrs->bDeviceClass = (uint8_t)usbg_read_hex(path, name, "bDeviceClass");
-	g_attrs->bDeviceSubClass = (uint8_t)usbg_read_hex(path, name, "bDeviceSubClass");
-	g_attrs->bDeviceProtocol = (uint8_t)usbg_read_hex(path, name, "bDeviceProtocol");
-	g_attrs->bMaxPacketSize0 = (uint8_t)usbg_read_hex(path, name, "bMaxPacketSize0");
-	g_attrs->idVendor = (uint16_t)usbg_read_hex(path, name, "idVendor");
-	g_attrs->idProduct = (uint16_t)usbg_read_hex(path, name, "idProduct");
-	g_attrs->bcdDevice = (uint16_t)usbg_read_hex(path, name, "bcdDevice");
+
+	ret = usbg_read_hex(path, name, "bcdUSB", &buf);
+	if (ret == USBG_SUCCESS)
+		g_attrs->bcdUSB = (uint16_t) buf;
+	else
+		goto out;
+
+	ret = usbg_read_hex(path, name, "bDeviceClass", &buf);
+	if (ret == USBG_SUCCESS)
+		g_attrs->bDeviceClass = (uint8_t)buf;
+	else
+		goto out;
+
+	ret = usbg_read_hex(path, name, "bDeviceSubClass", &buf);
+	if (ret == USBG_SUCCESS)
+		g_attrs->bDeviceSubClass = (uint8_t)buf;
+	else
+		goto out;
+
+	ret = usbg_read_hex(path, name, "bDeviceProtocol", &buf);
+	if (ret == USBG_SUCCESS)
+		g_attrs->bDeviceProtocol = (uint8_t) buf;
+	else
+		goto out;
+
+	ret = usbg_read_hex(path, name, "bMaxPacketSize0", &buf);
+	if (ret == USBG_SUCCESS)
+		g_attrs->bMaxPacketSize0 = (uint8_t) buf;
+	else
+		goto out;
+
+	ret = usbg_read_hex(path, name, "idVendor", &buf);
+	if (ret == USBG_SUCCESS)
+		g_attrs->idVendor = (uint16_t) buf;
+	else
+		goto out;
+
+	ret = usbg_read_hex(path, name, "idProduct", &buf);
+	if (ret == USBG_SUCCESS)
+		g_attrs->idProduct = (uint16_t) buf;
+	else
+		goto out;
+
+out:
+	return ret;
 }
 
 static usbg_gadget_strs *usbg_parse_strings(char *path, char *name, int lang,
@@ -514,75 +625,109 @@ static usbg_gadget_strs *usbg_parse_strings(char *path, char *name, int lang,
 	return g_strs;
 }
 
+static inline int usbg_parse_gadget(char *path, char *name, usbg_state *parent,
+		usbg_gadget *g)
+{
+	int ret = USBG_SUCCESS;
+
+	strcpy(g->name, name);
+	strcpy(g->path, path);
+	g->parent = parent;
+	TAILQ_INIT(&g->functions);
+	TAILQ_INIT(&g->configs);
+
+	/* UDC bound to, if any */
+	ret = usbg_read_string(path, g->name, "UDC", g->udc);
+	if (ret != USBG_SUCCESS)
+		goto out;
+
+	ret = usbg_parse_functions(path, g);
+	if (ret != USBG_SUCCESS)
+		goto out;
+
+	ret = usbg_parse_configs(path, g);
+out:
+	return ret;
+}
+
 static int usbg_parse_gadgets(char *path, usbg_state *s)
 {
 	usbg_gadget *g;
 	int i, n;
+	int ret = USBG_SUCCESS;
 	struct dirent **dent;
 
-	TAILQ_INIT(&s->gadgets);
-
 	n = scandir(path, &dent, file_select, alphasort);
-	for (i=0; i < n; i++) {
-		g = malloc(sizeof(usbg_gadget));
-		strcpy(g->name, dent[i]->d_name);
-		strcpy(g->path, s->path);
-		g->parent = s;
-		/* UDC bound to, if any */
-		usbg_read_string(path, g->name, "UDC", g->udc);
-		usbg_parse_functions(path, g);
-		usbg_parse_configs(path, g);
-		TAILQ_INSERT_TAIL(&s->gadgets, g, gnode);
-		free(dent[i]);
+	if (n >= 0) {
+		for (i = 0; i < n; i++) {
+			/* Check if earlier gadgets
+			 * has been created correctly */
+			if (ret == USBG_SUCCESS) {
+				/* Create new gadget and insert it into list */
+				g = malloc(sizeof(usbg_gadget));
+				if (g) {
+					ret = usbg_parse_gadget(path, dent[i]->d_name, s, g);
+					if (ret == USBG_SUCCESS)
+						TAILQ_INSERT_TAIL(&s->gadgets, g, gnode);
+					else
+						usbg_free_gadget(g);
+				} else {
+					ret = USBG_ERROR_NO_MEM;
+				}
+			}
+			free(dent[i]);
+		}
+		free(dent);
+	} else {
+		ret = usbg_translate_error(errno);
 	}
-	free(dent);
 
-	return 0;
+	return ret;
 }
 
 static int usbg_init_state(char *path, usbg_state *s)
 {
+	int ret = USBG_SUCCESS;
+
 	strcpy(s->path, path);
+	TAILQ_INIT(&s->gadgets);
 
-	if (usbg_parse_gadgets(path, s) < 0) {
+	ret = usbg_parse_gadgets(path, s);
+	if (ret != USBG_SUCCESS)
 		ERRORNO("unable to parse %s\n", path);
-		return -1;
-	}
 
-	return 0;
+	return ret;
 }
 
 /*
  * User API
  */
 
-usbg_state *usbg_init(char *configfs_path)
+int usbg_init(char *configfs_path, usbg_state **state)
 {
-	int ret;
-	struct stat sts;
+	int ret = USBG_SUCCESS;
+	DIR *dir;
 	char path[USBG_MAX_PATH_LENGTH];
-	usbg_state *s = NULL;
 
-	strcpy(path, configfs_path);
-	ret = stat(strcat(path, "/usb_gadget"), &sts);
-	if (ret < 0) {
-		ERRORNO("%s", path);
-		goto out;
-	}
-
-	if (!S_ISDIR(sts.st_mode)) {
-		ERRORNO("%s", path);
-		goto out;
-	}
+	sprintf(path, "%s/usb_gadget", configfs_path);
 
-	s = malloc(sizeof(usbg_state));
-	if (s)
-		usbg_init_state(path, s);
-	else
+	/* Check if directory exist */
+	dir = opendir(path);
+	if (dir) {
+		closedir(dir);
+		*state = malloc(sizeof(usbg_state));
+		ret = *state ? usbg_init_state(path, *state)
+			 : USBG_ERROR_NO_MEM;
+		if (*state && ret != USBG_SUCCESS) {
+			ERRORNO("couldn't init gadget state\n");
+			usbg_free_state(*state);
+		}
+	} else {
 		ERRORNO("couldn't init gadget state\n");
+		ret = usbg_translate_error(errno);
+	}
 
-out:
-	return s;
+	return ret;
 }
 
 void usbg_cleanup(usbg_state *s)
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux