L4Re/departure

libext2fs/lib/libe2p/feature.c

617:2733e5770ee9
9 months ago Paul Boddie Made the run command wait for completion, introducing the spawn command to run programs in the background. Introduced conveniences for waiting for the last job to be initiated and for piping from the last job, also subscribing to signals from pipe-supplying jobs so that they may be transparently removed from the job list upon completion. Augmented the job listing with the "+" notation familiar from Unix. Prevented new jobs from being started when no job slots are available.
     1 /*     2  * feature.c --- convert between features and strings     3  *     4  * Copyright (C) 1999  Theodore Ts'o <tytso@mit.edu>     5  *     6  * %Begin-Header%     7  * This file may be redistributed under the terms of the GNU Library     8  * General Public License, version 2.     9  * %End-Header%    10  */    11     12 #include "config.h"    13 #include <stdio.h>    14 #include <stdlib.h>    15 #include <string.h>    16 #include <ctype.h>    17 #include <errno.h>    18     19 #include "e2p.h"    20 #include <ext2fs/ext2fs.h>    21 #include <ext2fs/kernel-jbd.h>    22     23 struct feature {    24 	int		compat;    25 	unsigned int	mask;    26 	const char	*string;    27 };    28     29 static struct feature feature_list[] = {    30 	{	E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_DIR_PREALLOC,    31 			"dir_prealloc" },    32 	{	E2P_FEATURE_COMPAT, EXT3_FEATURE_COMPAT_HAS_JOURNAL,    33 			"has_journal" },    34 	{	E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_IMAGIC_INODES,    35 			"imagic_inodes" },    36 	{	E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_EXT_ATTR,    37 			"ext_attr" },    38 	{	E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_DIR_INDEX,    39 			"dir_index" },    40 	{	E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_RESIZE_INODE,    41 			"resize_inode" },    42 	{	E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_LAZY_BG,    43 			"lazy_bg" },    44 	{	E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_EXCLUDE_BITMAP,    45 			"snapshot_bitmap" },    46 	{	E2P_FEATURE_COMPAT, EXT4_FEATURE_COMPAT_SPARSE_SUPER2,    47 			"sparse_super2" },    48 	{	E2P_FEATURE_COMPAT, EXT4_FEATURE_COMPAT_FAST_COMMIT,    49 			"fast_commit" },    50 	{	E2P_FEATURE_COMPAT, EXT4_FEATURE_COMPAT_STABLE_INODES,    51 			"stable_inodes" },    52     53 	{	E2P_FEATURE_RO_INCOMPAT, EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER,    54 			"sparse_super" },    55 	{	E2P_FEATURE_RO_INCOMPAT, EXT2_FEATURE_RO_COMPAT_LARGE_FILE,    56 			"large_file" },    57 	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_HUGE_FILE,    58 			"huge_file" },    59 	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_GDT_CSUM,    60 			"uninit_bg" },    61 	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_GDT_CSUM,    62 			"uninit_groups" },    63 	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_DIR_NLINK,    64 			"dir_nlink" },    65 	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE,    66 			"extra_isize" },    67 	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_QUOTA,    68 			"quota" },    69 	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_BIGALLOC,    70 			"bigalloc"},    71 	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_METADATA_CSUM,    72 			"metadata_csum"},    73 	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_REPLICA,    74 			"replica" },    75 	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_READONLY,    76 			"read-only" },    77 	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_PROJECT,    78 			"project"},    79 	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_SHARED_BLOCKS,    80 			"shared_blocks"},    81 	{	E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_VERITY,    82 			"verity"},    83     84 	{	E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_COMPRESSION,    85 			"compression" },    86 	{	E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_FILETYPE,    87 			"filetype" },    88 	{	E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_RECOVER,    89 			"needs_recovery" },    90 	{	E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_JOURNAL_DEV,    91 			"journal_dev" },    92 	{	E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_EXTENTS,    93 			"extent" },    94 	{	E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_EXTENTS,    95 			"extents" },    96 	{	E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_META_BG,    97 			"meta_bg" },    98 	{	E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_64BIT,    99 			"64bit" },   100 	{       E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_MMP,   101 			"mmp" },   102 	{       E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_FLEX_BG,   103 			"flex_bg"},   104 	{       E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_EA_INODE,   105 			"ea_inode"},   106 	{       E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_DIRDATA,   107 			"dirdata"},   108 	{       E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_CSUM_SEED,   109 			"metadata_csum_seed"},   110 	{       E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_LARGEDIR,   111 			"large_dir"},   112 	{       E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_INLINE_DATA,   113 			"inline_data"},   114 	{       E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_ENCRYPT,   115 			"encrypt"},   116 	{       E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_CASEFOLD,   117 			"casefold"},   118 	{       E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_CASEFOLD,   119 			"fname_encoding"},   120 	{	0, 0, 0 },   121 };   122    123 static struct feature jrnl_feature_list[] = {   124        {       E2P_FEATURE_COMPAT, JBD2_FEATURE_COMPAT_CHECKSUM,   125                        "journal_checksum" },   126    127        {       E2P_FEATURE_INCOMPAT, JBD2_FEATURE_INCOMPAT_REVOKE,   128                        "journal_incompat_revoke" },   129        {       E2P_FEATURE_INCOMPAT, JBD2_FEATURE_INCOMPAT_64BIT,   130                        "journal_64bit" },   131        {       E2P_FEATURE_INCOMPAT, JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT,   132                        "journal_async_commit" },   133        {       E2P_FEATURE_INCOMPAT, JBD2_FEATURE_INCOMPAT_CSUM_V2,   134                        "journal_checksum_v2" },   135        {       E2P_FEATURE_INCOMPAT, JBD2_FEATURE_INCOMPAT_CSUM_V3,   136                        "journal_checksum_v3" },   137        {       0, 0, 0 },   138 };   139    140 void e2p_feature_to_string(int compat, unsigned int mask, char *buf,   141                            size_t buf_len)   142 {   143 	struct feature  *f;   144 	char	fchar;   145 	int	fnum;   146    147 	for (f = feature_list; f->string; f++) {   148 		if ((compat == f->compat) &&   149 		    (mask == f->mask)) {   150 			strncpy(buf, f->string, buf_len);   151 			buf[buf_len - 1] = 0;   152 			return;   153 		}   154 	}   155 	switch (compat) {   156 	case  E2P_FEATURE_COMPAT:   157 		fchar = 'C';   158 		break;   159 	case E2P_FEATURE_INCOMPAT:   160 		fchar = 'I';   161 		break;   162 	case E2P_FEATURE_RO_INCOMPAT:   163 		fchar = 'R';   164 		break;   165 	default:   166 		fchar = '?';   167 		break;   168 	}   169 	for (fnum = 0; mask >>= 1; fnum++);   170 	sprintf(buf, "FEATURE_%c%d", fchar, fnum);   171 }   172    173 const char *e2p_feature2string(int compat, unsigned int mask)   174 {   175 	static char buf[20];   176    177 	e2p_feature_to_string(compat, mask, buf, sizeof(buf) / sizeof(buf[0]));   178 	return buf;   179 }   180    181 int e2p_string2feature(char *string, int *compat_type, unsigned int *mask)   182 {   183 	struct feature  *f;   184 	char		*eptr;   185 	int		num;   186    187 	for (f = feature_list; f->string; f++) {   188 		if (!strcasecmp(string, f->string)) {   189 			*compat_type = f->compat;   190 			*mask = f->mask;   191 			return 0;   192 		}   193 	}   194 	if (strncasecmp(string, "FEATURE_", 8))   195 		return 1;   196    197 	switch (string[8]) {   198 	case 'c':   199 	case 'C':   200 		*compat_type = E2P_FEATURE_COMPAT;   201 		break;   202 	case 'i':   203 	case 'I':   204 		*compat_type = E2P_FEATURE_INCOMPAT;   205 		break;   206 	case 'r':   207 	case 'R':   208 		*compat_type = E2P_FEATURE_RO_INCOMPAT;   209 		break;   210 	default:   211 		return 1;   212 	}   213 	if (string[9] == 0)   214 		return 1;   215 	num = strtol(string+9, &eptr, 10);   216 	if (num > 31 || num < 0)   217 		return 1;   218 	if (*eptr)   219 		return 1;   220 	*mask = 1 << num;   221 	return 0;   222 }   223    224 const char *e2p_jrnl_feature2string(int compat, unsigned int mask)   225 {   226 	struct feature  *f;   227 	static char buf[20];   228 	char	fchar;   229 	int	fnum;   230    231 	for (f = jrnl_feature_list; f->string; f++) {   232 		if ((compat == f->compat) &&   233 		    (mask == f->mask))   234 			return f->string;   235 	}   236 	switch (compat) {   237 	case  E2P_FEATURE_COMPAT:   238 		fchar = 'C';   239 		break;   240 	case E2P_FEATURE_INCOMPAT:   241 		fchar = 'I';   242 		break;   243 	case E2P_FEATURE_RO_INCOMPAT:   244 		fchar = 'R';   245 		break;   246 	default:   247 		fchar = '?';   248 		break;   249 	}   250 	for (fnum = 0; mask >>= 1; fnum++);   251 	sprintf(buf, "FEATURE_%c%d", fchar, fnum);   252 	return buf;   253 }   254    255 int e2p_jrnl_string2feature(char *string, int *compat_type, unsigned int *mask)   256 {   257 	struct feature  *f;   258 	char		*eptr;   259 	int		num;   260    261 	for (f = jrnl_feature_list; f->string; f++) {   262 		if (!strcasecmp(string, f->string)) {   263 			*compat_type = f->compat;   264 			*mask = f->mask;   265 			return 0;   266 		}   267 	}   268 	if (strncasecmp(string, "FEATURE_", 8))   269 		return 1;   270    271 	switch (string[8]) {   272 	case 'c':   273 	case 'C':   274 		*compat_type = E2P_FEATURE_COMPAT;   275 		break;   276 	case 'i':   277 	case 'I':   278 		*compat_type = E2P_FEATURE_INCOMPAT;   279 		break;   280 	case 'r':   281 	case 'R':   282 		*compat_type = E2P_FEATURE_RO_INCOMPAT;   283 		break;   284 	default:   285 		return 1;   286 	}   287 	if (string[9] == 0)   288 		return 1;   289 	num = strtol(string+9, &eptr, 10);   290 	if (num > 31 || num < 0)   291 		return 1;   292 	if (*eptr)   293 		return 1;   294 	*mask = 1 << num;   295 	return 0;   296 }   297 static char *skip_over_blanks(char *cp)   298 {   299 	while (*cp && isspace(*cp))   300 		cp++;   301 	return cp;   302 }   303    304 static char *skip_over_word(char *cp)   305 {   306 	while (*cp && !isspace(*cp) && *cp != ',')   307 		cp++;   308 	return cp;   309 }   310    311 /*   312  * Edit a feature set array as requested by the user.  The ok_array,   313  * if set, allows the application to limit what features the user is   314  * allowed to set or clear using this function.  If clear_ok_array is set,   315  * then use it tell whether or not it is OK to clear a filesystem feature.   316  */   317 int e2p_edit_feature2(const char *str, __u32 *compat_array, __u32 *ok_array,   318 		      __u32 *clear_ok_array, int *type_err,   319 		      unsigned int *mask_err)   320 {   321 	char		*cp, *buf, *next;   322 	int		neg;   323 	unsigned int	mask;   324 	int		compat_type;   325 	int		rc = 0;   326    327 	if (!clear_ok_array)   328 		clear_ok_array = ok_array;   329    330 	if (type_err)   331 		*type_err = 0;   332 	if (mask_err)   333 		*mask_err = 0;   334    335 	buf = malloc(strlen(str)+1);   336 	if (!buf)   337 		return 1;   338 	strcpy(buf, str);   339 	for (cp = buf; cp && *cp; cp = next ? next+1 : 0) {   340 		neg = 0;   341 		cp = skip_over_blanks(cp);   342 		next = skip_over_word(cp);   343    344 		if (*next == 0)   345 			next = 0;   346 		else   347 			*next = 0;   348    349 		if ((strcasecmp(cp, "none") == 0) ||   350 		    (strcasecmp(cp, "clear") == 0)) {   351 			compat_array[0] = 0;   352 			compat_array[1] = 0;   353 			compat_array[2] = 0;   354 			continue;   355 		}   356    357 		switch (*cp) {   358 		case '-':   359 		case '^':   360 			neg++;   361 			/* fallthrough */   362 		case '+':   363 			cp++;   364 			break;   365 		}   366 		if (e2p_string2feature(cp, &compat_type, &mask)) {   367 			rc = 1;   368 			break;   369 		}   370 		if (neg) {   371 			if (clear_ok_array &&   372 			    !(clear_ok_array[compat_type] & mask)) {   373 				rc = 1;   374 				if (type_err)   375 					*type_err = (compat_type |   376 						     E2P_FEATURE_NEGATE_FLAG);   377 				if (mask_err)   378 					*mask_err = mask;   379 				break;   380 			}   381 			compat_array[compat_type] &= ~mask;   382 		} else {   383 			if (ok_array && !(ok_array[compat_type] & mask)) {   384 				rc = 1;   385 				if (type_err)   386 					*type_err = compat_type;   387 				if (mask_err)   388 					*mask_err = mask;   389 				break;   390 			}   391 			compat_array[compat_type] |= mask;   392 		}   393 	}   394 	free(buf);   395 	return rc;   396 }   397    398 int e2p_edit_feature(const char *str, __u32 *compat_array, __u32 *ok_array)   399 {   400 	return e2p_edit_feature2(str, compat_array, ok_array, 0, 0, 0);   401 }   402    403 #ifdef TEST_PROGRAM   404 int main(int argc, char **argv)   405 {   406 	int compat, compat2, i;   407 	unsigned int mask, mask2;   408 	const char *str;   409 	struct feature *f;   410    411 	for (i = 0; i < 2; i++) {   412 		if (i == 0) {   413 			f = feature_list;   414 			printf("Feature list:\n");   415 		} else {   416 			printf("\nJournal feature list:\n");   417 			f = jrnl_feature_list;   418 		}   419 		for (; f->string; f++) {   420 			if (i == 0) {   421 				e2p_string2feature((char *)f->string, &compat,   422 						   &mask);   423 				str = e2p_feature2string(compat, mask);   424 			} else {   425 				e2p_jrnl_string2feature((char *)f->string,   426 							&compat, &mask);   427 				str = e2p_jrnl_feature2string(compat, mask);   428 			}   429    430 			printf("\tCompat = %d, Mask = %u, %s\n",   431 			       compat, mask, f->string);   432 			if (strcmp(f->string, str)) {   433 				if (e2p_string2feature((char *) str, &compat2,   434 						       &mask2) ||   435 				    (compat2 != compat) ||   436 				    (mask2 != mask)) {   437 					fprintf(stderr, "Failure!\n");   438 					exit(1);   439 				}   440 			}   441 		}   442 	}   443 	exit(0);   444 }   445 #endif