예제 #1
0
파일: semeru.c 프로젝트: bmellstrom/semeru
static void expand_class_path(char *cp, struct strlist *dst) {
  struct strlist wildcards;
  size_t i;
  strlist_init(&wildcards, 16);
  split(cp, ':', &wildcards);
  for (i = 0; i < wildcards.size; i++) {
    expand_jars(wildcards.items[i], dst);
  }
  strlist_destroy(&wildcards);
}
예제 #2
0
int archwriter_init(carchwriter *ai)
{
    assert(ai);
    memset(ai, 0, sizeof(struct s_archwriter));
    strlist_init(&ai->vollist);
    ai->newarch=false;
    ai->archfd=-1;
    ai->archid=0;
    ai->curvol=0;
    return 0;
}
예제 #3
0
파일: semeru.c 프로젝트: bmellstrom/semeru
static char* create_class_path_option(char *cp) {
  struct strlist parts;
  char *result;
  strlist_init(&parts, 128);
  strlist_add(&parts, "-Djava.class.path=");
  expand_class_path(cp, &parts);
  if (parts.size > 1) {
    strlist_remove_last(&parts); /* last entry is a ':' */
  }
  result = strlist_concat(&parts);
  strlist_destroy(&parts);
  return result;
}
예제 #4
0
retvalue exportmode_init(/*@out@*/struct exportmode *mode, bool uncompressed, /*@null@*/const char *release, const char *indexfile) {
    strlist_init(&mode->hooks);
    mode->compressions = IC_FLAG(ic_gzip) | (uncompressed
                         ? IC_FLAG(ic_uncompressed) : 0);
    mode->filename = strdup(indexfile);
    if (FAILEDTOALLOC(mode->filename))
        return RET_ERROR_OOM;
    if (release == NULL)
        mode->release = NULL;
    else {
        mode->release = strdup(release);
        if (FAILEDTOALLOC(mode->release))
            return RET_ERROR_OOM;
    }
    return RET_OK;
}
예제 #5
0
static retvalue parse_stringpart(/*@out@*/struct strlist *strings, const char **pp, const struct filebeingparsed *fbp, int column) {
	const char *p = *pp;
	retvalue r;

	strlist_init(strings);
	do {
		const char *startp, *endp;
		char *n;

		while (*p != '\0' && xisspace(*p))
			p++;
		if (*p != '\'') {
			errorcol(fbp, column + (int)(p - *pp),
"starting \"'\" expected!");
			return RET_ERROR;
		}
		p++;
		startp = p;
		while (*p != '\0' && *p != '\'')
			p++;
		if (*p == '\0') {
			errorcol(fbp, column + (int)(p - *pp),
"closing \"'\" expected!");
			return RET_ERROR;
		}
		assert (*p == '\'');
		endp = p;
		p++;
		n = strndup(startp, endp - startp);
		if (FAILEDTOALLOC(n))
			return RET_ERROR_OOM;
		r = strlist_adduniq(strings, n);
		if (RET_WAS_ERROR(r))
			return r;
		while (*p != '\0' && xisspace(*p))
			p++;
		column += (p - *pp);
		*pp = p;
		if (**pp == '|') {
			p++;
		}
	} while (**pp == '|');
	*pp = p;
	return RET_OK;
}
예제 #6
0
retvalue chunk_getextralinelist(const char *chunk, const char *name, struct strlist *strlist) {
	retvalue r;
	const char *f, *b, *e;
	char *v;

	f = chunk_getfield(name, chunk);
	if (f == NULL)
		return RET_NOTHING;
	strlist_init(strlist);
	/* walk over the first line */
	while (*f != '\0' && *f != '\n')
		f++;
	/* nothing there is an empty list */
	if (*f == '\0')
		return RET_OK;
	f++;
	/* while lines begin with ' ' or '\t', add them */
	while (*f == ' ' || *f == '\t') {
		while (*f != '\0' && xisblank(*f))
			f++;
		b = f;
		while (*f != '\0' && *f != '\n')
			f++;
		e = f;
		while (e > b && *e != '\0' && xisspace(*e))
			e--;
		if (!xisspace(*e))
			v = strndup(b, e - b + 1);
		else
			v = strdup("");
		if (FAILEDTOALLOC(v)) {
			strlist_done(strlist);
			return RET_ERROR_OOM;
		}
		r = strlist_add(strlist, v);
		if (!RET_IS_OK(r)) {
			strlist_done(strlist);
			return r;
		}
		if (*f == '\0')
			return RET_OK;
		f++;
	}
	return RET_OK;
}
예제 #7
0
파일: tracking.c 프로젝트: Noctem/reprepro
static inline retvalue trackedpackage_removeall(trackingdb tracks, struct trackedpackage *pkg) {
	retvalue result = RET_OK, r;
	char *id;

//	printf("[trackedpackage_removeall %s %s %s]\n", tracks->codename, pkg->sourcename, pkg->sourceversion);
	id = calc_trackreferee(tracks->codename, pkg->sourcename,
			pkg->sourceversion);
	if (FAILEDTOALLOC(id))
		return RET_ERROR_OOM;

	pkg->flags.deleted = true;
	r = references_delete(id, &pkg->filekeys, NULL);
	RET_UPDATE(result, r);
	free(id);
	strlist_done(&pkg->filekeys);
	strlist_init(&pkg->filekeys);
	free(pkg->refcounts); pkg->refcounts = NULL;
	return result;
}
예제 #8
0
retvalue chunk_getuniqwordlist(const char *chunk, const char *name, struct strlist *strlist) {
	retvalue r;
	const char *f, *b;
	char *v;

	f = chunk_getfield(name, chunk);
	if (f == NULL)
		return RET_NOTHING;
	strlist_init(strlist);
	while (*f != '\0') {
		/* walk over spaces */
		while (*f != '\0' && xisspace(*f)) {
			if (*f == '\n') {
				f++;
				if (*f != ' ' && *f != '\t')
					return RET_OK;
			} else
				f++;
		}
		if (*f == '\0')
			return RET_OK;
		b = f;
		/* search for end of word */
		while (*f != '\0' && !xisspace(*f))
			f++;
		v = strndup(b, f - b);
		if (FAILEDTOALLOC(v)) {
			strlist_done(strlist);
			return RET_ERROR_OOM;
		}
		r = strlist_adduniq(strlist, v);
		if (!RET_IS_OK(r)) {
			strlist_done(strlist);
			return r;
		}
	}
	return RET_OK;
}
예제 #9
0
파일: image-host.c 프로젝트: cxg1987/u-boot
static int fit_config_get_hash_list(void *fit, int conf_noffset,
				    int sig_offset, struct strlist *node_inc)
{
	int allow_missing;
	const char *prop, *iname, *end;
	const char *conf_name, *sig_name;
	char name[200], path[200];
	int image_count;
	int ret, len;

	conf_name = fit_get_name(fit, conf_noffset, NULL);
	sig_name = fit_get_name(fit, sig_offset, NULL);

	/*
	 * Build a list of nodes we need to hash. We always need the root
	 * node and the configuration.
	 */
	strlist_init(node_inc);
	snprintf(name, sizeof(name), "%s/%s", FIT_CONFS_PATH, conf_name);
	if (strlist_add(node_inc, "/") ||
	    strlist_add(node_inc, name))
		goto err_mem;

	/* Get a list of images that we intend to sign */
	prop = fit_config_get_image_list(fit, sig_offset, &len,
					&allow_missing);
	if (!prop)
		return 0;

	/* Locate the images */
	end = prop + len;
	image_count = 0;
	for (iname = prop; iname < end; iname += strlen(iname) + 1) {
		int noffset;
		int image_noffset;
		int hash_count;

		image_noffset = fit_conf_get_prop_node(fit, conf_noffset,
						       iname);
		if (image_noffset < 0) {
			printf("Failed to find image '%s' in  configuration '%s/%s'\n",
			       iname, conf_name, sig_name);
			if (allow_missing)
				continue;

			return -ENOENT;
		}

		ret = fdt_get_path(fit, image_noffset, path, sizeof(path));
		if (ret < 0)
			goto err_path;
		if (strlist_add(node_inc, path))
			goto err_mem;

		snprintf(name, sizeof(name), "%s/%s", FIT_CONFS_PATH,
			 conf_name);

		/* Add all this image's hashes */
		hash_count = 0;
		for (noffset = fdt_first_subnode(fit, image_noffset);
		     noffset >= 0;
		     noffset = fdt_next_subnode(fit, noffset)) {
			const char *name = fit_get_name(fit, noffset, NULL);

			if (strncmp(name, FIT_HASH_NODENAME,
				    strlen(FIT_HASH_NODENAME)))
				continue;
			ret = fdt_get_path(fit, noffset, path, sizeof(path));
			if (ret < 0)
				goto err_path;
			if (strlist_add(node_inc, path))
				goto err_mem;
			hash_count++;
		}

		if (!hash_count) {
			printf("Failed to find any hash nodes in configuration '%s/%s' image '%s' - without these it is not possible to verify this image\n",
			       conf_name, sig_name, iname);
			return -ENOMSG;
		}

		image_count++;
	}

	if (!image_count) {
		printf("Failed to find any images for configuration '%s/%s'\n",
		       conf_name, sig_name);
		return -ENOMSG;
	}

	return 0;

err_mem:
	printf("Out of memory processing configuration '%s/%s'\n", conf_name,
	       sig_name);
	return -ENOMEM;

err_path:
	printf("Failed to get path for image '%s' in configuration '%s/%s': %s\n",
	       iname, conf_name, sig_name, fdt_strerror(ret));
	return -ENOENT;
}
예제 #10
0
static retvalue parse_condition(const struct filebeingparsed *fbp, int column, const char **pp, /*@out@*/struct upload_condition *condition) {
	const char *p = *pp;
	struct upload_condition *fallback, *last, *or_scope;

	setzero(struct upload_condition, condition);

	/* allocate a new fallback-node:
	 * (this one is used to make it easier to concatenate those decision
	 * trees, especially it keeps open the possibility to have deny
	 * decisions) */
	fallback = zNEW(struct upload_condition);
	if (FAILEDTOALLOC(fallback))
		return RET_ERROR_OOM;
	fallback->type = uc_ALWAYS;
	assert(!fallback->accept_if_true);

	/* the queue with next has all nodes, so they can be freed
	 * (or otherwise modified) */
	condition->next = fallback;


	last = condition;
	or_scope = condition;

	while (true) {
		if (strncmp(p, "not", 3) == 0 &&
				xisspace(p[3])) {
			p += 3;
			while (*p != '\0' && xisspace(*p))
				p++;
			/* negate means false is good and true
			 * is bad: */
			last->accept_if_false = true;
			last->accept_if_true = false;
			last->next_if_false = NULL;
			last->next_if_true = fallback;
		} else {
			last->accept_if_false = false;
			last->accept_if_true = true;
			last->next_if_false = fallback;
			last->next_if_true = NULL;
		}
		if (p[0] == '*' && xisspace(p[1])) {
			last->type = uc_ALWAYS;
			p++;
		} else if (strncmp(p, "architectures", 13) == 0 &&
			   strchr(" \t'", p[13]) != NULL) {
			retvalue r;

			last->type = uc_ARCHITECTURES;
			last->needs = needs_all;
			p += 13;
			while (*p != '\0' && xisspace(*p))
				p++;
			if (strncmp(p, "contain", 7) == 0 &&
					strchr(" \t'", p[7]) != NULL) {
				last->needs = needs_any;
				p += 7;
			}

			r = parse_architectures(&last->atoms, &p,
					fbp, column + (p-*pp));
			if (RET_WAS_ERROR(r)) {
				uploadpermission_release(condition);
				return r;
			}
		} else if (strncmp(p, "binaries", 8) == 0 &&
			   strchr(" \t'", p[8]) != NULL) {
			retvalue r;

			last->type = uc_BINARIES;
			last->needs = needs_all;
			p += 8;
			while (*p != '\0' && xisspace(*p))
				p++;
			if (strncmp(p, "contain", 7) == 0 &&
					strchr(" \t'", p[7]) != NULL) {
				last->needs = needs_any;
				p += 7;
			}

			r = parse_stringpart(&last->strings, &p,
					fbp, column + (p-*pp));
			if (RET_WAS_ERROR(r)) {
				uploadpermission_release(condition);
				return r;
			}
		} else if (strncmp(p, "byhand", 6) == 0 &&
			   strchr(" \t'", p[6]) != NULL) {
			retvalue r;

			last->type = uc_BYHAND;
			last->needs = needs_existsall;
			p += 8;
			while (*p != '\0' && xisspace(*p))
				p++;
			if (*p != '\'') {
				strlist_init(&last->strings);
				r = RET_OK;
			} else
				r = parse_stringpart(&last->strings, &p,
						fbp, column + (p-*pp));
			if (RET_WAS_ERROR(r)) {
				uploadpermission_release(condition);
				return r;
			}
		} else if (strncmp(p, "sections", 8) == 0 &&
			   strchr(" \t'", p[8]) != NULL) {
			retvalue r;

			last->type = uc_SECTIONS;
			last->needs = needs_all;
			p += 8;
			while (*p != '\0' && xisspace(*p))
				p++;
			if (strncmp(p, "contain", 7) == 0 &&
					strchr(" \t'", p[7]) != NULL) {
				last->needs = needs_any;
				p += 7;
			}

			r = parse_stringpart(&last->strings, &p,
					fbp, column + (p-*pp));
			if (RET_WAS_ERROR(r)) {
				uploadpermission_release(condition);
				return r;
			}
		} else if (strncmp(p, "source", 6) == 0 &&
			   strchr(" \t'", p[6]) != NULL) {
			retvalue r;

			last->type = uc_SOURCENAME;
			p += 6;

			r = parse_stringpart(&last->strings, &p,
					fbp, column + (p-*pp));
			if (RET_WAS_ERROR(r)) {
				uploadpermission_release(condition);
				return r;
			}

		} else if (strncmp(p, "distribution", 12) == 0 &&
			   strchr(" \t'", p[12]) != NULL) {
			retvalue r;

			last->type = uc_CODENAME;
			p += 12;

			r = parse_stringpart(&last->strings, &p,
					fbp, column + (p-*pp));
			if (RET_WAS_ERROR(r)) {
				uploadpermission_release(condition);
				return r;
			}

		} else {
			errorcol(fbp, column + (int)(p - *pp),
"condition expected after 'allow' keyword!");
			uploadpermission_release(condition);
			return RET_ERROR;
		}
		while (*p != '\0' && xisspace(*p))
			p++;
		if (strncmp(p, "and", 3) == 0 && xisspace(p[3])) {
			struct upload_condition *n, *c;

			p += 3;

			n = zNEW(struct upload_condition);
			if (FAILEDTOALLOC(n)) {
				uploadpermission_release(condition);
				return RET_ERROR_OOM;
			}
			/* everything that yet made it succeed makes it need
			 * to check this condition: */
			for (c = condition ; c != NULL ; c = c->next) {
				if (c->accept_if_true) {
					c->next_if_true = n;
					c->accept_if_true = false;
				}
				if (c->accept_if_false) {
					c->next_if_false = n;
					c->accept_if_false = false;
				}
			}
			/* or will only bind to this one */
			or_scope = n;

			/* add it to queue: */
			assert (last->next == fallback);
			n->next = fallback;
			last->next = n;
			last = n;
		} else if (strncmp(p, "or", 2) == 0 && xisspace(p[2])) {
			struct upload_condition *n, *c;

			p += 2;

			n = zNEW(struct upload_condition);
			if (FAILEDTOALLOC(n)) {
				uploadpermission_release(condition);
				return RET_ERROR_OOM;
			}
			/* everything in current scope that made it fail
			 * now makes it check this: (currently that will
			 * only be true at most for c == last, but with
			 * parentheses this all will be needed) */
			for (c = or_scope ; c != NULL ; c = c->next) {
				if (c->next_if_true == fallback)
					c->next_if_true = n;
				if (c->next_if_false == fallback)
					c->next_if_false = n;
			}
			/* add it to queue: */
			assert (last->next == fallback);
			n->next = fallback;
			last->next = n;
			last = n;
		} else if (strncmp(p, "by", 2) == 0 && xisspace(p[2])) {
예제 #11
0
int extfs_mkfs(cdico *d, char *partition, int extfstype, char *fsoptions)
{
    cstrlist strfeatures;
    u64 features_tab[3];
    u64 fsextrevision;
    int origextfstype;
    char buffer[2048];
    char command[2048];
    char options[2048];
    char temp[1024];
    char progname[64];
    u64 e2fstoolsver;
    int compat_type;
    u64 temp64;
    int exitst;
    int ret=0;
    int res;
    int i;
    
    // init    
    memset(options, 0, sizeof(options));
    snprintf(progname, sizeof(progname), "mke2fs");
    strlist_init(&strfeatures);
    
    // ---- check that mkfs is installed and get its version
    if (exec_command(command, sizeof(command), NULL, NULL, 0, NULL, 0, "%s -V", progname)!=0)
    {   errprintf("%s not found. please install a recent e2fsprogs on your system or check the PATH.\n", progname);
        ret=-1;
        goto extfs_mkfs_cleanup;
    }
    e2fstoolsver=check_prog_version(progname);
    
    // ---- filesystem revision (good-old-rev or dynamic)
    if (dico_get_u64(d, 0, FSYSHEADKEY_FSEXTREVISION, &fsextrevision)!=0)
        fsextrevision=EXT2_DYNAMIC_REV; // don't fail (case of fs conversion to extfs)
    
    // "mke2fs -q" prevents problems in exec_command when too many output details printed
    strlcatf(options, sizeof(options), " -q ");
    
    // filesystem revision: good-old-rev or dynamic
    strlcatf(options, sizeof(options), " -r %d ", (int)fsextrevision);

    strlcatf(options, sizeof(options), " %s ", fsoptions);
    
    // ---- set the advanced filesystem settings from the dico
    if (dico_get_string(d, 0, FSYSHEADKEY_FSLABEL, buffer, sizeof(buffer))==0 && strlen(buffer)>0)
        strlcatf(options, sizeof(options), " -L '%.16s' ", buffer);
    
    if (dico_get_u64(d, 0, FSYSHEADKEY_FSEXTBLOCKSIZE, &temp64)==0)
        strlcatf(options, sizeof(options), " -b %ld ", (long)temp64);
    
    if (dico_get_u64(d, 0, FSYSHEADKEY_FSINODESIZE, &temp64)==0)
        strlcatf(options, sizeof(options), " -I %ld ", (long)temp64);
    
    // ---- get original filesystem features (if the original filesystem was an ext{2,3,4})
    if (dico_get_u64(d, 0, FSYSHEADKEY_FSEXTFEATURECOMPAT, &features_tab[E2P_FEATURE_COMPAT])!=0 ||
        dico_get_u64(d, 0, FSYSHEADKEY_FSEXTFEATUREINCOMPAT, &features_tab[E2P_FEATURE_INCOMPAT])!=0 ||
        dico_get_u64(d, 0, FSYSHEADKEY_FSEXTFEATUREROCOMPAT, &features_tab[E2P_FEATURE_RO_INCOMPAT])!=0)
    {   // dont fail the original filesystem may not be ext{2,3,4}. in that case set defaults features
        features_tab[E2P_FEATURE_COMPAT]=EXT2_FEATURE_COMPAT_RESIZE_INODE|EXT2_FEATURE_COMPAT_DIR_INDEX;
        features_tab[E2P_FEATURE_INCOMPAT]=EXT2_FEATURE_INCOMPAT_FILETYPE;
        features_tab[E2P_FEATURE_RO_INCOMPAT]=EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
    }
    
    // ---- check that fsarchiver is aware of all the filesystem features used on that filesystem
    if (extfs_check_compatibility(features_tab[E2P_FEATURE_COMPAT], features_tab[E2P_FEATURE_INCOMPAT], features_tab[E2P_FEATURE_RO_INCOMPAT])!=0)
    {   errprintf("this filesystem has ext{2,3,4} features which are not supported by this fsarchiver version.\n");
        return -1;
    }
    
    // ---- get original filesystem type
    origextfstype=extfs_get_fstype_from_compat_flags(features_tab[E2P_FEATURE_COMPAT], 
            features_tab[E2P_FEATURE_INCOMPAT], features_tab[E2P_FEATURE_RO_INCOMPAT]);
    msgprintf(MSG_VERB2, "the filesystem type determined by the original filesystem features is [%s]\n", format_fstype(origextfstype));
    
    // remove all the features not supported by the filesystem to create (conversion = downgrade fs)
    for (i=0; mkfeatures[i].name; i++)
    {
        compat_type=mkfeatures[i].compat;
        if (mkfeatures[i].firstfs > extfstype)
            features_tab[compat_type] &= ~mkfeatures[i].mask;
    }
    
    // add new features if the filesystem to create is newer than the filesystem type that was backed up
    // eg: user did a "savefs" of an ext3 and does a "restfs mkfs=ext4" --> add features to force ext4
    // it's a bit more difficult because we only want to add such a feature if no feature of the new
    // filesystem is currently enabled.
    msgprintf(MSG_VERB2, "the filesystem type to create considering the command options is [%s]\n", format_fstype(extfstype));
    if (origextfstype==EXTFSTYPE_EXT2 && extfstype>EXTFSTYPE_EXT2) // upgrade ext2 to ext{3,4}
    {   fsextrevision=EXT2_DYNAMIC_REV;
        features_tab[E2P_FEATURE_COMPAT]|=EXT3_FEATURE_COMPAT_HAS_JOURNAL;
    }
    if (origextfstype<EXTFSTYPE_EXT4 && extfstype>=EXTFSTYPE_EXT4) // upgrade ext{2,3} to ext4
    {   fsextrevision=EXT2_DYNAMIC_REV;
        features_tab[E2P_FEATURE_INCOMPAT]|=EXT3_FEATURE_INCOMPAT_EXTENTS;
    }
    
    // convert int features to string to be passed to mkfs
    for (i=0; mkfeatures[i].name; i++)
    {
        if (mkfeatures[i].firste2p<=e2fstoolsver) // don't pass an option to a program that does not support it
        {
            compat_type=mkfeatures[i].compat;
            if (features_tab[compat_type] & mkfeatures[i].mask)
            {   msgprintf(MSG_VERB2, "--> feature [%s]=YES\n", mkfeatures[i].name);
                strlist_add(&strfeatures, mkfeatures[i].name);
            }
            else
            {   msgprintf(MSG_VERB2, "--> feature [%s]=NO\n", mkfeatures[i].name);
                snprintf(temp, sizeof(temp), "^%s", mkfeatures[i].name); // exclude feature
                strlist_add(&strfeatures, temp);
            }
        }
    }
    
    // if extfs revision is dynamic and there are features in the list
    if (fsextrevision!=EXT2_GOOD_OLD_REV && strlist_count(&strfeatures)>0)
    {   strlist_merge(&strfeatures, temp, sizeof(temp), ',');
        strlcatf(options, sizeof(options), " -O %s ", temp);
        msgprintf(MSG_VERB2, "features: mkfs_options+=[-O %s]\n", temp);
    }
    
    // ---- check mke2fs version requirement
    msgprintf(MSG_VERB2, "mke2fs version detected: %s\n", format_prog_version(e2fstoolsver, temp, sizeof(temp)));
    msgprintf(MSG_VERB2, "mke2fs version required: %s\n", format_prog_version(e2fsprogs_minver[extfstype], temp, sizeof(temp)));
    if (e2fstoolsver < e2fsprogs_minver[extfstype])
    {   errprintf("mke2fs was found but is too old, please upgrade to a version %s or more recent.\n", 
            format_prog_version(e2fsprogs_minver[extfstype], temp, sizeof(temp)));
        ret=-1;
        goto extfs_mkfs_cleanup;
    }
    
    // ---- extended options
    if (dico_get_u64(d, 0, FSYSHEADKEY_FSEXTEOPTRAIDSTRIDE, &temp64)==0)
        strlcatf(options, sizeof(options), " -E stride=%ld ", (long)temp64);
    if ((dico_get_u64(d, 0, FSYSHEADKEY_FSEXTEOPTRAIDSTRIPEWIDTH, &temp64)==0) && e2fstoolsver>=PROGVER(1,40,7))
        strlcatf(options, sizeof(options), " -E stripe-width=%ld ", (long)temp64);
    
    // ---- execute mke2fs
    msgprintf(MSG_VERB2, "exec: %s\n", command);
    if (exec_command(command, sizeof(command), &exitst, NULL, 0, NULL, 0, "%s %s %s", progname, partition, options)!=0 || exitst!=0)
    {   errprintf("command [%s] failed with return status=%d\n", command, exitst);
        ret=-1;
        goto extfs_mkfs_cleanup;
    }
    
    // ---- use tune2fs to set the other advanced options
    memset(options, 0, sizeof(options));
    if (dico_get_string(d, 0, FSYSHEADKEY_FSUUID, buffer, sizeof(buffer))==0 && strlen(buffer)==36)
        strlcatf(options, sizeof(options), " -U %s ", buffer);
    
    if (dico_get_string(d, 0, FSYSHEADKEY_FSEXTDEFMNTOPT, buffer, sizeof(buffer))==0 && strlen(buffer)>0)
        strlcatf(options, sizeof(options), " -o %s ", buffer);
    
    if (dico_get_u64(d, 0, FSYSHEADKEY_FSEXTFSCKMAXMNTCOUNT, &temp64)==0)
        strlcatf(options, sizeof(options), " -c %ld ", (long)temp64);
    
    if (dico_get_u64(d, 0, FSYSHEADKEY_FSEXTFSCKCHECKINTERVAL, &temp64)==0)
        strlcatf(options, sizeof(options), " -i %ldd ", (long)(temp64/86400L));
    
    if (options[0])
    {
        if (exec_command(command, sizeof(command), &exitst, NULL, 0, NULL, 0, "tune2fs %s %s", partition, options)!=0 || exitst!=0)
        {   errprintf("command [%s] failed with return status=%d\n", command, exitst);
            ret=-1;
            goto extfs_mkfs_cleanup;
        }
        
        // run e2fsck to workaround an tune2fs bug in e2fsprogs < 1.41.4 on ext4
        // http://article.gmane.org/gmane.comp.file-systems.ext4/11181
        if (extfstype==EXTFSTYPE_EXT4 && e2fstoolsver<PROGVER(1,41,4))
        {
            if ( ((res=exec_command(command, sizeof(command), &exitst, NULL, 0, NULL, 0, "e2fsck -fy %s", partition))!=0) || ((exitst!=0) && (exitst!=1)) )
            {   errprintf("command [%s] failed with return status=%d\n", command, exitst);
                ret=-1;
                goto extfs_mkfs_cleanup;
            }
        }
    }
    
extfs_mkfs_cleanup:
    strlist_destroy(&strfeatures);
    return ret;
}