diff mbox series

[v3] diskpart_handler: support explicitly sized partitions

Message ID 20220308215920.2270478-1-bkylerussell@gmail.com
State Changes Requested
Headers show
Series [v3] diskpart_handler: support explicitly sized partitions | expand

Commit Message

Kyle Russell March 8, 2022, 9:59 p.m. UTC
When passing in a partition size in units of sectors, fdisk expects you to
enable explicit sizing on the partition; otherwise, fdisk assumes you want
the partition aligned to the nearest grain (typically 1MB), which may
corrupt a partition table containing already explicitly sized partitions.

This matches the behavior of other libfdisk clients in util-linux (see
excerpt from libfdisk's parse_line_nameval() below):

libfdisk/src/script.c:
        if (pow)        /* specified as <num><suffix> */
                num /= dp->cxt->sector_size;
        else            /* specified as number of sectors */
                fdisk_partition_size_explicit(pa, 1);

To achieve this, we allow ustrtoull() to return a char* to the suffix
of the converted string, if one exists.  If the suffix points to '\0',
then the entire string was a valid integer, and we assume the user
provided an explicit partition size.  Otherwise, the default behavior
occurs and fdisk aligns the partition to the nearest grain.

Signed-off-by: Kyle Russell <bkylerussell@gmail.com>
---
 core/util.c                 | 28 ++++++++++++++++++----------
 corelib/lua_interface.c     |  2 +-
 handlers/delta_handler.c    |  2 +-
 handlers/diskpart_handler.c | 19 +++++++++++++------
 include/util.h              |  2 +-
 parser/parse_external.c     |  2 +-
 parser/parser.c             |  2 +-
 suricatta/common.c          |  2 +-
 suricatta/server_general.c  |  2 +-
 suricatta/server_hawkbit.c  |  2 +-
 10 files changed, 39 insertions(+), 24 deletions(-)

Comments

Stefano Babic March 9, 2022, 9:22 a.m. UTC | #1
Hi Kyle,

On 08.03.22 22:59, Kyle Russell wrote:
> When passing in a partition size in units of sectors, fdisk expects you to
> enable explicit sizing on the partition; otherwise, fdisk assumes you want
> the partition aligned to the nearest grain (typically 1MB), which may
> corrupt a partition table containing already explicitly sized partitions.
> 
> This matches the behavior of other libfdisk clients in util-linux (see
> excerpt from libfdisk's parse_line_nameval() below):
> 
> libfdisk/src/script.c:
>          if (pow)        /* specified as <num><suffix> */
>                  num /= dp->cxt->sector_size;
>          else            /* specified as number of sectors */
>                  fdisk_partition_size_explicit(pa, 1);
> 
> To achieve this, we allow ustrtoull() to return a char* to the suffix
> of the converted string, if one exists.  If the suffix points to '\0',
> then the entire string was a valid integer, and we assume the user
> provided an explicit partition size.  Otherwise, the default behavior
> occurs and fdisk aligns the partition to the nearest grain.
> 

The new post lets me to think again and (apart that your patch is ok) 
check about the semantic of ustrtoull(). I fully agree to change it, 
because it becomes the same syntax as strtoull() - it was written in 
this way first, see commit 94f9a86f. The thing is what is returning: 
strtoull() returns the first "invalid" character, and this is the topic. 
Is the size delimiter in ustrtoull() an invalid character ? Really not, 
because it is decoded. So if we will use the function in other context, 
like :

	size = ustrtoull("1024G, some fancy things", &endptr, 10);

we would like to get in endptr what was not decoded, that is after the "G".

This does not work with your rule to check for a '\0', but what you want 
to check if there is a size delimiter. You could do in another way, for 
example checking then endptr from ustrtoull() and strtoul(). Instead of:

part->size = ustrtoull(equal, &suffix, 10);

You could call also strtoull(equal, &suffix1, 10), and for your test 
case, suffix == suffix1.



> Signed-off-by: Kyle Russell <bkylerussell@gmail.com>
> ---
>   core/util.c                 | 28 ++++++++++++++++++----------
>   corelib/lua_interface.c     |  2 +-
>   handlers/delta_handler.c    |  2 +-
>   handlers/diskpart_handler.c | 19 +++++++++++++------
>   include/util.h              |  2 +-
>   parser/parse_external.c     |  2 +-
>   parser/parser.c             |  2 +-
>   suricatta/common.c          |  2 +-
>   suricatta/server_general.c  |  2 +-
>   suricatta/server_hawkbit.c  |  2 +-
>   10 files changed, 39 insertions(+), 24 deletions(-)
> 
> diff --git a/core/util.c b/core/util.c
> index 4c8c034..7525521 100644
> --- a/core/util.c
> +++ b/core/util.c
> @@ -743,7 +743,15 @@ void free_string_array(char **nodes)
>   	free(nodes);
>   }
>   
> -unsigned long long ustrtoull(const char *cp, unsigned int base)
> +/*
> + * Like strtoull(), but automatically scales the conversion
> + * result by size-type units, and only returns a pointer to
> + * the size unit in the string if requested by the caller.
> + *
> + * Sets errno to ERANGE if strtoull() found no digits or
> + * encountered an overflow, and returns 0 in both cases.
> + */
> +unsigned long long ustrtoull(const char *cp, char **endptr, unsigned int base)
>   {
>   	errno = 0;
>   	char *endp = NULL;
> @@ -756,7 +764,8 @@ unsigned long long ustrtoull(const char *cp, unsigned int base)
>   
>   	if (cp == endp || (result == ULLONG_MAX && errno == ERANGE)) {
>   		errno = ERANGE;
> -		return 0;
> +		result = 0;
> +		goto out;
>   	}
>   
>   	switch (*endp) {
> @@ -769,13 +778,12 @@ unsigned long long ustrtoull(const char *cp, unsigned int base)
>   	case 'K':
>   	case 'k':
>   		result *= 1024;
> -		if (endp[1] == 'i') {
> -			if (endp[2] == 'B')
> -				endp += 3;
> -			else
> -				endp += 2;
> -		}

This is not wrong and should not be dropped. It is allowed to have GiB, 
or KiB, or MiB, and the delimiter is then dropped from result, that is 
endp must be increased.

>   	}
> +
> +out:
> +	if (endptr)
> +		*endptr = endp;
> +
>   	return result;
>   }
>   
> @@ -1196,7 +1204,7 @@ long long get_output_size(struct img_type *img, bool strict)
>   			return -ENOENT;
>   		}
>   
> -		bytes = ustrtoull(output_size_str, 0);
> +		bytes = ustrtoull(output_size_str, NULL, 0);
>   		if (errno || bytes <= 0) {
>   			ERROR("decompressed-size argument %s: ustrtoull failed",
>   			      output_size_str);
> @@ -1214,7 +1222,7 @@ long long get_output_size(struct img_type *img, bool strict)
>   			return -ENOENT;
>   		}
>   
> -		bytes = ustrtoull(output_size_str, 0);
> +		bytes = ustrtoull(output_size_str, NULL, 0);
>   		if (errno || bytes <= 0) {
>   			ERROR("decrypted-size argument %s: ustrtoull failed",
>   			      output_size_str);
> diff --git a/corelib/lua_interface.c b/corelib/lua_interface.c
> index c15592f..52b6605 100644
> --- a/corelib/lua_interface.c
> +++ b/corelib/lua_interface.c
> @@ -319,7 +319,7 @@ static void lua_string_to_img(struct img_type *img, const char *key,
>   		strncpy(seek_str, value,
>   			sizeof(seek_str));
>   		/* convert the offset handling multiplicative suffixes */
> -		img->seek = ustrtoull(seek_str, 0);
> +		img->seek = ustrtoull(seek_str, NULL, 0);
>   		if (errno){
>   			ERROR("offset argument: ustrtoull failed");
>   		}
> diff --git a/handlers/delta_handler.c b/handlers/delta_handler.c
> index 3132f2e..f8d330c 100644
> --- a/handlers/delta_handler.c
> +++ b/handlers/delta_handler.c
> @@ -329,7 +329,7 @@ static int delta_retrieve_attributes(struct img_type *img, struct hnd_priv *priv
>   		if (!strcmp(srcsize, "detect"))
>   			priv->detectsrcsize = true;
>   		else
> -			priv->srcsize = ustrtoull(srcsize, 10);
> +			priv->srcsize = ustrtoull(srcsize, NULL, 10);
>   	}
>   
>   	char *zckloglevel = dict_get_value(&img->properties, "zckloglevel");
> diff --git a/handlers/diskpart_handler.c b/handlers/diskpart_handler.c
> index fc9b169..d584bda 100644
> --- a/handlers/diskpart_handler.c
> +++ b/handlers/diskpart_handler.c
> @@ -74,6 +74,7 @@ struct partition_data {
>   	char fstype[SWUPDATE_GENERAL_STRING_SIZE];
>   	char dostype[SWUPDATE_GENERAL_STRING_SIZE];
>   	char partuuid[UUID_STR_LEN];
> +	int explicit_size;
>   	LIST_ENTRY(partition_data) next;
>   };
>   LIST_HEAD(listparts, partition_data);
> @@ -305,10 +306,13 @@ static int diskpart_set_partition(struct fdisk_partition *pa,
>   		ret |= -EINVAL;
>   	if (strlen(part->name))
>   	      ret |= fdisk_partition_set_name(pa, part->name);
> -	if (part->size != LIBFDISK_INIT_UNDEF(part->size))
> +	if (part->size != LIBFDISK_INIT_UNDEF(part->size)) {
>   	      ret |= fdisk_partition_set_size(pa, part->size / sector_size);
> -	else
> +	      if (part->explicit_size)
> +			ret |= fdisk_partition_size_explicit(pa, part->explicit_size);
> +	} else {
>   		ret |= fdisk_partition_end_follow_default(pa, 1);
> +	}
>   
>   	if (parttype)
>   		ret |= fdisk_partition_set_type(pa, parttype);
> @@ -543,7 +547,7 @@ static int diskpart_fill_table(struct fdisk_context *cxt, struct diskpart_table
>   				parttype = fdisk_label_get_parttype_from_string(lb, GPT_DEFAULT_ENTRY_TYPE);
>   			}
>   		} else {
> -			parttype = fdisk_label_get_parttype_from_code(lb, ustrtoull(part->type, 16));
> +			parttype = fdisk_label_get_parttype_from_code(lb, ustrtoull(part->type, NULL, 16));
>   		}
>   		ret = diskpart_set_partition(newpa, part, sector_size, parttype, oldtb->parent);
>   		if (ret) {
> @@ -578,7 +582,7 @@ static int diskpart_fill_table(struct fdisk_context *cxt, struct diskpart_table
>   
>   				newpa = fdisk_new_partition();
>   
> -				parttype = fdisk_label_get_parttype_from_code(lb, ustrtoull(part->dostype, 16));
> +				parttype = fdisk_label_get_parttype_from_code(lb, ustrtoull(part->dostype, NULL, 16));
>   				if (!parttype) {
>   					ERROR("I cannot add hybrid partition %zu(%s) invalid dostype: %s",
>   						part->partno, part->name, part->dostype);
> @@ -846,6 +850,7 @@ static int diskpart(struct img_type *img,
>   		part->partno = strtoul(entry->key  + strlen("partition-"), NULL, 10);
>   		while (elem) {
>   			char *equal = index(elem->value, '=');
> +			char *suffix = NULL;
>   			if (equal) {
>   				for (i = 0; i < ARRAY_SIZE(fields); i++) {
>   					if (!((equal - elem->value) == strlen(fields[i]) &&
> @@ -854,10 +859,12 @@ static int diskpart(struct img_type *img,
>   					equal++;
>   					switch (i) {
>   					case PART_SIZE:
> -						part->size = ustrtoull(equal, 10);
> +						part->size = ustrtoull(equal, &suffix, 10);
> +						if (*suffix == '\0')
> +							part->explicit_size = 1;
>   						break;
>   					case PART_START:
> -						part->start = ustrtoull(equal, 10);
> +						part->start = ustrtoull(equal, NULL, 10);
>   						break;
>   					case PART_TYPE:
>   						strncpy(part->type, equal, sizeof(part->type));
> diff --git a/include/util.h b/include/util.h
> index 950046d..3d52a93 100644
> --- a/include/util.h
> +++ b/include/util.h
> @@ -228,7 +228,7 @@ void set_version_range(const char *minversion,
>   			const char *maxversion,
>   			const char *current);
>   
> -unsigned long long ustrtoull(const char *cp, unsigned int base);
> +unsigned long long ustrtoull(const char *cp, char **endptr, unsigned int base);
>   
>   const char* get_tmpdir(void);
>   const char* get_tmpdirscripts(void);
> diff --git a/parser/parse_external.c b/parser/parse_external.c
> index 6240c46..c6ab4fe 100644
> --- a/parser/parse_external.c
> +++ b/parser/parse_external.c
> @@ -69,7 +69,7 @@ static void sw_append_stream(struct img_type *img, const char *key,
>   		strlcpy(seek_str, value,
>   			sizeof(seek_str));
>   		/* convert the offset handling multiplicative suffixes */
> -		img->seek = ustrtoull(seek_str, 0);
> +		img->seek = ustrtoull(seek_str, NULL, 0);
>   		if (errno){
>   			ERROR("offset argument: ustrtoull failed");
>   		}
> diff --git a/parser/parser.c b/parser/parser.c
> index 85241f4..eebd581 100644
> --- a/parser/parser.c
> +++ b/parser/parser.c
> @@ -406,7 +406,7 @@ static int parse_common_attributes(parsertype p, void *elem, struct img_type *im
>   	get_hash_value(p, elem, image->sha256);
>   
>   	/* convert the offset handling multiplicative suffixes */
> -	image->seek = ustrtoull(seek_str, 0);
> +	image->seek = ustrtoull(seek_str, NULL, 0);
>   	if (errno){
>   		ERROR("offset argument: ustrtoull failed");
>   		return -1;
> diff --git a/suricatta/common.c b/suricatta/common.c
> index 28c5e94..c47fa5c 100644
> --- a/suricatta/common.c
> +++ b/suricatta/common.c
> @@ -25,7 +25,7 @@ void suricatta_channel_settings(void *elem, channel_data_t *chan)
>   
>   	GET_FIELD_STRING_RESET(LIBCFG_PARSER, elem, "max-download-speed", tmp);
>   	if (strlen(tmp))
> -		chan->max_download_speed = (unsigned int)ustrtoull(tmp, 10);
> +		chan->max_download_speed = (unsigned int)ustrtoull(tmp, NULL, 10);
>   
>   	GET_FIELD_STRING_RESET(LIBCFG_PARSER, elem, "retrywait", tmp);
>   	if (strlen(tmp))
> diff --git a/suricatta/server_general.c b/suricatta/server_general.c
> index e674441..47f9078 100644
> --- a/suricatta/server_general.c
> +++ b/suricatta/server_general.c
> @@ -669,7 +669,7 @@ server_op_res_t server_start(char *fname, int argc, char *argv[])
>   			break;
>   		case 'n':
>   			channel_data_defaults.max_download_speed =
> -				(unsigned int)ustrtoull(optarg, 10);
> +				(unsigned int)ustrtoull(optarg, NULL, 10);
>   			break;
>   
>   		case '?':
> diff --git a/suricatta/server_hawkbit.c b/suricatta/server_hawkbit.c
> index 68ce32e..5a456e1 100644
> --- a/suricatta/server_hawkbit.c
> +++ b/suricatta/server_hawkbit.c
> @@ -1848,7 +1848,7 @@ server_op_res_t server_start(char *fname, int argc, char *argv[])
>   			break;
>   		case 'n':
>   			channel_data_defaults.max_download_speed =
> -				(unsigned int)ustrtoull(optarg, 10);
> +				(unsigned int)ustrtoull(optarg, NULL, 10);
>   			break;
>   		/* Ignore not recognized options, they can be already parsed by the caller */
>   		case '?':

Best regards,
Stefano
Kyle Russell March 9, 2022, 3:13 p.m. UTC | #2
Hi Stefano,

On Wed, Mar 9, 2022 at 4:22 AM Stefano Babic <sbabic@denx.de> wrote:

> The new post lets me to think again and (apart that your patch is ok)
> check about the semantic of ustrtoull(). I fully agree to change it,
> because it becomes the same syntax as strtoull() - it was written in
> this way first, see commit 94f9a86f. The thing is what is returning:
> strtoull() returns the first "invalid" character, and this is the topic.
> Is the size delimiter in ustrtoull() an invalid character ? Really not,
> because it is decoded. So if we will use the function in other context,
> like :
>
>         size = ustrtoull("1024G, some fancy things", &endptr, 10);
>
> we would like to get in endptr what was not decoded, that is after the "G".
>

I agree since the size delimiter is considered part of the conversion that
endptr should be advanced after.

This does not work with your rule to check for a '\0', but what you want
> to check if there is a size delimiter. You could do in another way, for
> example checking then endptr from ustrtoull() and strtoul(). Instead of:
>
> part->size = ustrtoull(equal, &suffix, 10);
>
> You could call also strtoull(equal, &suffix1, 10), and for your test
> case, suffix == suffix1.
>

I will work on adding a test case for this and send another patch tomorrow.

> @@ -769,13 +778,12 @@ unsigned long long ustrtoull(const char *cp,
> unsigned int base)
> >       case 'K':
> >       case 'k':
> >               result *= 1024;
> > -             if (endp[1] == 'i') {
> > -                     if (endp[2] == 'B')
> > -                             endp += 3;
> > -                     else
> > -                             endp += 2;
> > -             }
>
> This is not wrong and should not be dropped. It is allowed to have GiB,
> or KiB, or MiB, and the delimiter is then dropped from result, that is
> endp must be increased.
>

Originally the block I dropped was not doing anything since endptr was not
returned at all, so I removed it, but I will add it back to facilitate this.
diff mbox series

Patch

diff --git a/core/util.c b/core/util.c
index 4c8c034..7525521 100644
--- a/core/util.c
+++ b/core/util.c
@@ -743,7 +743,15 @@  void free_string_array(char **nodes)
 	free(nodes);
 }
 
-unsigned long long ustrtoull(const char *cp, unsigned int base)
+/*
+ * Like strtoull(), but automatically scales the conversion
+ * result by size-type units, and only returns a pointer to
+ * the size unit in the string if requested by the caller.
+ *
+ * Sets errno to ERANGE if strtoull() found no digits or
+ * encountered an overflow, and returns 0 in both cases.
+ */
+unsigned long long ustrtoull(const char *cp, char **endptr, unsigned int base)
 {
 	errno = 0;
 	char *endp = NULL;
@@ -756,7 +764,8 @@  unsigned long long ustrtoull(const char *cp, unsigned int base)
 
 	if (cp == endp || (result == ULLONG_MAX && errno == ERANGE)) {
 		errno = ERANGE;
-		return 0;
+		result = 0;
+		goto out;
 	}
 
 	switch (*endp) {
@@ -769,13 +778,12 @@  unsigned long long ustrtoull(const char *cp, unsigned int base)
 	case 'K':
 	case 'k':
 		result *= 1024;
-		if (endp[1] == 'i') {
-			if (endp[2] == 'B')
-				endp += 3;
-			else
-				endp += 2;
-		}
 	}
+
+out:
+	if (endptr)
+		*endptr = endp;
+
 	return result;
 }
 
@@ -1196,7 +1204,7 @@  long long get_output_size(struct img_type *img, bool strict)
 			return -ENOENT;
 		}
 
-		bytes = ustrtoull(output_size_str, 0);
+		bytes = ustrtoull(output_size_str, NULL, 0);
 		if (errno || bytes <= 0) {
 			ERROR("decompressed-size argument %s: ustrtoull failed",
 			      output_size_str);
@@ -1214,7 +1222,7 @@  long long get_output_size(struct img_type *img, bool strict)
 			return -ENOENT;
 		}
 
-		bytes = ustrtoull(output_size_str, 0);
+		bytes = ustrtoull(output_size_str, NULL, 0);
 		if (errno || bytes <= 0) {
 			ERROR("decrypted-size argument %s: ustrtoull failed",
 			      output_size_str);
diff --git a/corelib/lua_interface.c b/corelib/lua_interface.c
index c15592f..52b6605 100644
--- a/corelib/lua_interface.c
+++ b/corelib/lua_interface.c
@@ -319,7 +319,7 @@  static void lua_string_to_img(struct img_type *img, const char *key,
 		strncpy(seek_str, value,
 			sizeof(seek_str));
 		/* convert the offset handling multiplicative suffixes */
-		img->seek = ustrtoull(seek_str, 0);
+		img->seek = ustrtoull(seek_str, NULL, 0);
 		if (errno){
 			ERROR("offset argument: ustrtoull failed");
 		}
diff --git a/handlers/delta_handler.c b/handlers/delta_handler.c
index 3132f2e..f8d330c 100644
--- a/handlers/delta_handler.c
+++ b/handlers/delta_handler.c
@@ -329,7 +329,7 @@  static int delta_retrieve_attributes(struct img_type *img, struct hnd_priv *priv
 		if (!strcmp(srcsize, "detect"))
 			priv->detectsrcsize = true;
 		else
-			priv->srcsize = ustrtoull(srcsize, 10);
+			priv->srcsize = ustrtoull(srcsize, NULL, 10);
 	}
 
 	char *zckloglevel = dict_get_value(&img->properties, "zckloglevel");
diff --git a/handlers/diskpart_handler.c b/handlers/diskpart_handler.c
index fc9b169..d584bda 100644
--- a/handlers/diskpart_handler.c
+++ b/handlers/diskpart_handler.c
@@ -74,6 +74,7 @@  struct partition_data {
 	char fstype[SWUPDATE_GENERAL_STRING_SIZE];
 	char dostype[SWUPDATE_GENERAL_STRING_SIZE];
 	char partuuid[UUID_STR_LEN];
+	int explicit_size;
 	LIST_ENTRY(partition_data) next;
 };
 LIST_HEAD(listparts, partition_data);
@@ -305,10 +306,13 @@  static int diskpart_set_partition(struct fdisk_partition *pa,
 		ret |= -EINVAL;
 	if (strlen(part->name))
 	      ret |= fdisk_partition_set_name(pa, part->name);
-	if (part->size != LIBFDISK_INIT_UNDEF(part->size))
+	if (part->size != LIBFDISK_INIT_UNDEF(part->size)) {
 	      ret |= fdisk_partition_set_size(pa, part->size / sector_size);
-	else
+	      if (part->explicit_size)
+			ret |= fdisk_partition_size_explicit(pa, part->explicit_size);
+	} else {
 		ret |= fdisk_partition_end_follow_default(pa, 1);
+	}
 
 	if (parttype)
 		ret |= fdisk_partition_set_type(pa, parttype);
@@ -543,7 +547,7 @@  static int diskpart_fill_table(struct fdisk_context *cxt, struct diskpart_table
 				parttype = fdisk_label_get_parttype_from_string(lb, GPT_DEFAULT_ENTRY_TYPE);
 			}
 		} else {
-			parttype = fdisk_label_get_parttype_from_code(lb, ustrtoull(part->type, 16));
+			parttype = fdisk_label_get_parttype_from_code(lb, ustrtoull(part->type, NULL, 16));
 		}
 		ret = diskpart_set_partition(newpa, part, sector_size, parttype, oldtb->parent);
 		if (ret) {
@@ -578,7 +582,7 @@  static int diskpart_fill_table(struct fdisk_context *cxt, struct diskpart_table
 
 				newpa = fdisk_new_partition();
 
-				parttype = fdisk_label_get_parttype_from_code(lb, ustrtoull(part->dostype, 16));
+				parttype = fdisk_label_get_parttype_from_code(lb, ustrtoull(part->dostype, NULL, 16));
 				if (!parttype) {
 					ERROR("I cannot add hybrid partition %zu(%s) invalid dostype: %s",
 						part->partno, part->name, part->dostype);
@@ -846,6 +850,7 @@  static int diskpart(struct img_type *img,
 		part->partno = strtoul(entry->key  + strlen("partition-"), NULL, 10);
 		while (elem) {
 			char *equal = index(elem->value, '=');
+			char *suffix = NULL;
 			if (equal) {
 				for (i = 0; i < ARRAY_SIZE(fields); i++) {
 					if (!((equal - elem->value) == strlen(fields[i]) &&
@@ -854,10 +859,12 @@  static int diskpart(struct img_type *img,
 					equal++;
 					switch (i) {
 					case PART_SIZE:
-						part->size = ustrtoull(equal, 10);
+						part->size = ustrtoull(equal, &suffix, 10);
+						if (*suffix == '\0')
+							part->explicit_size = 1;
 						break;
 					case PART_START:
-						part->start = ustrtoull(equal, 10);
+						part->start = ustrtoull(equal, NULL, 10);
 						break;
 					case PART_TYPE:
 						strncpy(part->type, equal, sizeof(part->type));
diff --git a/include/util.h b/include/util.h
index 950046d..3d52a93 100644
--- a/include/util.h
+++ b/include/util.h
@@ -228,7 +228,7 @@  void set_version_range(const char *minversion,
 			const char *maxversion,
 			const char *current);
 
-unsigned long long ustrtoull(const char *cp, unsigned int base);
+unsigned long long ustrtoull(const char *cp, char **endptr, unsigned int base);
 
 const char* get_tmpdir(void);
 const char* get_tmpdirscripts(void);
diff --git a/parser/parse_external.c b/parser/parse_external.c
index 6240c46..c6ab4fe 100644
--- a/parser/parse_external.c
+++ b/parser/parse_external.c
@@ -69,7 +69,7 @@  static void sw_append_stream(struct img_type *img, const char *key,
 		strlcpy(seek_str, value,
 			sizeof(seek_str));
 		/* convert the offset handling multiplicative suffixes */
-		img->seek = ustrtoull(seek_str, 0);
+		img->seek = ustrtoull(seek_str, NULL, 0);
 		if (errno){
 			ERROR("offset argument: ustrtoull failed");
 		}
diff --git a/parser/parser.c b/parser/parser.c
index 85241f4..eebd581 100644
--- a/parser/parser.c
+++ b/parser/parser.c
@@ -406,7 +406,7 @@  static int parse_common_attributes(parsertype p, void *elem, struct img_type *im
 	get_hash_value(p, elem, image->sha256);
 
 	/* convert the offset handling multiplicative suffixes */
-	image->seek = ustrtoull(seek_str, 0);
+	image->seek = ustrtoull(seek_str, NULL, 0);
 	if (errno){
 		ERROR("offset argument: ustrtoull failed");
 		return -1;
diff --git a/suricatta/common.c b/suricatta/common.c
index 28c5e94..c47fa5c 100644
--- a/suricatta/common.c
+++ b/suricatta/common.c
@@ -25,7 +25,7 @@  void suricatta_channel_settings(void *elem, channel_data_t *chan)
 
 	GET_FIELD_STRING_RESET(LIBCFG_PARSER, elem, "max-download-speed", tmp);
 	if (strlen(tmp))
-		chan->max_download_speed = (unsigned int)ustrtoull(tmp, 10);
+		chan->max_download_speed = (unsigned int)ustrtoull(tmp, NULL, 10);
 
 	GET_FIELD_STRING_RESET(LIBCFG_PARSER, elem, "retrywait", tmp);
 	if (strlen(tmp))
diff --git a/suricatta/server_general.c b/suricatta/server_general.c
index e674441..47f9078 100644
--- a/suricatta/server_general.c
+++ b/suricatta/server_general.c
@@ -669,7 +669,7 @@  server_op_res_t server_start(char *fname, int argc, char *argv[])
 			break;
 		case 'n':
 			channel_data_defaults.max_download_speed =
-				(unsigned int)ustrtoull(optarg, 10);
+				(unsigned int)ustrtoull(optarg, NULL, 10);
 			break;
 
 		case '?':
diff --git a/suricatta/server_hawkbit.c b/suricatta/server_hawkbit.c
index 68ce32e..5a456e1 100644
--- a/suricatta/server_hawkbit.c
+++ b/suricatta/server_hawkbit.c
@@ -1848,7 +1848,7 @@  server_op_res_t server_start(char *fname, int argc, char *argv[])
 			break;
 		case 'n':
 			channel_data_defaults.max_download_speed =
-				(unsigned int)ustrtoull(optarg, 10);
+				(unsigned int)ustrtoull(optarg, NULL, 10);
 			break;
 		/* Ignore not recognized options, they can be already parsed by the caller */
 		case '?':