diff --git a/busybox.h b/busybox.h index 2fc0cc7e0..101e65989 100644 --- a/busybox.h +++ b/busybox.h @@ -232,7 +232,7 @@ extern int sysinfo (struct sysinfo* info); #endif #ifdef BB_FEATURE_HUMAN_READABLE -char *format(unsigned long val, unsigned long hr); +const char *format(unsigned long val, unsigned long hr); #define KILOBYTE 1024 #define MEGABYTE (KILOBYTE*1024) #define GIGABYTE (MEGABYTE*1024) diff --git a/include/busybox.h b/include/busybox.h index 2fc0cc7e0..101e65989 100644 --- a/include/busybox.h +++ b/include/busybox.h @@ -232,7 +232,7 @@ extern int sysinfo (struct sysinfo* info); #endif #ifdef BB_FEATURE_HUMAN_READABLE -char *format(unsigned long val, unsigned long hr); +const char *format(unsigned long val, unsigned long hr); #define KILOBYTE 1024 #define MEGABYTE (KILOBYTE*1024) #define GIGABYTE (MEGABYTE*1024) diff --git a/utility.c b/utility.c index 9f0bca971..f3c184e73 100644 --- a/utility.c +++ b/utility.c @@ -51,6 +51,7 @@ #include #include #include +#include #include #include /* for uname(2) */ @@ -77,7 +78,7 @@ const char mtab_file[] = "/proc/mounts"; extern void usage(const char *usage) { - fprintf(stderr, "%s\n\nUsage: %s\n", full_version, usage); + fprintf(stderr, "%s\n\nUsage: %s\n\n", full_version, usage); exit(EXIT_FAILURE); } @@ -145,16 +146,21 @@ extern void perror_msg_and_die(const char *s, ...) extern int get_kernel_revision(void) { struct utsname name; - int major = 0, minor = 0, patch = 0; + char *s; + int i, r; if (uname(&name) == -1) { perror_msg("cannot get system information"); return (0); } - major = atoi(strtok(name.release, ".")); - minor = atoi(strtok(NULL, ".")); - patch = atoi(strtok(NULL, ".")); - return major * 65536 + minor * 256 + patch; + + s = name.release; + r = 0; + for (i=0 ; i<3 ; i++) { + r = r * 256 + atoi(strtok(s, ".")); + s = NULL; + } + return r; } #endif /* BB_INIT */ @@ -749,102 +755,100 @@ extern int create_path(const char *name, int mode) || defined (BB_MKFIFO) || defined (BB_MKNOD) || defined (BB_AR) /* [ugoa]{+|-|=}[rwxst] */ - - extern int parse_mode(const char *s, mode_t * theMode) { - mode_t andMode = + static const mode_t group_set[] = { + S_ISUID | S_IRWXU, /* u */ + S_ISGID | S_IRWXG, /* g */ + S_IRWXO, /* o */ + S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO /* a */ + }; + static const mode_t mode_set[] = { + S_IRUSR | S_IRGRP | S_IROTH, /* r */ + S_IWUSR | S_IWGRP | S_IWOTH, /* w */ + S_IXUSR | S_IXGRP | S_IXOTH, /* x */ + S_ISUID | S_ISGID, /* s */ + S_ISVTX /* t */ + }; + + static const char group_string[] = "ugoa"; + static const char mode_string[] = "rwxst"; + + const char *p; + + mode_t andMode = S_ISVTX | S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO; mode_t orMode = 0; - mode_t mode = 0; - mode_t groups = 0; + mode_t mode; + mode_t groups; char type; char c; - if (s==NULL) + if (s==NULL) { return (FALSE); + } do { - for (;;) { - switch (c = *s++) { - case '\0': - return -1; - case 'u': - groups |= S_ISUID | S_IRWXU; - continue; - case 'g': - groups |= S_ISGID | S_IRWXG; - continue; - case 'o': - groups |= S_IRWXO; - continue; - case 'a': - groups |= S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO; - continue; - case '+': + mode = 0; + groups = 0; + NEXT_GROUP: + if ((c = *s++) == '\0') { + return -1; + } + for (p=group_string ; *p ; p++) { + if (*p == c) { + groups |= group_set[(int)(p-group_string)]; + goto NEXT_GROUP; + } + } + switch (c) { case '=': + case '+': case '-': type = c; - if (groups == 0) /* The default is "all" */ - groups |= - S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO; + if (groups == 0) { /* The default is "all" */ + groups |= S_ISUID | S_ISGID | S_ISVTX + | S_IRWXU | S_IRWXG | S_IRWXO; + } break; default: - if (isdigit(c) && c >= '0' && c <= '7' && - mode == 0 && groups == 0) { + if ((c < '0') || (c > '7') || (mode | groups)) { + return (FALSE); + } else { *theMode = strtol(--s, NULL, 8); return (TRUE); - } else - return (FALSE); - } - break; + } } - while ((c = *s++) != '\0') { - switch (c) { - case ',': - break; - case 'r': - mode |= S_IRUSR | S_IRGRP | S_IROTH; - continue; - case 'w': - mode |= S_IWUSR | S_IWGRP | S_IWOTH; - continue; - case 'x': - mode |= S_IXUSR | S_IXGRP | S_IXOTH; - continue; - case 's': - mode |= S_IXGRP | S_ISUID | S_ISGID; - continue; - case 't': - mode |= 0; - continue; - default: - *theMode &= andMode; - *theMode |= orMode; - return (TRUE); + NEXT_MODE: + if (((c = *s++) != '\0') && (c != ',')) { + for (p=mode_string ; *p ; p++) { + if (*p == c) { + mode |= mode_set[(int)(p-mode_string)]; + goto NEXT_MODE; + } } - break; + break; /* We're done so break out of loop.*/ } switch (type) { - case '=': - andMode &= ~(groups); - /* fall through */ - case '+': - orMode |= mode & groups; - break; - case '-': - andMode &= ~(mode & groups); - orMode &= andMode; - break; + case '=': + andMode &= ~(groups); /* Now fall through. */ + case '+': + orMode |= mode & groups; + break; + case '-': + andMode &= ~(mode & groups); + orMode &= ~(mode & groups); + break; } } while (c == ','); + *theMode &= andMode; *theMode |= orMode; - return (TRUE); -} + return TRUE; +} #endif /* BB_CHMOD_CHOWN_CHGRP || BB_MKDIR || BB_MKFIFO || BB_MKNOD */ @@ -1575,48 +1579,43 @@ extern int print_file_by_name(char *filename) #if defined BB_ECHO || defined BB_SH || defined BB_TR char process_escape_sequence(char **ptr) { - char c; + static const char charmap[] = { + 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', 0, + '\a', '\b', '\f', '\n', '\r', '\t', '\v', '\\', '\\' }; - switch (c = *(*ptr)++) { - case 'a': - c = '\a'; - break; - case 'b': - c = '\b'; - break; - case 'f': - c = '\f'; - break; - case 'n': - c = '\n'; - break; - case 'r': - c = '\r'; - break; - case 't': - c = '\t'; - break; - case 'v': - c = '\v'; - break; - case '\\': - c = '\\'; - break; - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - c -= '0'; - if ('0' <= **ptr && **ptr <= '7') { - c = c * 8 + (*(*ptr)++ - '0'); - if ('0' <= **ptr && **ptr <= '7') - c = c * 8 + (*(*ptr)++ - '0'); - } - break; - default: - (*ptr)--; - c = '\\'; - break; - } - return c; + const char *p; + char *q; + int num_digits; + unsigned int n; + + n = 0; + q = *ptr; + + for ( num_digits = 0 ; num_digits < 3 ; ++num_digits) { + if ((*q < '0') || (*q > '7')) { /* not a digit? */ + break; + } + n = n * 8 + (*q++ - '0'); + } + + if (num_digits == 0) { /* mnemonic escape sequence? */ + for (p=charmap ; *p ; p++) { + if (*p == *q) { + q++; + break; + } + } + n = *(p+(sizeof(charmap)/2)); + } + + /* doesn't hurt to fall through to here from mnemonic case */ + if (n > UCHAR_MAX) { /* is octal code too big for a char? */ + n /= 8; /* adjust value and */ + --q; /* back up one char */ + } + + *ptr = q; + return (char) n; } #endif @@ -1737,23 +1736,45 @@ ssize_t safe_read(int fd, void *buf, size_t count) #endif #ifdef BB_FEATURE_HUMAN_READABLE -char *format(unsigned long val, unsigned long hr) +const char *format(unsigned long val, unsigned long hr) { - static char str[10] = "\0"; + static const char strings[] = { '0', 0, 'k', 0, 'M', 0, 'G', 0 }; + static const char fmt[] = "%lu"; + static const char fmt_u[] = "%lu.%lu%s"; - if(val == 0) - return("0"); - if(hr) - snprintf(str, 9, "%ld", val/hr); - else if(val >= GIGABYTE) - snprintf(str, 9, "%.1LfG", ((long double)(val)/GIGABYTE)); - else if(val >= MEGABYTE) - snprintf(str, 9, "%.1LfM", ((long double)(val)/MEGABYTE)); - else if(val >= KILOBYTE) - snprintf(str, 9, "%.1Lfk", ((long double)(val)/KILOBYTE)); - else - snprintf(str, 9, "%ld", (val)); - return(str); + static char str[10]; + + unsigned long frac __attribute__ ((unused)); /* 'may be uninitialized' warning is ok */ + const char *u; + const char *f; + +#if 1 + if(val == 0) { /* This may be omitted to reduce size */ + return strings; /* at the cost of speed. */ + } +#endif + + u = strings; + f = fmt; + if (hr) { + val /= hr; + } else { + while ((val >= KILOBYTE) && (*u != 'G')) { + f = fmt_u; + u += 2; + frac = (((val % KILOBYTE) * 10) + (KILOBYTE/2)) / KILOBYTE; + val /= KILOBYTE; + if (frac >= 10) { /* We need to round up here. */ + ++val; + frac = 0; + } + } + } + + /* If f==fmt then 'frac' and 'u' are ignored and need not be set. */ + snprintf(str, sizeof(str), f, val, frac, u); + + return str; } #endif