diff --git a/commands/mmc_extcsd.c b/commands/mmc_extcsd.c index 7a6d390..acd23a4 100644 --- a/commands/mmc_extcsd.c +++ b/commands/mmc_extcsd.c @@ -2357,7 +2357,7 @@ break; } - mci_switch(mci, 0, index, value); + mci_switch(mci, index, value); out: return; diff --git a/commands/usbgadget.c b/commands/usbgadget.c index 507871e..a1744cb 100644 --- a/commands/usbgadget.c +++ b/commands/usbgadget.c @@ -119,13 +119,13 @@ BAREBOX_CMD_HELP_TEXT("Enable / disable a USB composite gadget on the USB device interface.") BAREBOX_CMD_HELP_TEXT("") BAREBOX_CMD_HELP_TEXT("Options:") -BAREBOX_CMD_HELP_OPT ("-a", "Create CDC ACM function") -BAREBOX_CMD_HELP_OPT ("-s", "Create Generic Serial function") -BAREBOX_CMD_HELP_OPT ("-A [desc]", "Create Android Fastboot function. If 'desc' is not provided,") -BAREBOX_CMD_HELP_OPT ("", "trying to use 'global.usbgadget.fastboot_function' variable.") -BAREBOX_CMD_HELP_OPT ("-b", "include registered barebox update handlers (fastboot specific)") -BAREBOX_CMD_HELP_OPT ("-D ", "Create DFU function") -BAREBOX_CMD_HELP_OPT ("-d", "Disable the currently running gadget") +BAREBOX_CMD_HELP_OPT ("-a\t", "Create CDC ACM function") +BAREBOX_CMD_HELP_OPT ("-s\t", "Create Generic Serial function") +BAREBOX_CMD_HELP_OPT ("-A ", "Create Android Fastboot function. If 'desc' is not provided, " + "try to use 'global.usbgadget.fastboot_function' variable.") +BAREBOX_CMD_HELP_OPT ("-b\t", "include registered barebox update handlers (fastboot specific)") +BAREBOX_CMD_HELP_OPT ("-D ", "Create DFU function") +BAREBOX_CMD_HELP_OPT ("-d\t", "Disable the currently running gadget") BAREBOX_CMD_HELP_END BAREBOX_CMD_START(usbgadget) diff --git a/common/bootm.c b/common/bootm.c index c23898b..05314a0 100644 --- a/common/bootm.c +++ b/common/bootm.c @@ -568,7 +568,7 @@ if (IS_ENABLED(CONFIG_FITIMAGE) && os_type == filetype_oftree) { struct fit_handle *fit; - fit = fit_open(data->os_file, data->os_part, data->verbose, data->verify); + fit = fit_open(data->os_file, data->verbose, data->verify); if (IS_ERR(fit)) { printf("Loading FIT image %s failed with: %s\n", data->os_file, strerrorp(fit)); @@ -577,6 +577,13 @@ } data->os_fit = fit; + + ret = fit_open_configuration(data->os_fit, data->os_part); + if (ret) { + printf("Cannot open FIT image configuration '%s'\n", + data->os_part ? data->os_part : "default"); + goto err_out; + } } if (os_type == filetype_uimage) { diff --git a/common/env.c b/common/env.c index df8a4df..80d3f7a 100644 --- a/common/env.c +++ b/common/env.c @@ -223,34 +223,50 @@ return 0; } +static int dev_setenv(const char *name, const char *val) +{ + const char *pos, *dot, *varname; + char *devname; + struct device_d *dev; + + pos = name; + + while (1) { + dot = strchr(pos, '.'); + if (!dot) + break; + + devname = xstrndup(name, dot - name); + varname = dot + 1; + + dev = get_device_by_name(devname); + + free(devname); + + if (dev) { + if (get_param_by_name(dev, varname)) + return dev_set_param(dev, varname, val); + } + + pos = dot + 1; + } + + return -ENODEV; +} + int setenv(const char *_name, const char *value) { char *name = strdup(_name); - char *par; int ret = 0; struct list_head *list; if (value && !*value) value = NULL; - - if ((par = strchr(name, '.'))) { - struct device_d *dev; - - *par++ = 0; - dev = get_device_by_name(name); - if (dev) { - ret = dev_set_param(dev, par, value); - if (ret) - eprintf("%s: set parameter %s: %s\n", - dev_name(dev), par, strerror(-ret)); - } else { - ret = -ENODEV; - eprintf("set parameter: no such device %s\n", name); - } - - errno = -ret; - + if (strchr(name, '.')) { + ret = dev_setenv(name, value); + if (ret) + eprintf("Cannot set parameter: %s\n", strerror(-ret)); goto out; } diff --git a/common/image-fit.c b/common/image-fit.c index db5d142..12379a6 100644 --- a/common/image-fit.c +++ b/common/image-fit.c @@ -397,14 +397,37 @@ return ret; } -static int fit_open_image(struct fit_handle *handle, const char *unit, const void **outdata, - unsigned long *outsize) +int fit_has_image(struct fit_handle *handle, const char *name) +{ + const char *unit; + struct device_node *conf_node = handle->conf_node; + + if (!conf_node) + return -EINVAL; + + if (of_property_read_string(conf_node, name, &unit)) + return 0; + + return 1; +} + +int fit_open_image(struct fit_handle *handle, const char *name, + const void **outdata, unsigned long *outsize) { struct device_node *image = NULL, *hash; - const char *type = NULL, *desc= "(no description)"; + const char *unit, *type = NULL, *desc= "(no description)"; const void *data; int data_len; int ret = 0; + struct device_node *conf_node = handle->conf_node; + + if (!conf_node) + return -EINVAL; + + if (of_property_read_string(conf_node, name, &unit)) { + pr_err("No image named '%s'\n", name); + return -ENOENT; + } image = of_get_child_by_name(handle->root, "images"); if (!image) @@ -523,7 +546,7 @@ return -ENOENT; } -static int fit_open_configuration(struct fit_handle *handle, const char *name) +int fit_open_configuration(struct fit_handle *handle, const char *name) { struct device_node *conf_node = NULL; const char *unit, *desc = "(no description)"; @@ -556,22 +579,25 @@ if (ret) return ret; - if (of_property_read_string(conf_node, "kernel", &unit) == 0) { - ret = fit_open_image(handle, unit, &handle->kernel, &handle->kernel_size); - if (ret) - return ret; - } else { - return -ENOENT; - } + handle->conf_node = conf_node; - if (of_property_read_string(conf_node, "fdt", &unit) == 0) { - ret = fit_open_image(handle, unit, &handle->oftree, &handle->oftree_size); + if (fit_has_image(handle, "kernel")) { + ret = fit_open_image(handle, "kernel", &handle->kernel, + &handle->kernel_size); if (ret) return ret; } - if (of_property_read_string(conf_node, "ramdisk", &unit) == 0) { - ret = fit_open_image(handle, unit, &handle->initrd, &handle->initrd_size); + if (fit_has_image(handle, "ramdisk")) { + ret = fit_open_image(handle, "ramdisk", &handle->initrd, + &handle->initrd_size); + if (ret) + return ret; + } + + if (fit_has_image(handle, "fdt")) { + ret = fit_open_image(handle, "fdt", &handle->oftree, + &handle->oftree_size); if (ret) return ret; } @@ -579,7 +605,7 @@ return 0; } -struct fit_handle *fit_open(const char *filename, const char *config, bool verbose, +struct fit_handle *fit_open(const char *filename, bool verbose, enum bootm_verify verify) { struct fit_handle *handle = NULL; @@ -609,10 +635,6 @@ of_property_read_string(handle->root, "description", &desc); pr_info("'%s': %s\n", filename, desc); - ret = fit_open_configuration(handle, config); - if (ret) - goto err; - return handle; err: if (handle->root) @@ -636,10 +658,23 @@ static int do_bootm_sandbox_fit(struct image_data *data) { struct fit_handle *handle; - handle = fit_open(data->os_file, data->os_part, data->verbose); - if (handle) - fit_close(handle); - return 0; + int ret; + void *kernel; + unsigned long kernel_size; + + handle = fit_open(data->os_file, data->verbose); + if (IS_ERR(handle)) + return PTR_ERR(handle); + + ret = fit_open_configuration(handle, data->os_part); + if (ret) + goto out; + + ret = 0; +out: + fit_close(handle); + + return ret; } static struct image_handler sandbox_fit_handler = { diff --git a/common/misc.c b/common/misc.c index c5d3704..0888f1f 100644 --- a/common/misc.c +++ b/common/misc.c @@ -187,6 +187,13 @@ } EXPORT_SYMBOL(barebox_get_hostname); +void barebox_set_hostname_no_overwrite(const char *__hostname) +{ + if (!barebox_get_hostname()) + barebox_set_hostname(__hostname); +} +EXPORT_SYMBOL(barebox_set_hostname_no_overwrite); + BAREBOX_MAGICVAR_NAMED(global_hostname, global.hostname, "shortname of the board. Also used as hostname for DHCP requests"); diff --git a/common/partitions/dos.c b/common/partitions/dos.c index 91b5399..488c293 100644 --- a/common/partitions/dos.c +++ b/common/partitions/dos.c @@ -21,6 +21,22 @@ #include "parser.h" + +enum { +/* These three have identical behaviour; use the second one if DOS FDISK gets + confused about extended/logical partitions starting past cylinder 1023. */ + DOS_EXTENDED_PARTITION = 5, + LINUX_EXTENDED_PARTITION = 0x85, + WIN98_EXTENDED_PARTITION = 0x0f, +}; + +static inline int is_extended_partition(struct partition *p) +{ + return (p->dos_partition_type == DOS_EXTENDED_PARTITION || + p->dos_partition_type == WIN98_EXTENDED_PARTITION || + p->dos_partition_type == LINUX_EXTENDED_PARTITION); +} + /** * Guess the size of the disk, based on the partition table entries * @param dev device to create partitions for @@ -212,13 +228,8 @@ sprintf(pd->parts[n].partuuid, "%08x-%02d", signature, i + 1); pd->used_entries++; - /* - * Partitions of type 0x05 and 0x0f (and some more) - * contain extended partitions. Only check for type 0x0f - * here as this is the easiest to parse and common - * enough. - */ - if (pentry.dos_partition_type == 0x0f) { + + if (is_extended_partition(&pentry)) { if (!extended_partition) extended_partition = &pd->parts[n]; else diff --git a/common/ubiformat.c b/common/ubiformat.c index 4c5f1f5..f728119 100644 --- a/common/ubiformat.c +++ b/common/ubiformat.c @@ -190,6 +190,7 @@ int fd, img_ebs, eb, written_ebs = 0, ret = -1, eb_cnt; off_t st_size; char *buf = NULL; + uint64_t lastprint = 0; eb_cnt = mtd_num_pebs(mtd); @@ -229,8 +230,12 @@ long long ec; if (!args->quiet && !args->verbose) { - printf("\rubiformat: flashing eraseblock %d -- %2u %% complete ", - eb, (eb + 1) * 100 / eb_cnt); + if (is_timeout(lastprint, 300 * MSECOND) || + eb == eb_cnt - 1) { + printf("\rubiformat: flashing eraseblock %d -- %2u %% complete ", + eb, (eb + 1) * 100 / eb_cnt); + lastprint = get_time_ns(); + } } if (si->ec[eb] == EB_BAD) @@ -325,6 +330,7 @@ struct ubi_vtbl_record *vtbl; int eb1 = -1, eb2 = -1; long long ec1 = -1, ec2 = -1; + uint64_t lastprint = 0; eb_cnt = mtd_num_pebs(mtd); @@ -340,8 +346,12 @@ long long ec; if (!args->quiet && !args->verbose) { - printf("\rubiformat: formatting eraseblock %d -- %2u %% complete ", - eb, (eb + 1 - start_eb) * 100 / (eb_cnt - start_eb)); + if (is_timeout(lastprint, 300 * MSECOND) || + eb == eb_cnt - 1) { + printf("\rubiformat: formatting eraseblock %d -- %2u %% complete ", + eb, (eb + 1 - start_eb) * 100 / (eb_cnt - start_eb)); + lastprint = get_time_ns(); + } } if (si->ec[eb] == EB_BAD) diff --git a/drivers/efi/Kconfig b/drivers/efi/Kconfig index d6beeb0..cca1a2e 100644 --- a/drivers/efi/Kconfig +++ b/drivers/efi/Kconfig @@ -1,5 +1,4 @@ config EFI_BOOTUP bool - select HAS_POWEROFF select BLOCK select PARTITION_DISK diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c index 208b766..c6b4e02 100644 --- a/drivers/mci/mci-core.c +++ b/drivers/mci/mci-core.c @@ -396,8 +396,7 @@ * @param value FIXME * @return Transaction status (0 on success) */ -int mci_switch(struct mci *mci, unsigned set, unsigned index, - unsigned value) +int mci_switch(struct mci *mci, unsigned index, unsigned value) { struct mci_cmd cmd; @@ -471,7 +470,7 @@ cardtype = mci->ext_csd[EXT_CSD_DEVICE_TYPE] & EXT_CSD_CARD_TYPE_MASK; - err = mci_switch(mci, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1); + err = mci_switch(mci, EXT_CSD_HS_TIMING, 1); if (err) { dev_dbg(&mci->dev, "MMC frequency changing failed: %d\n", err); @@ -1044,9 +1043,7 @@ * 4bit transfer mode. On success set the corresponding * bus width on the host. */ - err = mci_switch(mci, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_BUS_WIDTH, - ext_csd_bits[idx]); + err = mci_switch(mci, EXT_CSD_BUS_WIDTH, ext_csd_bits[idx]); if (err) { if (idx == 0) dev_warn(&mci->dev, "Changing MMC bus width failed: %d\n", err); @@ -1253,8 +1250,7 @@ part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK; part_config |= part->part_cfg; - ret = mci_switch(mci, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_PARTITION_CONFIG, part_config); + ret = mci_switch(mci, EXT_CSD_PARTITION_CONFIG, part_config); if (ret) return ret; @@ -1568,8 +1564,8 @@ mci->ext_csd_part_config &= ~(7 << 3); mci->ext_csd_part_config |= mci->bootpart << 3; - return mci_switch(mci, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_PARTITION_CONFIG, mci->ext_csd_part_config); + return mci_switch(mci, + EXT_CSD_PARTITION_CONFIG, mci->ext_csd_part_config); } static const char *mci_boot_names[] = { diff --git a/drivers/of/base.c b/drivers/of/base.c index eabbf3d..6a58217 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -2360,3 +2360,35 @@ return available; } EXPORT_SYMBOL(of_graph_port_is_available); + +/** + * of_get_machine_compatible - get first compatible string from the root node. + * + * Returns the string or NULL. + */ +const char *of_get_machine_compatible(void) +{ + struct property *prop; + const char *name, *p; + + if (!root_node) + return NULL; + + prop = of_find_property(root_node, "compatible", NULL); + name = of_prop_next_string(prop, NULL); + + p = strchr(name, ','); + return p ? p + 1 : name; +} +EXPORT_SYMBOL(of_get_machine_compatible); + +static int of_init_hostname(void) +{ + const char *name; + + name = of_get_machine_compatible(); + barebox_set_hostname_no_overwrite(name ?: "barebox"); + + return 0; +} +late_initcall(of_init_hostname); diff --git a/fs/Makefile b/fs/Makefile index b3f929f..8e3fd78 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -4,7 +4,7 @@ obj-y += devfs-core.o obj-$(CONFIG_FS_DEVFS) += devfs.o obj-$(CONFIG_FS_FAT) += fat/ -obj-y += fs.o parseopt.o +obj-y += fs.o obj-$(CONFIG_FS_UBIFS) += ubifs/ obj-$(CONFIG_FS_TFTP) += tftp.o obj-$(CONFIG_FS_OMAP4_USBBOOT) += omap4_usbbootfs.o diff --git a/fs/fs.c b/fs/fs.c index 051af8d..6f15e93 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -35,8 +35,7 @@ #include #include #include - -#include "parseopt.h" +#include char *mkmodestr(unsigned long mode, char *str) { diff --git a/fs/nfs.c b/fs/nfs.c index 97f01cf..75cd127 100644 --- a/fs/nfs.c +++ b/fs/nfs.c @@ -36,8 +36,7 @@ #include #include #include - -#include "parseopt.h" +#include #define SUNRPC_PORT 111 diff --git a/fs/parseopt.c b/fs/parseopt.c deleted file mode 100644 index 8ff8301..0000000 --- a/fs/parseopt.c +++ /dev/null @@ -1,60 +0,0 @@ -#include - -#include "parseopt.h" - -void parseopt_b(const char *options, const char *opt, bool *val) -{ - const char *start; - size_t optlen = strlen(opt); - -again: - start = strstr(options, opt); - - if (!start) { - *val = false; - return; - } - - if (start > options && start[-1] != ',') { - options = start; - goto again; - } - - if (start[optlen] != ',' && start[optlen] != '\0') { - options = start; - goto again; - } - - *val = true; -} - -void parseopt_hu(const char *options, const char *opt, unsigned short *val) -{ - const char *start; - size_t optlen = strlen(opt); - ulong v; - char *endp; - -again: - start = strstr(options, opt); - - if (!start) - return; - - if (start > options && start[-1] != ',') { - options = start; - goto again; - } - - if (start[optlen] != '=') { - options = start; - goto again; - } - - v = simple_strtoul(start + optlen + 1, &endp, 0); - if (v > USHRT_MAX) - return; - - if (*endp == ',' || *endp == '\0') - *val = v; -} diff --git a/fs/parseopt.h b/fs/parseopt.h deleted file mode 100644 index abf3be3..0000000 --- a/fs/parseopt.h +++ /dev/null @@ -1,2 +0,0 @@ -void parseopt_b(const char *options, const char *opt, bool *val); -void parseopt_hu(const char *options, const char *opt, unsigned short *val); diff --git a/include/common.h b/include/common.h index dd7445e..60e5005 100644 --- a/include/common.h +++ b/include/common.h @@ -93,8 +93,6 @@ void __noreturn start_barebox(void); void shutdown_barebox(void); -#define ALIGN_DOWN(x, a) ((x) & ~((typeof(x))(a) - 1)) - #define ARRAY_AND_SIZE(x) (x), ARRAY_SIZE(x) /* @@ -139,6 +137,7 @@ void barebox_set_model(const char *); const char *barebox_get_hostname(void); void barebox_set_hostname(const char *); +void barebox_set_hostname_no_overwrite(const char *); #if defined(CONFIG_MIPS) #include diff --git a/include/image-fit.h b/include/image-fit.h index c49f958..62f44dc 100644 --- a/include/image-fit.h +++ b/include/image-fit.h @@ -29,6 +29,7 @@ enum bootm_verify verify; struct device_node *root; + struct device_node *conf_node; const void *kernel; unsigned long kernel_size; @@ -38,8 +39,13 @@ unsigned long initrd_size; }; -struct fit_handle *fit_open(const char *filename, const char *config, bool verbose, +struct fit_handle *fit_open(const char *filename, bool verbose, enum bootm_verify verify); +int fit_open_configuration(struct fit_handle *handle, const char *name); +int fit_has_image(struct fit_handle *handle, const char *name); +int fit_open_image(struct fit_handle *handle, const char *name, + const void **outdata, unsigned long *outsize); + void fit_close(struct fit_handle *handle); #endif /* __IMAGE_FIT_H__ */ diff --git a/include/linux/kernel.h b/include/linux/kernel.h index b4d2f09..ab713f2 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -33,6 +33,7 @@ #define S64_MIN ((s64)(-S64_MAX - 1)) #define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a) - 1) +#define ALIGN_DOWN(x, a) ALIGN((x) - ((a) - 1), (a)) #define __ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask)) #define PTR_ALIGN(p, a) ((typeof(p))ALIGN((unsigned long)(p), (a))) #define IS_ALIGNED(x, a) (((x) & ((typeof(x))(a) - 1)) == 0) diff --git a/include/linux/string.h b/include/linux/string.h index 5df8c50..ed4eeb5 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -80,6 +80,9 @@ #ifndef __HAVE_ARCH_STRDUP extern char * strdup(const char *); #endif +#ifndef __HAVE_ARCH_STRNDUP +extern char *strndup(const char *, size_t); +#endif #ifndef __HAVE_ARCH_STRSWAB extern char * strswab(const char *); #endif diff --git a/include/mci.h b/include/mci.h index 1f65333..072008e 100644 --- a/include/mci.h +++ b/include/mci.h @@ -478,8 +478,7 @@ void mci_of_parse_node(struct mci_host *host, struct device_node *np); int mci_detect_card(struct mci_host *); int mci_send_ext_csd(struct mci *mci, char *ext_csd); -int mci_switch(struct mci *mci, unsigned set, unsigned index, - unsigned value); +int mci_switch(struct mci *mci, unsigned index, unsigned value); static inline int mmc_host_is_spi(struct mci_host *host) { diff --git a/include/of.h b/include/of.h index 9bdbbb5e..1b9719d 100644 --- a/include/of.h +++ b/include/of.h @@ -148,6 +148,7 @@ const struct device_node *other); extern void of_delete_node(struct device_node *node); +extern const char *of_get_machine_compatible(void); extern int of_machine_is_compatible(const char *compat); extern int of_device_is_compatible(const struct device_node *device, const char *compat); diff --git a/include/parseopt.h b/include/parseopt.h new file mode 100644 index 0000000..1f9763f --- /dev/null +++ b/include/parseopt.h @@ -0,0 +1,9 @@ +#ifndef __PARSEOPT_H__ +#define __PARSEOPT_H__ + +void parseopt_b(const char *options, const char *opt, bool *val); +void parseopt_hu(const char *options, const char *opt, unsigned short *val); +void parseopt_u16(const char *options, const char *opt, uint16_t *val); +void parseopt_str(const char *options, const char *opt, char **val); + +#endif /* __PARSEOPT_H__ */ diff --git a/lib/Makefile b/lib/Makefile index 0d5ac65..66c59fe 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -60,3 +60,4 @@ obj-$(CONFIG_RATP) += ratp.o obj-y += list_sort.o obj-y += int_sqrt.o +obj-y += parseopt.o diff --git a/lib/libscan.c b/lib/libscan.c index 74a24b5..c4139e6 100644 --- a/lib/libscan.c +++ b/lib/libscan.c @@ -39,6 +39,7 @@ int eb, v = (verbose == 2), pr = (verbose == 1), eb_cnt; struct ubi_scan_info *si; unsigned long long sum = 0; + uint64_t lastprint = 0; eb_cnt = mtd_div_by_eb(mtd->size, mtd); @@ -66,8 +67,12 @@ if (v) normsg_cont("scanning eraseblock %d", eb); if (pr) { - printf("\r" PROGRAM_NAME ": scanning eraseblock %d -- %2u %% complete ", - eb, (eb + 1) * 100 / eb_cnt); + if (is_timeout(lastprint, 300 * MSECOND) || + eb == eb_cnt - 1) { + printf("\r" PROGRAM_NAME ": scanning eraseblock %d -- %2u %% complete ", + eb, (eb + 1) * 100 / eb_cnt); + lastprint = get_time_ns(); + } } ret = mtd_peb_is_bad(mtd, eb); diff --git a/lib/misc.c b/lib/misc.c index 62ddd66..1d20e1b 100644 --- a/lib/misc.c +++ b/lib/misc.c @@ -79,38 +79,53 @@ int parse_area_spec(const char *str, loff_t *start, loff_t *size) { char *endp; - loff_t end; + loff_t end, _start, _size; if (!isdigit(*str)) return -1; - *start = strtoull_suffix(str, &endp, 0); + _start = strtoull_suffix(str, &endp, 0); str = endp; if (!*str) { /* beginning given, but no size, assume maximum size */ - *size = ~0; - return 0; + _size = ~0; + goto success; } if (*str == '-') { /* beginning and end given */ - end = strtoull_suffix(str + 1, NULL, 0); - if (end < *start) { + if (!isdigit(*(str + 1))) + return -1; + + end = strtoull_suffix(str + 1, &endp, 0); + str = endp; + if (end < _start) { printf("end < start\n"); return -1; } - *size = end - *start + 1; - return 0; + _size = end - _start + 1; + goto success; } if (*str == '+') { /* beginning and size given */ - *size = strtoull_suffix(str + 1, NULL, 0); - return 0; + if (!isdigit(*(str + 1))) + return -1; + + _size = strtoull_suffix(str + 1, &endp, 0); + str = endp; + goto success; } return -1; + +success: + if (*str && !isspace(*str)) + return -1; + *start = _start; + *size = _size; + return 0; } EXPORT_SYMBOL(parse_area_spec); diff --git a/lib/parseopt.c b/lib/parseopt.c new file mode 100644 index 0000000..8211733 --- /dev/null +++ b/lib/parseopt.c @@ -0,0 +1,124 @@ +#include + +#include "parseopt.h" + +void parseopt_b(const char *options, const char *opt, bool *val) +{ + const char *start; + size_t optlen = strlen(opt); + +again: + start = strstr(options, opt); + + if (!start) { + *val = false; + return; + } + + if (start > options && start[-1] != ',') { + options = start; + goto again; + } + + if (start[optlen] != ',' && start[optlen] != '\0') { + options = start; + goto again; + } + + *val = true; +} + +void parseopt_hu(const char *options, const char *opt, unsigned short *val) +{ + const char *start; + size_t optlen = strlen(opt); + ulong v; + char *endp; + +again: + start = strstr(options, opt); + + if (!start) + return; + + if (start > options && start[-1] != ',') { + options = start; + goto again; + } + + if (start[optlen] != '=') { + options = start; + goto again; + } + + v = simple_strtoul(start + optlen + 1, &endp, 0); + if (v > USHRT_MAX) + return; + + if (*endp == ',' || *endp == '\0') + *val = v; +} + +void parseopt_u16(const char *options, const char *opt, uint16_t *val) +{ + const char *start; + size_t optlen = strlen(opt); + ulong v; + char *endp; + +again: + start = strstr(options, opt); + + if (!start) + return; + + if (start > options && start[-1] != ',') { + options = start; + goto again; + } + + if (start[optlen] != '=') { + options = start; + goto again; + } + + v = simple_strtoul(start + optlen + 1, &endp, 0); + if (v > U16_MAX) + return; + + if (*endp == ',' || *endp == '\0') + *val = v; +} + +void parseopt_str(const char *options, const char *opt, char **val) +{ + const char *start; + size_t optlen = strlen(opt); + char *endp; + char *parsed; + +again: + start = strstr(options, opt); + + if (!start) + return; + + if (start > options && start[-1] != ',') { + options = start; + goto again; + } + + if (start[optlen] != '=') { + options = start; + goto again; + } + + parsed = (char *)start + optlen + 1; + endp = parsed; + while (*endp != '\0' && *endp != ',') { + + endp++; + } + + *val = xstrndup(parsed, endp - parsed); +} diff --git a/lib/string.c b/lib/string.c index 1d491c9..f588933 100644 --- a/lib/string.c +++ b/lib/string.c @@ -323,6 +323,26 @@ #endif EXPORT_SYMBOL(strdup); +#ifndef __HAVE_ARCH_STRNDUP +char *strndup(const char *s, size_t n) +{ + char *new; + size_t len = strnlen(s, n); + + if ((s == NULL) || + ((new = malloc(len + 1)) == NULL)) { + return NULL; + } + + memcpy(new, s, len); + new[len] = '\0'; + + return new; +} + +#endif +EXPORT_SYMBOL(strndup); + #ifndef __HAVE_ARCH_STRSPN /** * strspn - Calculate the length of the initial substring of @s which only