From 53600591311a129717abd2e3bcaa302622a6ce67 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 23 Oct 2010 21:06:06 +0200 Subject: libbb: introduce and use strcpy_and_process_escape_sequences function old new delta strcpy_and_process_escape_sequences - 50 +50 bb_process_escape_sequence 148 138 -10 printf_main 789 776 -13 getty_main 1897 1831 -66 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 0/3 up/down: 50/-89) Total: -39 bytes Signed-off-by: Denys Vlasenko --- libbb/parse_config.c | 14 +------------ libbb/process_escape_sequence.c | 44 ++++++++++++++++++++++++++++------------- 2 files changed, 31 insertions(+), 27 deletions(-) (limited to 'libbb') diff --git a/libbb/parse_config.c b/libbb/parse_config.c index 3fff9f212..9dbfaf5d7 100644 --- a/libbb/parse_config.c +++ b/libbb/parse_config.c @@ -187,19 +187,7 @@ again: #if 0 /* unused so far */ if (flags & PARSE_ESCAPE) { - const char *from; - char *to; - - from = to = tokens[t]; - while (*from) { - if (*from == '\\') { - from++; - *to++ = bb_process_escape_sequence(&from); - } else { - *to++ = *from++; - } - } - *to = '\0'; + strcpy_and_process_escape_sequences(tokens[t], tokens[t]); } #endif /* Skip possible delimiters */ diff --git a/libbb/process_escape_sequence.c b/libbb/process_escape_sequence.c index 82cbe10dc..dd6e076b0 100644 --- a/libbb/process_escape_sequence.c +++ b/libbb/process_escape_sequence.c @@ -31,14 +31,13 @@ char FAST_FUNC bb_process_escape_sequence(const char **ptr) unsigned num_digits; unsigned r; unsigned n; - unsigned d; unsigned base; num_digits = n = 0; base = 8; q = *ptr; -#ifdef WANT_HEX_ESCAPES +#if WANT_HEX_ESCAPES if (*q == 'x') { ++q; base = 16; @@ -50,20 +49,21 @@ char FAST_FUNC bb_process_escape_sequence(const char **ptr) * \02 works, \2 does not (prints \ and 2). * We treat \2 as a valid octal escape sequence. */ do { - d = (unsigned char)(*q) - '0'; -#ifdef WANT_HEX_ESCAPES - if (d >= 10) { - d = (unsigned char)(_tolower(*q)) - 'a' + 10; - } +#if !WANT_HEX_ESCAPES + unsigned d = (unsigned char)(*q) - '0'; +#else + unsigned d = (unsigned char)_tolower(*q) - '0'; + if (d >= 10) + d += ('0' - 'a' + 10); #endif - if (d >= base) { -#ifdef WANT_HEX_ESCAPES - if ((base == 16) && (!--num_digits)) { -/* return '\\'; */ - --q; + if (WANT_HEX_ESCAPES && base == 16) { + --num_digits; + if (num_digits == 0) { + /* \x */ + --q; /* go back to x */ + } } -#endif break; } @@ -85,7 +85,9 @@ char FAST_FUNC bb_process_escape_sequence(const char **ptr) } } while (*++p); /* p points to found escape char or NUL, - * advance it and find what it translates to */ + * advance it and find what it translates to. + * Note that unrecognized sequence \z returns '\' + * and leaves ptr pointing to z. */ p += sizeof(charmap) / 2; n = *p; } @@ -94,3 +96,17 @@ char FAST_FUNC bb_process_escape_sequence(const char **ptr) return (char) n; } + +char* FAST_FUNC strcpy_and_process_escape_sequences(char *dst, const char *src) +{ + while (1) { + char c, c1; + c = c1 = *src++; + if (c1 == '\\') + c1 = bb_process_escape_sequence(&src); + *dst = c1; + if (c == '\0') + return dst; + dst++; + } +} -- cgit v1.2.3-55-g6feb From 2b299fed6a77d3aaf7e4e768fb519f2536c2eff0 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 24 Oct 2010 01:58:04 +0200 Subject: awk: fix breakage in last commit While at it, made bb_process_escape_sequence faster (same size) function old new delta nextchar 49 53 +4 bb_process_escape_sequence 138 140 +2 next_token 838 839 +1 static.charmap 20 18 -2 is_assignment 143 135 -8 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 3/2 up/down: 7/-10) Total: -3 bytes Signed-off-by: Denys Vlasenko --- editors/awk.c | 27 +++++++++++++----------- libbb/process_escape_sequence.c | 46 ++++++++++++++++++++--------------------- 2 files changed, 38 insertions(+), 35 deletions(-) (limited to 'libbb') diff --git a/editors/awk.c b/editors/awk.c index fb3bf6b47..9646cedd6 100644 --- a/editors/awk.c +++ b/editors/awk.c @@ -684,8 +684,11 @@ static char nextchar(char **s) pps = *s; if (c == '\\') c = bb_process_escape_sequence((const char**)s); - if (c == '\\' && *s == pps) - c = *(*s)++; + if (c == '\\' && *s == pps) { /* unrecognized \z? */ + c = *(*s); /* yes, fetch z */ + if (c) + (*s)++; /* advance unless z = NUL */ + } return c; } @@ -1007,9 +1010,10 @@ static uint32_t next_token(uint32_t expected) /* it's a string */ t_string = s = ++p; while (*p != '\"') { - char *pp = p; + char *pp; if (*p == '\0' || *p == '\n') syntax_error(EMSG_UNEXP_EOS); + pp = p; *s++ = nextchar(&pp); p = pp; } @@ -2926,22 +2930,21 @@ static int awk_exit(int r) * otherwise return 0 */ static int is_assignment(const char *expr) { - char *exprc, *s, *s0, *s1; + char *exprc, *val, *s, *s1; - if (!isalnum_(*expr) || (s0 = strchr(expr, '=')) == NULL) { + if (!isalnum_(*expr) || (val = strchr(expr, '=')) == NULL) { return FALSE; } exprc = xstrdup(expr); - s0 = exprc + (s0 - expr); - *s++ = '\0'; + val = exprc + (val - expr); + *val++ = '\0'; - s = s1 = s0; - while (*s) - *s1++ = nextchar(&s); - *s1 = '\0'; + s = s1 = val; + while ((*s1 = nextchar(&s)) != '\0') + s1++; - setvar_u(newvar(exprc), s0); + setvar_u(newvar(exprc), val); free(exprc); return TRUE; } diff --git a/libbb/process_escape_sequence.c b/libbb/process_escape_sequence.c index dd6e076b0..7b1d97f9c 100644 --- a/libbb/process_escape_sequence.c +++ b/libbb/process_escape_sequence.c @@ -18,18 +18,8 @@ char FAST_FUNC bb_process_escape_sequence(const char **ptr) { - /* bash builtin "echo -e '\ec'" interprets \e as ESC, - * but coreutils "/bin/echo -e '\ec'" does not. - * manpages tend to support coreutils way. - * Update: coreutils added support for \e on 28 Oct 2009. */ - static const char charmap[] ALIGN1 = { - 'a', 'b', 'e', 'f', 'n', 'r', 't', 'v', '\\', 0, - '\a', '\b', 27, '\f', '\n', '\r', '\t', '\v', '\\', '\\' }; - - const char *p; const char *q; unsigned num_digits; - unsigned r; unsigned n; unsigned base; @@ -37,18 +27,17 @@ char FAST_FUNC bb_process_escape_sequence(const char **ptr) base = 8; q = *ptr; -#if WANT_HEX_ESCAPES - if (*q == 'x') { + if (WANT_HEX_ESCAPES && *q == 'x') { ++q; base = 16; ++num_digits; } -#endif /* bash requires leading 0 in octal escapes: * \02 works, \2 does not (prints \ and 2). * We treat \2 as a valid octal escape sequence. */ do { + unsigned r; #if !WANT_HEX_ESCAPES unsigned d = (unsigned char)(*q) - '0'; #else @@ -60,8 +49,9 @@ char FAST_FUNC bb_process_escape_sequence(const char **ptr) if (WANT_HEX_ESCAPES && base == 16) { --num_digits; if (num_digits == 0) { - /* \x */ - --q; /* go back to x */ + /* \x: return '\', + * leave ptr pointing to x */ + return '\\'; } } break; @@ -76,20 +66,30 @@ char FAST_FUNC bb_process_escape_sequence(const char **ptr) ++q; } while (++num_digits < 3); - if (num_digits == 0) { /* mnemonic escape sequence? */ - p = charmap; + if (num_digits == 0) { + /* Not octal or hex escape sequence. + * Is it one-letter one? */ + + /* bash builtin "echo -e '\ec'" interprets \e as ESC, + * but coreutils "/bin/echo -e '\ec'" does not. + * Manpages tend to support coreutils way. + * Update: coreutils added support for \e on 28 Oct 2009. */ + static const char charmap[] ALIGN1 = { + 'a', 'b', 'e', 'f', 'n', 'r', 't', 'v', '\\', + '\a', '\b', 27, '\f', '\n', '\r', '\t', '\v', '\\', + }; + const char *p = charmap; do { if (*p == *q) { q++; break; } - } while (*++p); - /* p points to found escape char or NUL, + } while (*++p != '\\'); + /* p points to found escape char or '\', * advance it and find what it translates to. - * Note that unrecognized sequence \z returns '\' - * and leaves ptr pointing to z. */ - p += sizeof(charmap) / 2; - n = *p; + * Note that \NUL and unrecognized sequence \z return '\' + * and leave ptr pointing to NUL or z. */ + n = p[sizeof(charmap) / 2]; } *ptr = q; -- cgit v1.2.3-55-g6feb From f4c93ab30460667cb3506a89a5419508a7bcfa0e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 24 Oct 2010 19:27:30 +0200 Subject: sha1: use Rob's code, it's smaller and faster function old new delta static.rconsts - 16 +16 sha1_process_block64 460 298 -162 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 0/1 up/down: 16/-162) Total: -146 bytes Signed-off-by: Denys Vlasenko --- libbb/hash_md5_sha.c | 105 +++++++++++++++++++++++++-------------------------- 1 file changed, 51 insertions(+), 54 deletions(-) (limited to 'libbb') diff --git a/libbb/hash_md5_sha.c b/libbb/hash_md5_sha.c index aeacddef8..5e4078ae6 100644 --- a/libbb/hash_md5_sha.c +++ b/libbb/hash_md5_sha.c @@ -473,20 +473,13 @@ void FAST_FUNC md5_end(md5_ctx_t *ctx, void *resbuf) /* - * Based on shasum from http://www.netsw.org/crypto/hash/ - * Majorly hacked up to use Dr Brian Gladman's sha1 code + * SHA1 part is: + * Copyright 2007 Rob Landley * - * Copyright (C) 2002 Dr Brian Gladman , Worcester, UK. - * Copyright (C) 2003 Glenn L. McGrath - * Copyright (C) 2003 Erik Andersen - * - * Licensed under GPLv2 or later, see file LICENSE in this source tree. - * - * --------------------------------------------------------------------------- - * Issue Date: 10/11/2002 + * Based on the public domain SHA-1 in C by Steve Reid + * from http://www.mirrors.wiretapped.net/security/cryptography/hashes/sha1/ * - * This is a byte oriented version of SHA1 that operates on arrays of bytes - * stored in memory. It runs at 22 cycles per byte on a Pentium P4 processor + * Licensed under GPLv2, see file LICENSE in this source tree. * * --------------------------------------------------------------------------- * @@ -503,16 +496,18 @@ void FAST_FUNC md5_end(md5_ctx_t *ctx, void *resbuf) static void FAST_FUNC sha1_process_block64(sha1_ctx_t *ctx) { - unsigned t; - uint32_t W[80], a, b, c, d, e; - const uint32_t *words = (uint32_t*) ctx->wbuffer; + static const uint32_t rconsts[] = { + 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 + }; + int i, j; + int cnt; + uint32_t W[16+16]; + uint32_t a, b, c, d, e; - for (t = 0; t < 16; ++t) - W[t] = SWAP_BE32(words[t]); - for (/*t = 16*/; t < 80; ++t) { - uint32_t T = W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]; - W[t] = rotl32(T, 1); - } + /* On-stack work buffer frees up one register in the main loop + * which otherwise will be needed to hold ctx pointer */ + for (i = 0; i < 16; i++) + W[i] = W[i+16] = SWAP_BE32(((uint32_t*)ctx->wbuffer)[i]); a = ctx->hash[0]; b = ctx->hash[1]; @@ -520,39 +515,41 @@ static void FAST_FUNC sha1_process_block64(sha1_ctx_t *ctx) d = ctx->hash[3]; e = ctx->hash[4]; -#undef ch -#undef parity -#undef maj -#undef rnd -#define ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z)))) -#define parity(x,y,z) ((x) ^ (y) ^ (z)) -#define maj(x,y,z) (((x) & (y)) | ((z) & ((x) | (y)))) -/* A normal version as set out in the FIPS. */ -#define rnd(f,k) \ - do { \ - uint32_t T = a; \ - a = rotl32(a, 5) + f(b, c, d) + e + k + W[t]; \ - e = d; \ - d = c; \ - c = rotl32(b, 30); \ - b = T; \ - } while (0) - - for (t = 0; t < 20; ++t) - rnd(ch, 0x5a827999); - - for (/*t = 20*/; t < 40; ++t) - rnd(parity, 0x6ed9eba1); - - for (/*t = 40*/; t < 60; ++t) - rnd(maj, 0x8f1bbcdc); - - for (/*t = 60*/; t < 80; ++t) - rnd(parity, 0xca62c1d6); -#undef ch -#undef parity -#undef maj -#undef rnd + /* 4 rounds of 20 operations each */ + cnt = 0; + for (i = 0; i < 4; i++) { + j = 19; + do { + uint32_t work; + + work = c ^ d; + if (i == 0) { + work = (work & b) ^ d; + if (j <= 3) + goto ge16; + /* Used to do SWAP_BE32 here, but this + * requires ctx (see comment above) */ + work += W[cnt]; + } else { + if (i == 2) + work = ((b | c) & d) | (b & c); + else /* i = 1 or 3 */ + work ^= b; + ge16: + W[cnt] = W[cnt+16] = rotl32(W[cnt+13] ^ W[cnt+8] ^ W[cnt+2] ^ W[cnt], 1); + work += W[cnt]; + } + work = e + work + rotl32(a, 5) + rconsts[i]; + + /* Rotate by one for next time */ + e = d; + d = c; + c = /* b = */ rotl32(b, 30); + b = a; + a = work; + cnt = (cnt + 1) & 15; + } while (--j >= 0); + } ctx->hash[0] += a; ctx->hash[1] += b; -- cgit v1.2.3-55-g6feb From 03a5fe378e50cb7a43c4c367c6c0e18e6f156597 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 24 Oct 2010 20:51:28 +0200 Subject: sha1: small tweak for clearer code, no logic changes Signed-off-by: Denys Vlasenko --- libbb/hash_md5_sha.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libbb') diff --git a/libbb/hash_md5_sha.c b/libbb/hash_md5_sha.c index 5e4078ae6..e427f6080 100644 --- a/libbb/hash_md5_sha.c +++ b/libbb/hash_md5_sha.c @@ -539,7 +539,7 @@ static void FAST_FUNC sha1_process_block64(sha1_ctx_t *ctx) W[cnt] = W[cnt+16] = rotl32(W[cnt+13] ^ W[cnt+8] ^ W[cnt+2] ^ W[cnt], 1); work += W[cnt]; } - work = e + work + rotl32(a, 5) + rconsts[i]; + work += e + rotl32(a, 5) + rconsts[i]; /* Rotate by one for next time */ e = d; -- cgit v1.2.3-55-g6feb From ccb070450e79c33fb3f755dbea2fdd979f09d3fb Mon Sep 17 00:00:00 2001 From: Kevin Cernekee Date: Mon, 25 Oct 2010 02:00:24 +0200 Subject: fdisk: initial stab at GPT partition support Signed-off-by: Kevin Cernekee Signed-off-by: Denys Vlasenko --- include/libbb.h | 7 +- libbb/human_readable.c | 4 +- util-linux/Config.src | 8 ++ util-linux/fdisk.c | 79 +++++++++++++------ util-linux/fdisk_gpt.c | 203 +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 275 insertions(+), 26 deletions(-) create mode 100644 util-linux/fdisk_gpt.c (limited to 'libbb') diff --git a/include/libbb.h b/include/libbb.h index bd1d586c7..d14728ed0 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -746,7 +746,7 @@ char *itoa(int n) FAST_FUNC; char *utoa_to_buf(unsigned n, char *buf, unsigned buflen) FAST_FUNC; char *itoa_to_buf(int n, char *buf, unsigned buflen) FAST_FUNC; /* Intelligent formatters of bignums */ -void smart_ulltoa4(unsigned long long ul, char buf[5], const char *scale) FAST_FUNC; +void smart_ulltoa4(unsigned long long ul, char buf[4], const char *scale) FAST_FUNC; void smart_ulltoa5(unsigned long long ul, char buf[5], const char *scale) FAST_FUNC; /* If block_size == 0, display size without fractional part, * else display (size * block_size) with one decimal digit. @@ -1543,7 +1543,10 @@ void sha512_begin(sha512_ctx_t *ctx) FAST_FUNC; void sha512_hash(sha512_ctx_t *ctx, const void *buffer, size_t len) FAST_FUNC; void sha512_end(sha512_ctx_t *ctx, void *resbuf) FAST_FUNC; - +/* TODO: add global crc32_table pointer and create + * LE and BE functions to calculate crc32 over given bytes. + * Currently we have about five reimplementations... + */ uint32_t *crc32_filltable(uint32_t *tbl256, int endian) FAST_FUNC; typedef struct masks_labels_t { diff --git a/libbb/human_readable.c b/libbb/human_readable.c index 22dc5d23f..50cbe41bb 100644 --- a/libbb/human_readable.c +++ b/libbb/human_readable.c @@ -94,7 +94,7 @@ const char* FAST_FUNC make_human_readable_str(unsigned long long val, /* Convert unsigned long long value into compact 5-char representation. * String is not terminated (buf[5] is untouched) */ -void FAST_FUNC smart_ulltoa5(unsigned long long ul, char buf[6], const char *scale) +void FAST_FUNC smart_ulltoa5(unsigned long long ul, char buf[5], const char *scale) { const char *fmt; char c; @@ -150,7 +150,7 @@ void FAST_FUNC smart_ulltoa5(unsigned long long ul, char buf[6], const char *sca /* Convert unsigned long long value into compact 4-char * representation. Examples: "1234", "1.2k", " 27M", "123T" * String is not terminated (buf[4] is untouched) */ -void FAST_FUNC smart_ulltoa4(unsigned long long ul, char buf[5], const char *scale) +void FAST_FUNC smart_ulltoa4(unsigned long long ul, char buf[4], const char *scale) { const char *fmt; char c; diff --git a/util-linux/Config.src b/util-linux/Config.src index afa30923b..19b309e57 100644 --- a/util-linux/Config.src +++ b/util-linux/Config.src @@ -181,6 +181,14 @@ config FEATURE_OSF_LABEL Enabling this option allows you to create or change BSD disklabels and define and edit BSD disk slices. +config FEATURE_GPT_LABEL + bool "Support GPT disklabels" + default n + depends on FDISK && FEATURE_FDISK_WRITABLE + help + Enabling this option allows you to view GUID Partition Table + disklabels. + config FEATURE_FDISK_ADVANCED bool "Support expert mode" default y diff --git a/util-linux/fdisk.c b/util-linux/fdisk.c index b6417a355..3f2e0d3ae 100644 --- a/util-linux/fdisk.c +++ b/util-linux/fdisk.c @@ -107,12 +107,30 @@ struct partition { unsigned char size4[4]; /* nr of sectors in partition */ } PACKED; +/* + * per partition table entry data + * + * The four primary partitions have the same sectorbuffer (MBRbuffer) + * and have NULL ext_pointer. + * Each logical partition table entry has two pointers, one for the + * partition and one link to the next one. + */ +struct pte { + struct partition *part_table; /* points into sectorbuffer */ + struct partition *ext_pointer; /* points into sectorbuffer */ + sector_t offset_from_dev_start; /* disk sector number */ + char *sectorbuffer; /* disk sector contents */ +#if ENABLE_FEATURE_FDISK_WRITABLE + char changed; /* boolean */ +#endif +}; + #define unable_to_open "can't open '%s'" #define unable_to_read "can't read from %s" #define unable_to_seek "can't seek on %s" enum label_type { - LABEL_DOS, LABEL_SUN, LABEL_SGI, LABEL_AIX, LABEL_OSF + LABEL_DOS, LABEL_SUN, LABEL_SGI, LABEL_AIX, LABEL_OSF, LABEL_GPT }; #define LABEL_IS_DOS (LABEL_DOS == current_label_type) @@ -149,6 +167,14 @@ enum label_type { #define STATIC_OSF extern #endif +#if ENABLE_FEATURE_GPT_LABEL +#define LABEL_IS_GPT (LABEL_GPT == current_label_type) +#define STATIC_GPT static +#else +#define LABEL_IS_GPT 0 +#define STATIC_GPT extern +#endif + enum action { OPEN_MAIN, TRY_ONLY, CREATE_EMPTY_DOS, CREATE_EMPTY_SUN }; static void update_units(void); @@ -162,6 +188,7 @@ static sector_t read_int(sector_t low, sector_t dflt, sector_t high, sector_t ba #endif static const char *partition_type(unsigned char type); static void get_geometry(void); +static void read_pte(struct pte *pe, sector_t offset); #if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE static int get_boot(enum action what); #else @@ -174,24 +201,6 @@ static int get_boot(void); static sector_t get_start_sect(const struct partition *p); static sector_t get_nr_sects(const struct partition *p); -/* - * per partition table entry data - * - * The four primary partitions have the same sectorbuffer (MBRbuffer) - * and have NULL ext_pointer. - * Each logical partition table entry has two pointers, one for the - * partition and one link to the next one. - */ -struct pte { - struct partition *part_table; /* points into sectorbuffer */ - struct partition *ext_pointer; /* points into sectorbuffer */ - sector_t offset_from_dev_start; /* disk sector number */ - char *sectorbuffer; /* disk sector contents */ -#if ENABLE_FEATURE_FDISK_WRITABLE - char changed; /* boolean */ -#endif -}; - /* DOS partition types */ static const char *const i386_sys_types[] = { @@ -653,6 +662,8 @@ STATIC_OSF void bsd_select(void); STATIC_OSF void xbsd_print_disklabel(int); #include "fdisk_osf.c" +#include "fdisk_gpt.c" + #if ENABLE_FEATURE_SGI_LABEL || ENABLE_FEATURE_SUN_LABEL static uint16_t fdisk_swap16(uint16_t x) @@ -833,6 +844,11 @@ menu(void) puts("o\tcreate a new empty DOS partition table"); puts("q\tquit without saving changes"); puts("s\tcreate a new empty Sun disklabel"); /* sun */ + } else if (LABEL_IS_GPT) { + puts("o\tcreate a new empty DOS partition table"); + puts("p\tprint the partition table"); + puts("q\tquit without saving changes"); + puts("s\tcreate a new empty Sun disklabel"); /* sun */ } else { puts("a\ttoggle a bootable flag"); puts("b\tedit bsd disklabel"); @@ -1308,7 +1324,18 @@ get_geometry(void) /* * Opens disk_device and optionally reads MBR. - * FIXME: document what each 'what' value will do! + * If what == OPEN_MAIN: + * Open device, read MBR. Abort program on short read. Create empty + * disklabel if the on-disk structure is invalid (WRITABLE mode). + * If what == TRY_ONLY: + * Open device, read MBR. Return an error if anything is out of place. + * Do not create an empty disklabel. This is used for the "list" + * operations: "fdisk -l /dev/sda" and "fdisk -l" (all devices). + * If what == CREATE_EMPTY_*: + * This means that get_boot() was called recursively from create_*label(). + * Do not re-open the device; just set up the ptes array and print + * geometry warnings. + * * Returns: * -1: no 0xaa55 flag present (possibly entire disk BSD) * 0: found or created label @@ -1390,6 +1417,10 @@ static int get_boot(void) if (check_aix_label()) return 0; #endif +#if ENABLE_FEATURE_GPT_LABEL + if (check_gpt_label()) + return 0; +#endif #if ENABLE_FEATURE_OSF_LABEL if (check_osf_label()) { possibly_osf_label = 1; @@ -1409,7 +1440,7 @@ static int get_boot(void) if (!valid_part_table_flag(MBRbuffer)) { if (what == OPEN_MAIN) { printf("Device contains neither a valid DOS " - "partition table, nor Sun, SGI or OSF " + "partition table, nor Sun, SGI, OSF or GPT " "disklabel\n"); #ifdef __sparc__ IF_FEATURE_SUN_LABEL(create_sunlabel();) @@ -2056,10 +2087,14 @@ list_table(int xtra) sun_list_table(xtra); return; } - if (LABEL_IS_SUN) { + if (LABEL_IS_SGI) { sgi_list_table(xtra); return; } + if (LABEL_IS_GPT) { + gpt_list_table(xtra); + return; + } list_disk_geometry(); diff --git a/util-linux/fdisk_gpt.c b/util-linux/fdisk_gpt.c new file mode 100644 index 000000000..98803ec88 --- /dev/null +++ b/util-linux/fdisk_gpt.c @@ -0,0 +1,203 @@ +#if ENABLE_FEATURE_GPT_LABEL +/* + * Copyright (C) 2010 Kevin Cernekee + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +#define GPT_MAGIC 0x5452415020494645ULL +enum { + LEGACY_GPT_TYPE = 0xee, + GPT_MAX_PARTS = 256, + GPT_MAX_PART_ENTRY_LEN = 4096, + GUID_LEN = 16, +}; + +typedef struct { + uint64_t magic; + uint32_t revision; + uint32_t hdr_size; + uint32_t hdr_crc32; + uint32_t reserved; + uint64_t current_lba; + uint64_t backup_lba; + uint64_t first_usable_lba; + uint64_t last_usable_lba; + uint8_t disk_guid[GUID_LEN]; + uint64_t first_part_lba; + uint32_t n_parts; + uint32_t part_entry_len; + uint32_t part_array_crc32; +} gpt_header; + +typedef struct { + uint8_t type_guid[GUID_LEN]; + uint8_t part_guid[GUID_LEN]; + uint64_t lba_start; + uint64_t lba_end; + uint64_t flags; + uint16_t name[36]; +} gpt_partition; + +static gpt_header *gpt_hdr; + +static char *part_array; +static unsigned int n_parts; +static unsigned int part_array_len; +static unsigned int part_entry_len; + +static uint32_t *crc32_table; + +static inline gpt_partition * +gpt_part(int i) +{ + if (i >= n_parts) { + return NULL; + } + return (gpt_partition *)&part_array[i * part_entry_len]; +} + +/* TODO: move to libbb */ +static uint32_t +gpt_crc32(void *buf, int len) +{ + uint32_t crc = 0xffffffff; + + for (; len > 0; len--, buf++) { + crc = crc32_table[(crc ^ *((char *)buf)) & 0xff] ^ (crc >> 8); + } + return crc ^ 0xffffffff; +} + +static void +gpt_print_guid(uint8_t *buf) +{ + printf( + "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", + buf[3], buf[2], buf[1], buf[0], + buf[5], buf[4], + buf[7], buf[6], + buf[8], buf[9], + buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]); +} + +/* TODO: real unicode support */ +static void +gpt_print_wide(uint16_t *s, int max_len) +{ + int i = 0; + + while (i < max_len) { + if (*s == 0) + return; + fputc(*s, stdout); + s++; + } +} + +static void +gpt_list_table(int xtra UNUSED_PARAM) +{ + int i; + char numstr6[6]; + + numstr6[5] = '\0'; + + smart_ulltoa5(total_number_of_sectors, numstr6, " KMGTPEZY"); + printf("Disk %s: %llu sectors, %s\n", disk_device, + (unsigned long long)total_number_of_sectors, + numstr6); + printf("Logical sector size: %u\n", sector_size); + printf("Disk identifier (GUID): "); + gpt_print_guid(gpt_hdr->disk_guid); + printf("\nPartition table holds up to %u entries\n", + (int)SWAP_LE32(gpt_hdr->n_parts)); + printf("First usable sector is %llu, last usable sector is %llu\n\n", + (unsigned long long)SWAP_LE64(gpt_hdr->first_usable_lba), + (unsigned long long)SWAP_LE64(gpt_hdr->last_usable_lba)); + + printf("Number Start (sector) End (sector) Size Code Name\n"); + for (i = 0; i < n_parts; i++) { + gpt_partition *p = gpt_part(i); + if (p->lba_start) { + smart_ulltoa5(1 + SWAP_LE64(p->lba_end) - SWAP_LE64(p->lba_start), + numstr6, " KMGTPEZY"); + printf("%4u %15llu %15llu %11s %04x ", + i + 1, + (unsigned long long)SWAP_LE64(p->lba_start), + (unsigned long long)SWAP_LE64(p->lba_end), + numstr6, + 0x0700 /* FIXME */); + gpt_print_wide(p->name, 18); + printf("\n"); + } + } +} + +static int +check_gpt_label(void) +{ + struct partition *first = pt_offset(MBRbuffer, 0); + struct pte pe; + uint32_t crc; + + /* LBA 0 contains the legacy MBR */ + + if (!valid_part_table_flag(MBRbuffer) + || first->sys_ind != LEGACY_GPT_TYPE + ) { + current_label_type = 0; + return 0; + } + + /* LBA 1 contains the GPT header */ + + read_pte(&pe, 1); + gpt_hdr = (void *)pe.sectorbuffer; + + if (gpt_hdr->magic != SWAP_LE64(GPT_MAGIC)) { + current_label_type = 0; + return 0; + } + + if (!crc32_table) { + crc32_table = crc32_filltable(NULL, 0); + } + + crc = SWAP_LE32(gpt_hdr->hdr_crc32); + gpt_hdr->hdr_crc32 = 0; + if (gpt_crc32(gpt_hdr, SWAP_LE32(gpt_hdr->hdr_size)) != crc) { + /* FIXME: read the backup table */ + puts("\nwarning: GPT header CRC is invalid\n"); + } + + n_parts = SWAP_LE32(gpt_hdr->n_parts); + part_entry_len = SWAP_LE32(gpt_hdr->part_entry_len); + if (n_parts > GPT_MAX_PARTS + || part_entry_len > GPT_MAX_PART_ENTRY_LEN + || SWAP_LE32(gpt_hdr->hdr_size) > sector_size + ) { + puts("\nwarning: unable to parse GPT disklabel\n"); + current_label_type = 0; + return 0; + } + + part_array_len = n_parts * part_entry_len; + part_array = xmalloc(part_array_len); + seek_sector(SWAP_LE64(gpt_hdr->first_part_lba)); + if (full_read(dev_fd, part_array, part_array_len) != part_array_len) { + fdisk_fatal(unable_to_read); + } + + if (gpt_crc32(part_array, part_array_len) != gpt_hdr->part_array_crc32) { + /* FIXME: read the backup table */ + puts("\nwarning: GPT array CRC is invalid\n"); + } + + puts("Found valid GPT with protective MBR; using GPT\n"); + + current_label_type = LABEL_GPT; + return 1; +} + +#endif /* GPT_LABEL */ -- cgit v1.2.3-55-g6feb From b507cc3aceda26eff851230223a62c6fb471573c Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Mon, 25 Oct 2010 03:44:34 +0200 Subject: powertop: new applet Signed-off-by: Marek Polacek Signed-off-by: Denys Vlasenko --- libbb/Config.src | 11 + procps/powertop.c | 886 ++++++++++++++++++++++++++++++++++++++++++++++++++ util-linux/Config.src | 11 - 3 files changed, 897 insertions(+), 11 deletions(-) create mode 100644 procps/powertop.c (limited to 'libbb') diff --git a/libbb/Config.src b/libbb/Config.src index 74dc9c549..f6c7a11ea 100644 --- a/libbb/Config.src +++ b/libbb/Config.src @@ -43,6 +43,17 @@ config FEATURE_ETC_NETWORKS a rarely used feature which allows you to use names instead of IP/mask pairs in route command. +config FEATURE_USE_TERMIOS + bool "Use termios to manipulate the screen" + default y + depends on MORE || TOP || POWERTOP + help + This option allows utilities such as 'more' and 'top' to determine + the size of the screen. If you leave this disabled, your utilities + that display things on the screen will be especially primitive and + will be unable to determine the current screen size, and will be + unable to move the cursor. + config FEATURE_EDITING bool "Command line editing" default y diff --git a/procps/powertop.c b/procps/powertop.c new file mode 100644 index 000000000..f35aa5c0a --- /dev/null +++ b/procps/powertop.c @@ -0,0 +1,886 @@ +/* vi: set sw=4 ts=4: */ +/* + * A mini 'powertop' utility: + * Analyze power consumption on Intel-based laptops. + * Based on powertop 1.11. + * + * Copyright (C) 2010 Marek Polacek + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +//applet:IF_POWERTOP(APPLET(powertop, _BB_DIR_BIN, _BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_POWERTOP) += powertop.o + +//config:config POWERTOP +//config: bool "powertop" +//config: default y +//config: help +//config: Analyze power consumption on Intel-based laptops + +#include "libbb.h" + +//#define debug(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__) +#define debug(fmt, ...) ((void)0) + +// XXX This should not be here +#define ENABLE_FEATURE_POWERTOP_PROCIRQ 1 + +#define DEFAULT_SLEEP 10 +#define DEFAULT_SLEEP_STR "10" + +/* Frequency of the ACPI timer */ +#define FREQ_ACPI 3579.545 +#define FREQ_ACPI_1000 3579545 + +/* Max filename length of entry in /sys/devices subsystem */ +#define BIG_SYSNAME_LEN 16 + +typedef unsigned long long ullong; + +struct line { + char *string; + int count; + int disk_count; +}; + +#if ENABLE_FEATURE_POWERTOP_PROCIRQ +#define IRQCOUNT 40 + +struct irqdata { + int active; + int number; + ullong count; + char irq_desc[32]; +}; +#endif + +struct globals { + bool timer_list_read; + smallint nostats; + int headline; + int nlines; + int linesize; + int maxcstate; +#if ENABLE_FEATURE_POWERTOP_PROCIRQ + int total_interrupt; + int interrupt_0; + int percpu_hpet_start; + int percpu_hpet_end; + struct irqdata interrupts[IRQCOUNT]; +#endif + unsigned total_cpus; + ullong start_usage[8]; + ullong last_usage[8]; + ullong start_duration[8]; + ullong last_duration[8]; + char cstate_names[8][16]; + struct line *lines; +#if ENABLE_FEATURE_USE_TERMIOS + struct termios init_settings; +#endif +}; +#define G (*ptr_to_globals) +#define INIT_G() do { \ + SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ +} while (0) + +#if ENABLE_FEATURE_USE_TERMIOS +static void reset_term(void) +{ + tcsetattr_stdin_TCSANOW(&G.init_settings); +} + +static void sig_handler(int signo UNUSED_PARAM) +{ + reset_term(); + exit(EXIT_FAILURE); +} +#endif + +static int write_str_to_file(const char *fname, const char *str) +{ + FILE *fp = fopen_for_write(fname); + if (!fp) + return 1; + fputs(str, fp); + fclose(fp); + return 0; +} + +/* Make it more readable */ +#define start_timer() write_str_to_file("/proc/timer_stats", "1\n") +#define stop_timer() write_str_to_file("/proc/timer_stats", "0\n") + +static void NOINLINE clear_lines(void) +{ + int i; + + for (i = 0; i < G.headline; i++) + free(G.lines[i].string); + free(G.lines); + G.headline = G.linesize = 0; + G.lines = NULL; +} + +static void count_lines(void) +{ + int i; + + for (i = 0; i < G.headline; i++) + G.nlines += G.lines[i].count; +} + +static int line_compare(const void *p1, const void *p2) +{ + const struct line *a = p1; + const struct line *b = p2; + + return (b->count + 50 * b->disk_count) - (a->count + 50 * a->disk_count); +} + +static void do_sort(void) +{ + qsort(G.lines, G.headline, sizeof(struct line), line_compare); +} + +/* + * Save C-state names, usage and duration. Also get maxcstate. + * Reads data from /proc. + */ +static void read_data(ullong *usage, ullong *duration) +{ + DIR *dir; + struct dirent *d; + + dir = opendir("/proc/acpi/processor"); + if (!dir) + return; + + while ((d = readdir(dir)) != NULL) { + FILE *fp; + char buf[192]; + int level = 0; + int len; + + len = strlen(d->d_name); + if (len < 3 || len > BIG_SYSNAME_LEN) + continue; + + sprintf(buf, "/proc/acpi/processor/%s/power", d->d_name); + fp = fopen_for_read(buf); + if (!fp) + continue; + + while (fgets(buf, sizeof(buf), fp)) { + char *p; + + /* Get usage */ + p = strstr(buf, "age["); + if (!p) + continue; + p += 4; + usage[level] += bb_strtoull(p, NULL, 10) + 1; + + /* Get duration */ + p = strstr(buf, "ation["); + if (!p) + continue; + p += 6; + duration[level] += bb_strtoull(p, NULL, 10); + + /* Increment level */ + level++; + + /* Also update maxcstate */ + if (level > G.maxcstate) + G.maxcstate = level; + } + fclose(fp); + } + closedir(dir); +} + +/* Add line and/or update count */ +static void push_line(const char *string, int count) +{ + int i; + + if (!string) + return; + + /* Loop through entries */ + for (i = 0; i < G.headline; i++) { + if (strcmp(string, G.lines[i].string) == 0) { + /* It's already there, only update count */ + G.lines[i].count += count; + return; + } + } + + G.lines = xrealloc_vector(G.lines, 1, G.headline); + + G.lines[G.headline].string = xstrdup(string); + G.lines[G.headline].count = count; + G.lines[G.headline].disk_count = 0; + + /* We added a line */ + G.headline++; +} + +#if ENABLE_FEATURE_POWERTOP_PROCIRQ +static int percpu_hpet_timer(const char *name) +{ + char *p; + long hpet_chan; + + /* This is done once */ + if (!G.timer_list_read) { + FILE *fp; + char buf[80]; + + G.timer_list_read = true; + fp = fopen_for_read("/proc/timer_list"); + if (!fp) + return 0; + + while (fgets(buf, sizeof(buf), fp)) { + p = strstr(buf, "Clock Event Device: hpet"); + if (!p) + continue; + p += sizeof("Clock Event Device: hpet")-1; + if (!isdigit(p[0])) + continue; + hpet_chan = xatoi_positive(p); + if (hpet_chan < G.percpu_hpet_start) + G.percpu_hpet_start = hpet_chan; + if (hpet_chan > G.percpu_hpet_end) + G.percpu_hpet_end = hpet_chan; + } + fclose(fp); + } + + p = strstr(name, "hpet"); + if (!p) + return 0; + + p += 4; + if (!isdigit(p[0])) + return 0; + + hpet_chan = xatoi_positive(p); + if (G.percpu_hpet_start <= hpet_chan && hpet_chan <= G.percpu_hpet_end) + return 1; + + return 0; +} + +static int update_irq(int irq, ullong count) +{ + int unused = IRQCOUNT; + int i; + + for (i = 0; i < IRQCOUNT; i++) { + if (G.interrupts[i].active && G.interrupts[i].number == irq) { + ullong old; + old = G.interrupts[i].count; + G.interrupts[i].count = count; + return count - old; + } + if (!G.interrupts[i].active && unused > i) + unused = i; + } + + G.interrupts[unused].active = 1; + G.interrupts[unused].count = count; + G.interrupts[unused].number = irq; + + return count; +} + +/* + * Read /proc/interrupts, save IRQ counts and IRQ description. + */ +static void do_proc_irq(void) +{ + FILE *fp; + char buf[128]; + + /* Reset values */ + G.interrupt_0 = 0; + G.total_interrupt = 0; + + fp = xfopen_for_read("/proc/interrupts"); + while (fgets(buf, sizeof(buf), fp)) { + char irq_desc[sizeof(" : ") + sizeof(buf)]; + char *p; + const char *name; + int nr = -1; + ullong count; + ullong delta; + int special; + + /* Skip header */ + p = strchr(buf, ':'); + if (!p) + continue; + /* 0: 143646045 153901007 IO-APIC-edge timer + * ^ + */ + /* Deal with non-maskable interrupts -- make up fake numbers */ + special = 0; + if (buf[0] != ' ' && !isdigit(buf[0])) { + if (strncmp(buf, "NMI:", 4) == 0) + nr = 20000; + if (strncmp(buf, "RES:", 4) == 0) + nr = 20001; + if (strncmp(buf, "CAL:", 4) == 0) + nr = 20002; + if (strncmp(buf, "TLB:", 4) == 0) + nr = 20003; + if (strncmp(buf, "TRM:", 4) == 0) + nr = 20004; + if (strncmp(buf, "THR:", 4) == 0) + nr = 20005; + if (strncmp(buf, "SPU:", 4) == 0) + nr = 20006; + special = 1; + } else { + /* bb_strtou don't eat leading spaces, using strtoul */ + nr = strtoul(buf, NULL, 10); /* xato*() wouldn't work */ + } + if (nr == -1) + continue; + + p++; + /* 0: 143646045 153901007 IO-APIC-edge timer + * ^ + */ + /* Count sum of the IRQs */ + count = 0; + while (1) { + char *tmp; + p = skip_whitespace(p); + if (!isdigit(*p)) + break; + count += bb_strtoull(p, &tmp, 10); + p = tmp; + } + /* 0: 143646045 153901007 IO-APIC-edge timer + * NMI: 1 2 Non-maskable interrupts + * ^ + */ + if (!special) { + /* Skip to the interrupt name, e.g. 'timer' */ + p = strchr(p, ' '); + if (!p) + continue; + p = skip_whitespace(p); + } + + name = p; + strchrnul(name, '\n')[0] = '\0'; + /* Save description of the interrupt */ + if (special) + sprintf(irq_desc, " : %s", name); + else + sprintf(irq_desc, " : %s", name); + + delta = update_irq(nr, count); + + /* Skip per CPU timer interrupts */ + if (percpu_hpet_timer(name)) + delta = 0; + if (nr > 0 && delta > 0) + push_line(irq_desc, delta); + if (!nr) + G.interrupt_0 = delta; + else + G.total_interrupt += delta; + } + + fclose(fp); +} +#endif /* ENABLE_FEATURE_POWERTOP_PROCIRQ */ + +#ifdef __i386__ +/* + * Get information about CPU using CPUID opcode. + */ +static void cpuid(unsigned int *eax, unsigned int *ebx, unsigned int *ecx, + unsigned int *edx) +{ + /* EAX value specifies what information to return */ + __asm__( + " pushl %%ebx\n" /* Save EBX */ + " cpuid\n" + " movl %%ebx, %1\n" /* Save content of EBX */ + " popl %%ebx\n" /* Restore EBX */ + : "=a"(*eax), /* Output */ + "=r"(*ebx), + "=c"(*ecx), + "=d"(*edx) + : "0"(*eax), /* Input */ + "1"(*ebx), + "2"(*ecx), + "3"(*edx) + /* No clobbered registers */ + ); +} +#endif + +static void NOINLINE print_intel_cstates(void) +{ +#ifdef __i386__ + int bios_table[8] = { 0 }; + int nbios = 0; + DIR *cpudir; + struct dirent *d; + int i; + unsigned eax, ebx, ecx, edx; + + cpudir = opendir("/sys/devices/system/cpu"); + if (!cpudir) + return; + + /* Loop over cpuN entries */ + while ((d = readdir(cpudir)) != NULL) { + DIR *dir; + int len; + char fname[sizeof("/sys/devices/system/cpu//cpuidle//desc") + 2*BIG_SYSNAME_LEN]; + + len = strlen(d->d_name); + if (len < 3 || len > BIG_SYSNAME_LEN) + continue; + + if (!isdigit(d->d_name[3])) + continue; + + len = sprintf(fname, "/sys/devices/system/cpu/%s/cpuidle", d->d_name); + dir = opendir(fname); + if (!dir) + continue; + + /* + * Every C-state has its own stateN directory, that + * contains a `time' and a `usage' file. + */ + while ((d = readdir(dir)) != NULL) { + FILE *fp; + char buf[64]; + int n; + + n = strlen(d->d_name); + if (n < 3 || n > BIG_SYSNAME_LEN) + continue; + + sprintf(fname + len, "/%s/desc", d->d_name); + fp = fopen_for_read(fname); + if (fp) { + char *p = fgets(buf, sizeof(buf), fp); + fclose(fp); + if (!p) + break; + p = strstr(p, "MWAIT "); + if (p) { + int pos; + p += sizeof("MWAIT ") - 1; + pos = (bb_strtoull(p, NULL, 16) >> 4) + 1; + if (pos >= ARRAY_SIZE(bios_table)) + continue; + bios_table[pos]++; + nbios++; + } + } + } + closedir(dir); + } + closedir(cpudir); + + if (!nbios) + return; + + eax = 5; + ebx = ecx = edx = 0; + cpuid(&eax, &ebx, &ecx, &edx); + if (!edx || !(ecx & 1)) + return; + + printf("Your CPU supports the following C-states: "); + i = 0; + while (edx) { + if (edx & 7) + printf("C%u ", i); + edx >>= 4; + i++; + } + bb_putchar('\n'); + + /* Print BIOS C-States */ + printf("Your BIOS reports the following C-states: "); + for (i = 0; i < 8; i++) + if (bios_table[i]) + printf("C%u ", i); + + bb_putchar('\n'); +#endif +} + +static void print_header(void) +{ + printf( + /* Clear the screen */ + "\033[H\033[J" + /* Print the header */ + "\033[7m%.*s\033[0m", 79, "PowerTOP (C) 2007 Intel Corporation\n" + ); +} + +static void show_cstates(char cstate_lines[][64]) +{ + int i; + + for (i = 0; i < 10; i++) + if ((cstate_lines[i][0])) + printf("%s", cstate_lines[i]); +} + +static void show_timerstats(int nostats) +{ + unsigned lines; + + /* Get terminal height */ + get_terminal_width_height(STDOUT_FILENO, NULL, &lines); + + /* We don't have whole terminal just for timerstats */ + lines -= 12; + + if (!nostats) { + int i, n = 0; + + puts("\nTop causes for wakeups:"); + for (i = 0; i < G.headline; i++) { + if ((G.lines[i].count > 0 || G.lines[i].disk_count > 0) + && n++ < lines + ) { + char c = ' '; + if (G.lines[i].disk_count) + c = 'D'; + printf(" %5.1f%% (%5.1f)%c %s\n", + G.lines[i].count * 100.0 / G.nlines, + G.lines[i].count * 1.0 / DEFAULT_SLEEP, c, + G.lines[i].string); + } + } + } else { + bb_putchar('\n'); + bb_error_msg("no stats available; run as root or" + " enable the cpufreq_stats module"); + } +} + +//usage:#define powertop_trivial_usage +//usage: "" +//usage:#define powertop_full_usage "\n\n" +//usage: "Analyze power consumption on Intel-based laptops\n" + +int powertop_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv) +{ + ullong cur_usage[8]; + ullong cur_duration[8]; + char cstate_lines[12][64]; + char buf[128]; +#if ENABLE_FEATURE_USE_TERMIOS + struct termios new_settings; + struct pollfd pfd[1]; + + pfd[0].fd = 0; + pfd[0].events = POLLIN; +#endif + + INIT_G(); + +#if ENABLE_FEATURE_POWERTOP_PROCIRQ + G.percpu_hpet_start = INT_MAX; + G.percpu_hpet_end = INT_MIN; +#endif + + /* Print warning when we don't have superuser privileges */ + if (geteuid() != 0) + bb_error_msg("run as root to collect enough information"); + +#if ENABLE_FEATURE_USE_TERMIOS + /* So we don't forget to reset term settings */ + atexit(reset_term); +#endif + + /* Get number of CPUs */ + G.total_cpus = get_cpu_count(); + + printf("Collecting data for "DEFAULT_SLEEP_STR" seconds\n"); + +#if ENABLE_FEATURE_USE_TERMIOS + tcgetattr(0, (void *)&G.init_settings); + memcpy(&new_settings, &G.init_settings, sizeof(new_settings)); + + /* Turn on unbuffered input, turn off echoing */ + new_settings.c_lflag &= ~(ISIG | ICANON | ECHO | ECHONL); + + bb_signals(BB_FATAL_SIGS, sig_handler); + tcsetattr_stdin_TCSANOW(&new_settings); +#endif + +#if ENABLE_FEATURE_POWERTOP_PROCIRQ + /* Collect initial data */ + do_proc_irq(); + do_proc_irq(); +#endif + + /* Read initial usage and duration */ + read_data(&G.start_usage[0], &G.start_duration[0]); + + /* Copy them to "last" */ + memcpy(G.last_usage, G.start_usage, sizeof(G.last_usage)); + memcpy(G.last_duration, G.start_duration, sizeof(G.last_duration)); + + /* Display C-states */ + print_intel_cstates(); + + if (stop_timer()) + G.nostats = 1; + + /* The main loop */ + for (;;) { + double maxsleep = 0.0; + ullong totalticks, totalevents; + int i; + FILE *fp; + double newticks; + + if (start_timer()) + G.nostats = 1; + +#if !ENABLE_FEATURE_USE_TERMIOS + sleep(DEFAULT_SLEEP); +#else + if (safe_poll(pfd, 1, DEFAULT_SLEEP * 1000) > 0) { + unsigned char c; + if (safe_read(STDIN_FILENO, &c, 1) != 1) + break; /* EOF/error */ + if (c == G.init_settings.c_cc[VINTR]) + break; /* ^C */ + if ((c | 0x20) == 'q') + break; + } +#endif + + if (stop_timer()) + G.nostats = 1; + + clear_lines(); +#if ENABLE_FEATURE_POWERTOP_PROCIRQ + do_proc_irq(); +#endif + + /* Clear the stats */ + memset(cur_duration, 0, sizeof(cur_duration)); + memset(cur_usage, 0, sizeof(cur_usage)); + + /* Read them */ + read_data(&cur_usage[0], &cur_duration[0]); + + totalticks = totalevents = 0; + + /* Count totalticks and totalevents */ + for (i = 0; i < 8; i++) { + if (cur_usage[i]) { + totalticks += cur_duration[i] - G.last_duration[i]; + totalevents += cur_usage[i] - G.last_usage[i]; + } + } + + /* Show title bar */ + print_header(); + + /* Clear C-state lines */ + memset(&cstate_lines, 0, sizeof(cstate_lines)); + + if (totalevents == 0 && G.maxcstate <= 1) { + /* This should not happen */ + sprintf(cstate_lines[5], "< Detailed C-state information is not " + "available.>\n"); + } else { + double slept; + double percentage; + + newticks = G.total_cpus * DEFAULT_SLEEP * FREQ_ACPI_1000 - totalticks; + + /* Handle rounding errors: do not display negative values */ + if (newticks < 0) + newticks = 0; + + sprintf(cstate_lines[0], "Cn\t Avg residency\n"); + percentage = newticks * 100.0 / (G.total_cpus * DEFAULT_SLEEP * FREQ_ACPI_1000); + sprintf(cstate_lines[1], "C0 (cpu running) (%4.1f%%)\n", + percentage); + + /* Compute values for individual C-states */ + for (i = 0; i < 8; i++) { + if (cur_usage[i]) { + slept = (cur_duration[i] - G.last_duration[i]) + / (cur_usage[i] - G.last_usage[i] + 0.1) / FREQ_ACPI; + percentage = (cur_duration[i] - G.last_duration[i]) * 100 + / (G.total_cpus * DEFAULT_SLEEP * FREQ_ACPI_1000); + + if (!G.cstate_names[i][0]) + sprintf(G.cstate_names[i], "C%u", i + 1); + sprintf(cstate_lines[i + 2], "%s\t%5.1fms (%4.1f%%)\n", + G.cstate_names[i], slept, percentage); + if (maxsleep < slept) + maxsleep = slept; + } + } + } + + /* Display C-states */ + show_cstates(cstate_lines); + + /* Do timer_stats info */ + buf[0] = '\0'; + totalticks = 0; + + fp = NULL; + if (!G.nostats) + fp = fopen_for_read("/proc/timer_stats"); + if (fp) { + while (fgets(buf, sizeof(buf), fp)) { + const char *count, *process, *func; + char line[512]; + int cnt = 0; + bool defferable = false; + char *p; + int j = 0; + +/* Find char ' ', then eat remaining spaces */ +#define ADVANCE(p) do { \ + (p) = strchr((p), ' '); \ + if (!(p)) \ + continue; \ + *(p) = '\0'; \ + (p)++; \ + (p) = skip_whitespace(p); \ +} while (0) + + if (strstr(buf, "total events")) + break; + + while (isspace(buf[j])) + j++; + + count = &buf[j]; + p = (char *)count; + + /* Skip PID */ + p = strchr(p, ','); + if (!p) + continue; + *p = '\0'; + p++; + + p = skip_whitespace(p); + + /* Get process */ + ADVANCE(p); + process = p; + + /* Get function */ + ADVANCE(p); + func = p; + + if (strcmp(process, "swapper") == 0 + && strcmp(func, "hrtimer_start_range_ns (tick_sched_timer)\n") == 0 + ) { + process = "[kernel scheduler]"; + func = "Load balancing tick"; + } + + if (strcmp(process, "insmod") == 0) + process = "[kernel module]"; + if (strcmp(process, "modprobe") == 0) + process = "[kernel module]"; + if (strcmp(process, "swapper") == 0) + process = "[kernel core]"; + + p = strchr(p, '\n'); + + if (strncmp(func, "tick_nohz_", 10) == 0) + continue; + if (strncmp(func, "tick_setup_sched_timer", 20) == 0) + continue; + if (strcmp(process, "powertop") == 0) + continue; + + if (p) + *p = '\0'; + + cnt = bb_strtoull(count, &p, 10); + while (*p != 0) { + if (*p++ == 'D') + defferable = true; + } + if (defferable) + continue; + + if (strchr(process, '[')) + sprintf(line, "%s %s", process, func); + else + sprintf(line, "%s", process); + push_line(line, cnt); + } + fclose(fp); + } + +#if ENABLE_FEATURE_POWERTOP_PROCIRQ + if (strstr(buf, "total events")) { + int n = bb_strtoull(buf, NULL, 10) / G.total_cpus; + + if (totalevents == 0) { + /* No C-state info available, use timerstats */ + totalevents = n * G.total_cpus + G.total_interrupt; + if (n < 0) + totalevents += G.interrupt_0 - n; + } + if (n > 0 && n < G.interrupt_0) + push_line("[extra timer interrupt]", G.interrupt_0 - n); + } +#endif + if (totalevents) + printf("\n\033[1mWakeups-from-idle per second : %4.1f\tinterval:" + "%ds\n\033[0m", + (double)totalevents / DEFAULT_SLEEP / G.total_cpus, DEFAULT_SLEEP); + + count_lines(); + do_sort(); + + show_timerstats(G.nostats); + + fflush(stdout); + + /* Clear the stats */ + memset(cur_duration, 0, sizeof(cur_duration)); + memset(cur_usage, 0, sizeof(cur_usage)); + + /* Get new values */ + read_data(&cur_usage[0], &cur_duration[0]); + + /* Save them */ + memcpy(G.last_usage, cur_usage, sizeof(G.last_usage)); + memcpy(G.last_duration, cur_duration, sizeof(G.last_duration)); + } /* for (;;) */ + + bb_putchar('\n'); + + return EXIT_SUCCESS; +} diff --git a/util-linux/Config.src b/util-linux/Config.src index 19b309e57..c71b4de38 100644 --- a/util-linux/Config.src +++ b/util-linux/Config.src @@ -486,17 +486,6 @@ config MORE you will probably find this utility very helpful. If you don't have any need to reading text files, you can leave this disabled. -config FEATURE_USE_TERMIOS - bool "Use termios to manipulate the screen" - default y - depends on MORE || TOP - help - This option allows utilities such as 'more' and 'top' to determine - the size of the screen. If you leave this disabled, your utilities - that display things on the screen will be especially primitive and - will be unable to determine the current screen size, and will be - unable to move the cursor. - config MOUNT bool "mount" default y -- cgit v1.2.3-55-g6feb From a2d27a19197cc5ed787dc2439df0cae58053ea2c Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 25 Oct 2010 12:14:21 +0200 Subject: libbb/process_escape_sequence.c: fix recently broken handling of \\ Signed-off-by: Denys Vlasenko --- libbb/process_escape_sequence.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'libbb') diff --git a/libbb/process_escape_sequence.c b/libbb/process_escape_sequence.c index 7b1d97f9c..346ecfa1e 100644 --- a/libbb/process_escape_sequence.c +++ b/libbb/process_escape_sequence.c @@ -75,8 +75,8 @@ char FAST_FUNC bb_process_escape_sequence(const char **ptr) * Manpages tend to support coreutils way. * Update: coreutils added support for \e on 28 Oct 2009. */ static const char charmap[] ALIGN1 = { - 'a', 'b', 'e', 'f', 'n', 'r', 't', 'v', '\\', - '\a', '\b', 27, '\f', '\n', '\r', '\t', '\v', '\\', + 'a', 'b', 'e', 'f', 'n', 'r', 't', 'v', '\\', '\0', + '\a', '\b', 27, '\f', '\n', '\r', '\t', '\v', '\\', '\\', }; const char *p = charmap; do { @@ -84,8 +84,8 @@ char FAST_FUNC bb_process_escape_sequence(const char **ptr) q++; break; } - } while (*++p != '\\'); - /* p points to found escape char or '\', + } while (*++p != '\0'); + /* p points to found escape char or NUL, * advance it and find what it translates to. * Note that \NUL and unrecognized sequence \z return '\' * and leave ptr pointing to NUL or z. */ -- cgit v1.2.3-55-g6feb From 9ce642f9746dfc29d119d0680b769677e3ea6da6 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 27 Oct 2010 15:26:45 +0200 Subject: libbb: introduce and use common crc32 routine function old new delta crc32_block_endian1 - 37 +37 crc32_block_endian0 - 34 +34 global_crc32_table - 8 +8 file_read 82 87 +5 gzip_main 211 214 +3 xz_crc32 40 35 -5 crc32_table 8 - -8 calculate_gunzip_crc 54 34 -20 lzo_crc32 54 25 -29 cksum_main 298 211 -87 ------------------------------------------------------------------------------ (add/remove: 3/1 grow/shrink: 2/4 up/down: 87/-149) Total: -62 bytes Signed-off-by: Denys Vlasenko --- archival/gzip.c | 16 +++++----------- archival/libunarchive/decompress_unxz.c | 14 +++----------- archival/libunarchive/decompress_unzip.c | 5 +---- archival/lzop.c | 22 ++++++---------------- coreutils/cksum.c | 7 +------ include/libbb.h | 7 +++---- libbb/crc32.c | 24 ++++++++++++++++++++++++ miscutils/flash_eraseall.c | 14 +++----------- util-linux/fdisk_gpt.c | 13 +++---------- 9 files changed, 49 insertions(+), 73 deletions(-) (limited to 'libbb') diff --git a/archival/gzip.c b/archival/gzip.c index 32528d96b..4d399063d 100644 --- a/archival/gzip.c +++ b/archival/gzip.c @@ -340,7 +340,7 @@ struct globals { ulg bits_sent; /* bit length of the compressed data */ #endif - uint32_t *crc_32_tab; + /*uint32_t *crc_32_tab;*/ uint32_t crc; /* shift register contents */ }; @@ -393,15 +393,9 @@ static void put_32bit(ulg n) * pointer, then initialize the crc shift register contents instead. * Return the current crc in either case. */ -static uint32_t updcrc(uch * s, unsigned n) +static void updcrc(uch * s, unsigned n) { - uint32_t c = G1.crc; - while (n) { - c = G1.crc_32_tab[(uch)(c ^ *s++)] ^ (c >> 8); - n--; - } - G1.crc = c; - return c; + G1.crc = crc32_block_endian0(G1.crc, s, n, global_crc32_table /*G1.crc_32_tab*/); } @@ -2104,8 +2098,8 @@ int gzip_main(int argc UNUSED_PARAM, char **argv) ALLOC(uch, G1.window, 2L * WSIZE); ALLOC(ush, G1.prev, 1L << BITS); - /* Initialise the CRC32 table */ - G1.crc_32_tab = crc32_filltable(NULL, 0); + /* Initialize the CRC32 table */ + global_crc32_table = crc32_filltable(NULL, 0); return bbunpack(argv, pack_gzip, append_ext, "gz"); } diff --git a/archival/libunarchive/decompress_unxz.c b/archival/libunarchive/decompress_unxz.c index faba9ca82..ca427231e 100644 --- a/archival/libunarchive/decompress_unxz.c +++ b/archival/libunarchive/decompress_unxz.c @@ -22,17 +22,9 @@ /* We use our own crc32 function */ #define XZ_INTERNAL_CRC32 0 -static uint32_t *crc32_table; static uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc) { - crc = ~crc; - - while (size != 0) { - crc = crc32_table[*buf++ ^ (crc & 0xFF)] ^ (crc >> 8); - --size; - } - - return ~crc; + return ~crc32_block_endian0(~crc, buf, size, global_crc32_table); } /* We use arch-optimized unaligned accessors */ @@ -53,8 +45,8 @@ unpack_xz_stream(int src_fd, int dst_fd) unsigned char *membuf; IF_DESKTOP(long long) int total = 0; - if (!crc32_table) - crc32_table = crc32_filltable(NULL, /*endian:*/ 0); + if (!global_crc32_table) + global_crc32_table = crc32_filltable(NULL, /*endian:*/ 0); memset(&iobuf, 0, sizeof(iobuf)); /* Preload XZ file signature */ diff --git a/archival/libunarchive/decompress_unzip.c b/archival/libunarchive/decompress_unzip.c index 20fda9d26..cb8a3d737 100644 --- a/archival/libunarchive/decompress_unzip.c +++ b/archival/libunarchive/decompress_unzip.c @@ -925,10 +925,7 @@ static int inflate_block(STATE_PARAM smallint *e) /* Two callsites, both in inflate_get_next_window */ static void calculate_gunzip_crc(STATE_PARAM_ONLY) { - unsigned n; - for (n = 0; n < gunzip_outbuf_count; n++) { - gunzip_crc = gunzip_crc_table[((int) gunzip_crc ^ (gunzip_window[n])) & 0xff] ^ (gunzip_crc >> 8); - } + gunzip_crc = crc32_block_endian0(gunzip_crc, gunzip_window, gunzip_outbuf_count, gunzip_crc_table); gunzip_bytes_out += gunzip_outbuf_count; } diff --git a/archival/lzop.c b/archival/lzop.c index c6e718ad7..acb34fe14 100644 --- a/archival/lzop.c +++ b/archival/lzop.c @@ -393,7 +393,7 @@ typedef struct header_t { } header_t; struct globals { - const uint32_t *lzo_crc32_table; + /*const uint32_t *lzo_crc32_table;*/ chksum_t chksum_in; chksum_t chksum_out; } FIX_ALIASING; @@ -468,19 +468,10 @@ lzo_adler32(uint32_t adler, const uint8_t* buf, unsigned len) static FAST_FUNC uint32_t lzo_crc32(uint32_t c, const uint8_t* buf, unsigned len) { - uint32_t crc; + //if (buf == NULL) - impossible + // return 0; - if (buf == NULL) - return 0; - - crc = ~c; - if (len != 0) do { - crc = G.lzo_crc32_table[(uint8_t)((int)crc ^ *buf)] ^ (crc >> 8); - buf += 1; - len -= 1; - } while (len > 0); - - return ~crc; + return ~crc32_block_endian0(~c, buf, len, global_crc32_table); } /**********************************************************************/ @@ -679,8 +670,7 @@ static NOINLINE smallint lzo_compress(const header_t *h) if (dst_len < src_len) { /* write checksum of compressed block */ if (h->flags & F_ADLER32_C) - write32(lzo_adler32(ADLER32_INIT_VALUE, b2, - dst_len)); + write32(lzo_adler32(ADLER32_INIT_VALUE, b2, dst_len)); if (h->flags & F_CRC32_C) write32(lzo_crc32(CRC32_INIT_VALUE, b2, dst_len)); /* write compressed block data */ @@ -1080,6 +1070,6 @@ int lzop_main(int argc UNUSED_PARAM, char **argv) if (applet_name[0] == 'u') option_mask32 |= OPT_DECOMPRESS; - G.lzo_crc32_table = crc32_filltable(NULL, 0); + global_crc32_table = crc32_filltable(NULL, 0); return bbunpack(argv, pack_lzop, make_new_name_lzop, /*unused:*/ NULL); } diff --git a/coreutils/cksum.c b/coreutils/cksum.c index 7bf383e2d..7a37e6add 100644 --- a/coreutils/cksum.c +++ b/coreutils/cksum.c @@ -18,7 +18,6 @@ int cksum_main(int argc UNUSED_PARAM, char **argv) off_t length, filesize; int bytes_read; int exit_code = EXIT_SUCCESS; - uint8_t *cp; #if ENABLE_DESKTOP getopt32(argv, ""); /* coreutils 6.9 compat */ @@ -39,11 +38,7 @@ int cksum_main(int argc UNUSED_PARAM, char **argv) #define read_buf bb_common_bufsiz1 while ((bytes_read = safe_read(fd, read_buf, sizeof(read_buf))) > 0) { - cp = (uint8_t *) read_buf; - length += bytes_read; - do { - crc = (crc << 8) ^ crc32_table[(crc >> 24) ^ *cp++]; - } while (--bytes_read); + crc = crc32_block_endian1(crc, read_buf, bytes_read, crc32_table); } close(fd); diff --git a/include/libbb.h b/include/libbb.h index d14728ed0..587a5f952 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1543,11 +1543,10 @@ void sha512_begin(sha512_ctx_t *ctx) FAST_FUNC; void sha512_hash(sha512_ctx_t *ctx, const void *buffer, size_t len) FAST_FUNC; void sha512_end(sha512_ctx_t *ctx, void *resbuf) FAST_FUNC; -/* TODO: add global crc32_table pointer and create - * LE and BE functions to calculate crc32 over given bytes. - * Currently we have about five reimplementations... - */ +extern uint32_t *global_crc32_table; uint32_t *crc32_filltable(uint32_t *tbl256, int endian) FAST_FUNC; +uint32_t crc32_block_endian1(uint32_t val, const void *buf, unsigned len, uint32_t *crc_table) FAST_FUNC; +uint32_t crc32_block_endian0(uint32_t val, const void *buf, unsigned len, uint32_t *crc_table) FAST_FUNC; typedef struct masks_labels_t { const char *labels; diff --git a/libbb/crc32.c b/libbb/crc32.c index 520b1ffb9..2cc6ea779 100644 --- a/libbb/crc32.c +++ b/libbb/crc32.c @@ -18,6 +18,8 @@ #include "libbb.h" +uint32_t *global_crc32_table; + uint32_t* FAST_FUNC crc32_filltable(uint32_t *crc_table, int endian) { uint32_t polynomial = endian ? 0x04c11db7 : 0xedb88320; @@ -40,3 +42,25 @@ uint32_t* FAST_FUNC crc32_filltable(uint32_t *crc_table, int endian) return crc_table - 256; } + +uint32_t FAST_FUNC crc32_block_endian1(uint32_t val, const void *buf, unsigned len, uint32_t *crc_table) +{ + const void *end = (uint8_t*)buf + len; + + while (buf != end) { + val = (val << 8) ^ crc_table[(val >> 24) ^ *(uint8_t*)buf]; + buf = (uint8_t*)buf + 1; + } + return val; +} + +uint32_t FAST_FUNC crc32_block_endian0(uint32_t val, const void *buf, unsigned len, uint32_t *crc_table) +{ + const void *end = (uint8_t*)buf + len; + + while (buf != end) { + val = crc_table [(uint8_t)val ^ *(uint8_t*)buf] ^ (val >> 8); + buf = (uint8_t*)buf + 1; + } + return val; +} diff --git a/miscutils/flash_eraseall.c b/miscutils/flash_eraseall.c index 53aad3d52..b832cc1dd 100644 --- a/miscutils/flash_eraseall.c +++ b/miscutils/flash_eraseall.c @@ -42,15 +42,6 @@ but mtd/jffs2-user.h is gone now (at least 2.6.31.6 does not have it anymore) #define cpu_to_je16(v) ((jint16_t){(v)}) #define cpu_to_je32(v) ((jint32_t){(v)}) -static uint32_t crc32(uint32_t val, const void *ss, int len, - uint32_t *crc32_table) -{ - const unsigned char *s = ss; - while (--len >= 0) - val = crc32_table[(val ^ *s++) & 0xff] ^ (val >> 8); - return val; -} - static void show_progress(mtd_info_t *meminfo, erase_info_t *erase) { printf("\rErasing %u Kibyte @ %x - %2u%% complete.", @@ -131,8 +122,9 @@ int flash_eraseall_main(int argc UNUSED_PARAM, char **argv) cleanmarker.totlen = cpu_to_je32(8); } - cleanmarker.hdr_crc = cpu_to_je32(crc32(0, &cleanmarker, sizeof(struct jffs2_unknown_node) - 4, - crc32_table)); + cleanmarker.hdr_crc = cpu_to_je32( + crc32_block_endian0(0, &cleanmarker, sizeof(struct jffs2_unknown_node) - 4, crc32_table) + ); } /* Don't want to destroy progress indicator by bb_error_msg's */ diff --git a/util-linux/fdisk_gpt.c b/util-linux/fdisk_gpt.c index 98803ec88..4dfb5b227 100644 --- a/util-linux/fdisk_gpt.c +++ b/util-linux/fdisk_gpt.c @@ -46,8 +46,6 @@ static unsigned int n_parts; static unsigned int part_array_len; static unsigned int part_entry_len; -static uint32_t *crc32_table; - static inline gpt_partition * gpt_part(int i) { @@ -61,12 +59,7 @@ gpt_part(int i) static uint32_t gpt_crc32(void *buf, int len) { - uint32_t crc = 0xffffffff; - - for (; len > 0; len--, buf++) { - crc = crc32_table[(crc ^ *((char *)buf)) & 0xff] ^ (crc >> 8); - } - return crc ^ 0xffffffff; + return 0xffffffff ^ crc32_block_endian0(0xffffffff, buf, len, global_crc32_table); } static void @@ -160,8 +153,8 @@ check_gpt_label(void) return 0; } - if (!crc32_table) { - crc32_table = crc32_filltable(NULL, 0); + if (!global_crc32_table) { + global_crc32_table = crc32_filltable(NULL, 0); } crc = SWAP_LE32(gpt_hdr->hdr_crc32); -- cgit v1.2.3-55-g6feb From 16cc80e9890c0409921b0463e5678649a893ae7f Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 28 Oct 2010 05:38:11 +0200 Subject: crc32: cleanups, no code changes Signed-off-by: Denys Vlasenko --- libbb/crc32.c | 2 +- util-linux/fdisk_gpt.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'libbb') diff --git a/libbb/crc32.c b/libbb/crc32.c index 2cc6ea779..c63bf0772 100644 --- a/libbb/crc32.c +++ b/libbb/crc32.c @@ -59,7 +59,7 @@ uint32_t FAST_FUNC crc32_block_endian0(uint32_t val, const void *buf, unsigned l const void *end = (uint8_t*)buf + len; while (buf != end) { - val = crc_table [(uint8_t)val ^ *(uint8_t*)buf] ^ (val >> 8); + val = crc_table[(uint8_t)val ^ *(uint8_t*)buf] ^ (val >> 8); buf = (uint8_t*)buf + 1; } return val; diff --git a/util-linux/fdisk_gpt.c b/util-linux/fdisk_gpt.c index 4dfb5b227..1ab1293de 100644 --- a/util-linux/fdisk_gpt.c +++ b/util-linux/fdisk_gpt.c @@ -55,11 +55,10 @@ gpt_part(int i) return (gpt_partition *)&part_array[i * part_entry_len]; } -/* TODO: move to libbb */ static uint32_t gpt_crc32(void *buf, int len) { - return 0xffffffff ^ crc32_block_endian0(0xffffffff, buf, len, global_crc32_table); + return ~crc32_block_endian0(0xffffffff, buf, len, global_crc32_table); } static void -- cgit v1.2.3-55-g6feb