diff options
Diffstat (limited to '')
-rw-r--r-- | toolbox/Android.mk | 289 | ||||
-rw-r--r-- | toolbox/dynarray.h | 82 | ||||
-rw-r--r-- | toolbox/getprop.c | 50 | ||||
-rw-r--r-- | toolbox/ls.c | 588 | ||||
-rw-r--r-- | toolbox/setprop.c | 18 |
5 files changed, 1027 insertions, 0 deletions
diff --git a/toolbox/Android.mk b/toolbox/Android.mk new file mode 100644 index 000000000..c721bbd41 --- /dev/null +++ b/toolbox/Android.mk @@ -0,0 +1,289 @@ +TWRP_TOOLBOX_PATH := $(call my-dir) +LOCAL_PATH := system/core/toolbox +include $(CLEAR_VARS) + +OUR_TOOLS := \ + start \ + stop \ + +ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 23; echo $$?),0) + OUR_TOOLS += \ + getprop \ + setprop +endif + +# If busybox does not have SELinux support, provide these tools with toolbox. +# Note that RECOVERY_BUSYBOX_TOOLS will be empty if TW_USE_TOOLBOX == true. +ifeq ($(TWHAVE_SELINUX), true) + TOOLS_FOR_SELINUX := \ + ls + + ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 23; echo $$?),0) + TOOLS_FOR_SELINUX += \ + load_policy \ + getenforce \ + chcon \ + restorecon \ + runcon \ + getsebool \ + setsebool + endif + + OUR_TOOLS += $(filter-out $(RECOVERY_BUSYBOX_TOOLS), $(TOOLS_FOR_SELINUX)) + + # toolbox setenforce is used during init, so it needs to be included here + # symlink is omitted at the very end if busybox already provides this + ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 23; echo $$?),0) + OUR_TOOLS += setenforce + endif +endif + +ifeq ($(TW_USE_TOOLBOX), true) + ifeq ($(shell test $(PLATFORM_SDK_VERSION) -gt 22; echo $$?),0) + # These are the only toolbox tools in M. The rest are now in toybox. + BSD_TOOLS := \ + dd \ + du \ + + OUR_TOOLS := \ + df \ + iftop \ + ioctl \ + ionice \ + log \ + ls \ + lsof \ + mount \ + nandread \ + newfs_msdos \ + ps \ + prlimit \ + renice \ + sendevent \ + start \ + stop \ + top \ + uptime \ + watchprops \ + + else + ifneq (,$(filter $(PLATFORM_SDK_VERSION), 21 22)) + OUR_TOOLS += \ + mknod \ + nohup + BSD_TOOLS := \ + cat \ + chown \ + cp \ + dd \ + du \ + grep \ + kill \ + ln \ + mv \ + printenv \ + rm \ + rmdir \ + sleep \ + sync + else + OUR_TOOLS += \ + cat \ + chown \ + dd \ + du \ + kill \ + ln \ + mv \ + printenv \ + rm \ + rmdir \ + setconsole \ + sleep \ + sync + endif + + OUR_TOOLS += \ + chmod \ + clear \ + cmp \ + date \ + df \ + dmesg \ + getevent \ + hd \ + id \ + ifconfig \ + iftop \ + insmod \ + ioctl \ + ionice \ + log \ + lsmod \ + lsof \ + md5 \ + mkdir \ + mkswap \ + mount \ + nandread \ + netstat \ + newfs_msdos \ + notify \ + ps \ + readlink \ + renice \ + rmmod \ + route \ + schedtop \ + sendevent \ + smd \ + swapoff \ + swapon \ + top \ + touch \ + umount \ + uptime \ + vmstat \ + watchprops \ + wipe + ifneq ($(TWHAVE_SELINUX), true) + OUR_TOOLS += ls + endif + endif +endif + +ifneq (,$(filter $(PLATFORM_SDK_VERSION), 21 22)) + ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT))) + OUR_TOOLS += r + endif +endif + +LOCAL_SRC_FILES := \ + toolbox.c \ + $(patsubst %,%.c,$(OUR_TOOLS)) + +ifneq ($(wildcard system/core/toolbox/dynarray.c),) + LOCAL_SRC_FILES += dynarray.c +endif + +ifneq (,$(filter $(PLATFORM_SDK_VERSION), 21 22)) + LOCAL_SRC_FILES += \ + pwcache.c \ + upstream-netbsd/lib/libc/gen/getbsize.c \ + upstream-netbsd/lib/libc/gen/humanize_number.c \ + upstream-netbsd/lib/libc/stdlib/strsuftoll.c \ + upstream-netbsd/lib/libc/string/swab.c \ + upstream-netbsd/lib/libutil/raise_default_signal.c +endif + +ifneq (,$(filter $(PLATFORM_SDK_VERSION), 21 22 23)) + LOCAL_CFLAGS += \ + -std=gnu99 \ + -Werror -Wno-unused-parameter \ + -I$(LOCAL_PATH)/upstream-netbsd/include \ + -include bsd-compatibility.h +endif + +ifneq (,$(filter $(PLATFORM_SDK_VERSION), 21 22)) + LOCAL_C_INCLUDES += external/openssl/include +else + LOCAL_C_INCLUDES += bionic/libc/bionic +endif + +LOCAL_SHARED_LIBRARIES += libcutils + +ifneq (,$(filter $(PLATFORM_SDK_VERSION), 21 22)) + ifeq ($(TW_USE_TOOLBOX), true) + LOCAL_SHARED_LIBRARIES += libcrypto + endif +else + LOCAL_SHARED_LIBRARIES += \ + libc \ + liblog +endif + +ifeq ($(TWHAVE_SELINUX), true) + LOCAL_SHARED_LIBRARIES += libselinux +endif + +ifneq (,$(filter $(PLATFORM_SDK_VERSION), 21 22 23)) + # libusbhost is only used by lsusb, and that isn't usually included in toolbox. + # The linker strips out all the unused library code in the normal case. + LOCAL_STATIC_LIBRARIES := libusbhost + LOCAL_WHOLE_STATIC_LIBRARIES := $(patsubst %,libtoolbox_%,$(BSD_TOOLS)) +endif + +ifeq ($(shell test $(PLATFORM_SDK_VERSION) -gt 22; echo $$?),0) + # Rule to make getprop and setprop in M trees where toybox normally + # provides these tools. Toybox does not allow for easy dynamic + # configuration, so we would have to include the entire toybox binary + # which takes up more space than is necessary so long as we are still + # including busybox. + LOCAL_SRC_FILES += \ + ../../../$(TWRP_TOOLBOX_PATH)/getprop.c \ + ../../../$(TWRP_TOOLBOX_PATH)/setprop.c + OUR_TOOLS += getprop setprop + ifneq ($(TW_USE_TOOLBOX), true) + LOCAL_SRC_FILES += ../../../$(TWRP_TOOLBOX_PATH)/ls.c + endif +endif + +LOCAL_MODULE := toolbox_recovery +LOCAL_MODULE_STEM := toolbox +LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin +LOCAL_MODULE_TAGS := optional + +# Including this will define $(intermediates) below +include $(BUILD_EXECUTABLE) + +$(LOCAL_PATH)/toolbox.c: $(intermediates)/tools.h + +ifneq (,$(filter $(PLATFORM_SDK_VERSION), 21 22 23)) + ALL_TOOLS := $(BSD_TOOLS) $(OUR_TOOLS) +else + ALL_TOOLS := $(OUR_TOOLS) +endif + +TOOLS_H := $(intermediates)/tools.h +$(TOOLS_H): PRIVATE_TOOLS := $(ALL_TOOLS) +$(TOOLS_H): PRIVATE_CUSTOM_TOOL = echo "/* file generated automatically */" > $@ ; for t in $(PRIVATE_TOOLS) ; do echo "TOOL($$t)" >> $@ ; done +$(TOOLS_H): $(LOCAL_PATH)/Android.mk +$(TOOLS_H): + $(transform-generated-source) + +ifeq ($(TWHAVE_SELINUX), true) + # toolbox setenforce is used during init in non-symlink form, so it was + # required to be included as part of the suite above. if busybox already + # provides setenforce, we can omit the toolbox symlink + TEMP_TOOLS := $(filter-out $(RECOVERY_BUSYBOX_TOOLS), $(ALL_TOOLS)) + ALL_TOOLS := $(TEMP_TOOLS) +endif + +# Make /sbin/toolbox launchers for each tool +SYMLINKS := $(addprefix $(TARGET_RECOVERY_ROOT_OUT)/sbin/,$(ALL_TOOLS)) +$(SYMLINKS): TOOLBOX_BINARY := $(LOCAL_MODULE_STEM) +$(SYMLINKS): $(LOCAL_INSTALLED_MODULE) $(LOCAL_PATH)/Android.mk + @echo "Symlink: $@ -> $(TOOLBOX_BINARY)" + @mkdir -p $(dir $@) + @rm -rf $@ + $(hide) ln -sf $(TOOLBOX_BINARY) $@ + +include $(CLEAR_VARS) +LOCAL_MODULE := toolbox_symlinks +LOCAL_MODULE_TAGS := optional +LOCAL_ADDITIONAL_DEPENDENCIES := $(SYMLINKS) +include $(BUILD_PHONY_PACKAGE) + +ifneq (,$(filter $(PLATFORM_SDK_VERSION),16 17 18)) + # Only needed if the build system lacks support for LOCAL_ADDITIONAL_DEPENDENCIES + ALL_DEFAULT_INSTALLED_MODULES += $(SYMLINKS) + ALL_MODULES.$(LOCAL_MODULE).INSTALLED := \ + $(ALL_MODULES.$(LOCAL_MODULE).INSTALLED) $(SYMLINKS) +endif + +SYMLINKS := +ALL_TOOLS := +BSD_TOOLS := +OUR_TOOLS := +TEMP_TOOLS := +TOOLS_FOR_SELINUX := diff --git a/toolbox/dynarray.h b/toolbox/dynarray.h new file mode 100644 index 000000000..0ca54fdf6 --- /dev/null +++ b/toolbox/dynarray.h @@ -0,0 +1,82 @@ +#ifndef DYNARRAY_H +#define DYNARRAY_H + +// These functions are now found in system/core/toolbox/ls.c + +#include <stddef.h> + +/* simple dynamic array of pointers */ +typedef struct { + int count; + int capacity; + void** items; +} dynarray_t; + +#define DYNARRAY_INITIALIZER { 0, 0, NULL } + +void dynarray_init( dynarray_t *a ); +void dynarray_done( dynarray_t *a ); + +void dynarray_append( dynarray_t *a, void* item ); + +/* Used to iterate over a dynarray_t + * _array :: pointer to the array + * _item_type :: type of objects pointed to by the array + * _item :: name of a local variable defined within the loop + * with type '_item_type' + * _stmnt :: C statement that will be executed in each iteration. + * + * You case use 'break' and 'continue' within _stmnt + * + * This macro is only intended for simple uses. I.e. do not add or + * remove items from the array during iteration. + */ +#define DYNARRAY_FOREACH_TYPE(_array,_item_type,_item,_stmnt) \ + do { \ + int _nn_##__LINE__ = 0; \ + for (;_nn_##__LINE__ < (_array)->count; ++ _nn_##__LINE__) { \ + _item_type _item = (_item_type)(_array)->items[_nn_##__LINE__]; \ + _stmnt; \ + } \ + } while (0) + +#define DYNARRAY_FOREACH(_array,_item,_stmnt) \ + DYNARRAY_FOREACH_TYPE(_array,void *,_item,_stmnt) + +/* Simple dynamic string arrays + * + * NOTE: A strlist_t owns the strings it references. + */ +typedef dynarray_t strlist_t; + +#define STRLIST_INITIALIZER DYNARRAY_INITIALIZER + +/* Used to iterate over a strlist_t + * _list :: pointer to strlist_t object + * _string :: name of local variable name defined within the loop with + * type 'char*' + * _stmnt :: C statement executed in each iteration + * + * This macro is only intended for simple uses. Do not add or remove items + * to/from the list during iteration. + */ +#define STRLIST_FOREACH(_list,_string,_stmnt) \ + DYNARRAY_FOREACH_TYPE(_list,char *,_string,_stmnt) + +void strlist_init( strlist_t *list ); + +/* note: strlist_done will free all the strings owned by the list */ +void strlist_done( strlist_t *list ); + +/* append a new string made of the first 'slen' characters from 'str' + * followed by a trailing zero. + */ +void strlist_append_b( strlist_t *list, const void* str, size_t slen ); + +/* append the copy of a given input string to a strlist_t */ +void strlist_append_dup( strlist_t *list, const char *str); + +/* sort the strings in a given list (using strcmp) */ +void strlist_sort( strlist_t *list ); + +#endif /* DYNARRAY_H */ diff --git a/toolbox/getprop.c b/toolbox/getprop.c new file mode 100644 index 000000000..dcc0ea030 --- /dev/null +++ b/toolbox/getprop.c @@ -0,0 +1,50 @@ +#include <stdio.h> +#include <stdlib.h> + +#include <cutils/properties.h> + +#include "dynarray.h" + +static void record_prop(const char* key, const char* name, void* opaque) +{ + strlist_t* list = opaque; + char temp[PROP_VALUE_MAX + PROP_NAME_MAX + 16]; + snprintf(temp, sizeof temp, "[%s]: [%s]", key, name); + strlist_append_dup(list, temp); +} + +static void list_properties(void) +{ + strlist_t list[1] = { STRLIST_INITIALIZER }; + + /* Record properties in the string list */ + (void)property_list(record_prop, list); + + /* Sort everything */ + strlist_sort(list); + + /* print everything */ + STRLIST_FOREACH(list, str, printf("%s\n", str)); + + /* voila */ + strlist_done(list); +} + +int getprop_main(int argc, char *argv[]) +{ + if (argc == 1) { + list_properties(); + } else { + char value[PROPERTY_VALUE_MAX]; + char *default_value; + if(argc > 2) { + default_value = argv[2]; + } else { + default_value = ""; + } + + property_get(argv[1], value, default_value); + printf("%s\n", value); + } + return 0; +} diff --git a/toolbox/ls.c b/toolbox/ls.c new file mode 100644 index 000000000..9a89dd462 --- /dev/null +++ b/toolbox/ls.c @@ -0,0 +1,588 @@ +#include <dirent.h> +#include <errno.h> +#include <grp.h> +#include <limits.h> +#include <pwd.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/sysmacros.h> +#include <sys/types.h> +#include <time.h> +#include <unistd.h> + +#include <selinux/selinux.h> + +// simple dynamic array of strings. +typedef struct { + int count; + int capacity; + void** items; +} strlist_t; + +#define STRLIST_INITIALIZER { 0, 0, NULL } + +/* Used to iterate over a strlist_t + * _list :: pointer to strlist_t object + * _item :: name of local variable name defined within the loop with + * type 'char*' + * _stmnt :: C statement executed in each iteration + * + * This macro is only intended for simple uses. Do not add or remove items + * to/from the list during iteration. + */ +#define STRLIST_FOREACH(_list,_item,_stmnt) \ + do { \ + int _nn_##__LINE__ = 0; \ + for (;_nn_##__LINE__ < (_list)->count; ++ _nn_##__LINE__) { \ + char* _item = (char*)(_list)->items[_nn_##__LINE__]; \ + _stmnt; \ + } \ + } while (0) + +static void dynarray_reserve_more( strlist_t *a, int count ) { + int old_cap = a->capacity; + int new_cap = old_cap; + const int max_cap = INT_MAX/sizeof(void*); + void** new_items; + int new_count = a->count + count; + + if (count <= 0) + return; + + if (count > max_cap - a->count) + abort(); + + new_count = a->count + count; + + while (new_cap < new_count) { + old_cap = new_cap; + new_cap += (new_cap >> 2) + 4; + if (new_cap < old_cap || new_cap > max_cap) { + new_cap = max_cap; + } + } + new_items = realloc(a->items, new_cap*sizeof(void*)); + if (new_items == NULL) + abort(); + + a->items = new_items; + a->capacity = new_cap; +} + +void strlist_init( strlist_t *list ) { + list->count = list->capacity = 0; + list->items = NULL; +} + +// append a new string made of the first 'slen' characters from 'str' +// followed by a trailing zero. +void strlist_append_b( strlist_t *list, const void* str, size_t slen ) { + char *copy = malloc(slen+1); + memcpy(copy, str, slen); + copy[slen] = '\0'; + if (list->count >= list->capacity) + dynarray_reserve_more(list, 1); + list->items[list->count++] = copy; +} + +// append the copy of a given input string to a strlist_t. +void strlist_append_dup( strlist_t *list, const char *str) { + strlist_append_b(list, str, strlen(str)); +} + +// note: strlist_done will free all the strings owned by the list. +void strlist_done( strlist_t *list ) { + STRLIST_FOREACH(list, string, free(string)); + free(list->items); + list->items = NULL; + list->count = list->capacity = 0; +} + +static int strlist_compare_strings(const void* a, const void* b) { + const char *sa = *(const char **)a; + const char *sb = *(const char **)b; + return strcmp(sa, sb); +} + +/* sort the strings in a given list (using strcmp) */ +void strlist_sort( strlist_t *list ) { + if (list->count > 0) { + qsort(list->items, (size_t)list->count, sizeof(void*), strlist_compare_strings); + } +} + + +// bits for flags argument +#define LIST_LONG (1 << 0) +#define LIST_ALL (1 << 1) +#define LIST_RECURSIVE (1 << 2) +#define LIST_DIRECTORIES (1 << 3) +#define LIST_SIZE (1 << 4) +#define LIST_LONG_NUMERIC (1 << 5) +#define LIST_CLASSIFY (1 << 6) +#define LIST_MACLABEL (1 << 7) +#define LIST_INODE (1 << 8) + +// fwd +static int listpath(const char *name, int flags); + +static char mode2kind(mode_t mode) +{ + switch(mode & S_IFMT){ + case S_IFSOCK: return 's'; + case S_IFLNK: return 'l'; + case S_IFREG: return '-'; + case S_IFDIR: return 'd'; + case S_IFBLK: return 'b'; + case S_IFCHR: return 'c'; + case S_IFIFO: return 'p'; + default: return '?'; + } +} + +void strmode(mode_t mode, char *out) +{ + *out++ = mode2kind(mode); + + *out++ = (mode & 0400) ? 'r' : '-'; + *out++ = (mode & 0200) ? 'w' : '-'; + if(mode & 04000) { + *out++ = (mode & 0100) ? 's' : 'S'; + } else { + *out++ = (mode & 0100) ? 'x' : '-'; + } + *out++ = (mode & 040) ? 'r' : '-'; + *out++ = (mode & 020) ? 'w' : '-'; + if(mode & 02000) { + *out++ = (mode & 010) ? 's' : 'S'; + } else { + *out++ = (mode & 010) ? 'x' : '-'; + } + *out++ = (mode & 04) ? 'r' : '-'; + *out++ = (mode & 02) ? 'w' : '-'; + if(mode & 01000) { + *out++ = (mode & 01) ? 't' : 'T'; + } else { + *out++ = (mode & 01) ? 'x' : '-'; + } + *out = 0; +} + +static void user2str(uid_t uid, char *out, size_t out_size) +{ + struct passwd *pw = getpwuid(uid); + if(pw) { + strlcpy(out, pw->pw_name, out_size); + } else { + snprintf(out, out_size, "%d", uid); + } +} + +static void group2str(gid_t gid, char *out, size_t out_size) +{ + struct group *gr = getgrgid(gid); + if(gr) { + strlcpy(out, gr->gr_name, out_size); + } else { + snprintf(out, out_size, "%d", gid); + } +} + +static int show_total_size(const char *dirname, DIR *d, int flags) +{ + struct dirent *de; + char tmp[1024]; + struct stat s; + int sum = 0; + + /* run through the directory and sum up the file block sizes */ + while ((de = readdir(d)) != 0) { + if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0) + continue; + if (de->d_name[0] == '.' && (flags & LIST_ALL) == 0) + continue; + + if (strcmp(dirname, "/") == 0) + snprintf(tmp, sizeof(tmp), "/%s", de->d_name); + else + snprintf(tmp, sizeof(tmp), "%s/%s", dirname, de->d_name); + + if (lstat(tmp, &s) < 0) { + fprintf(stderr, "stat failed on %s: %s\n", tmp, strerror(errno)); + rewinddir(d); + return -1; + } + + sum += s.st_blocks / 2; + } + + printf("total %d\n", sum); + rewinddir(d); + return 0; +} + +static int listfile_size(const char *path, const char *filename, struct stat *s, + int flags) +{ + if(!s || !path) { + return -1; + } + + /* blocks are 512 bytes, we want output to be KB */ + if ((flags & LIST_SIZE) != 0) { + printf("%lld ", (long long)s->st_blocks / 2); + } + + if ((flags & LIST_CLASSIFY) != 0) { + char filetype = mode2kind(s->st_mode); + if (filetype != 'l') { + printf("%c ", filetype); + } else { + struct stat link_dest; + if (!stat(path, &link_dest)) { + printf("l%c ", mode2kind(link_dest.st_mode)); + } else { + fprintf(stderr, "stat '%s' failed: %s\n", path, strerror(errno)); + printf("l? "); + } + } + } + + printf("%s\n", filename); + + return 0; +} + +static int listfile_long(const char *path, struct stat *s, int flags) +{ + char date[32]; + char mode[16]; + char user[32]; + char group[32]; + const char *name; + + if(!s || !path) { + return -1; + } + + /* name is anything after the final '/', or the whole path if none*/ + name = strrchr(path, '/'); + if(name == 0) { + name = path; + } else { + name++; + } + + strmode(s->st_mode, mode); + if (flags & LIST_LONG_NUMERIC) { + snprintf(user, sizeof(user), "%u", s->st_uid); + snprintf(group, sizeof(group), "%u", s->st_gid); + } else { + user2str(s->st_uid, user, sizeof(user)); + group2str(s->st_gid, group, sizeof(group)); + } + + strftime(date, 32, "%Y-%m-%d %H:%M", localtime((const time_t*)&s->st_mtime)); + date[31] = 0; + +// 12345678901234567890123456789012345678901234567890123456789012345678901234567890 +// MMMMMMMM UUUUUUUU GGGGGGGGG XXXXXXXX YYYY-MM-DD HH:MM NAME (->LINK) + + switch(s->st_mode & S_IFMT) { + case S_IFBLK: + case S_IFCHR: + printf("%s %-8s %-8s %3d, %3d %s %s\n", + mode, user, group, + major(s->st_rdev), minor(s->st_rdev), + date, name); + break; + case S_IFREG: + printf("%s %-8s %-8s %8lld %s %s\n", + mode, user, group, (long long)s->st_size, date, name); + break; + case S_IFLNK: { + char linkto[256]; + ssize_t len; + + len = readlink(path, linkto, 256); + if(len < 0) return -1; + + if(len > 255) { + linkto[252] = '.'; + linkto[253] = '.'; + linkto[254] = '.'; + linkto[255] = 0; + } else { + linkto[len] = 0; + } + + printf("%s %-8s %-8s %s %s -> %s\n", + mode, user, group, date, name, linkto); + break; + } + default: + printf("%s %-8s %-8s %s %s\n", + mode, user, group, date, name); + + } + return 0; +} + +static int listfile_maclabel(const char *path, struct stat *s) +{ + char mode[16]; + char user[32]; + char group[32]; + char *maclabel = NULL; + const char *name; + + if(!s || !path) { + return -1; + } + + /* name is anything after the final '/', or the whole path if none*/ + name = strrchr(path, '/'); + if(name == 0) { + name = path; + } else { + name++; + } + + lgetfilecon(path, &maclabel); + if (!maclabel) { + return -1; + } + + strmode(s->st_mode, mode); + user2str(s->st_uid, user, sizeof(user)); + group2str(s->st_gid, group, sizeof(group)); + + switch(s->st_mode & S_IFMT) { + case S_IFLNK: { + char linkto[256]; + ssize_t len; + + len = readlink(path, linkto, sizeof(linkto)); + if(len < 0) return -1; + + if((size_t)len > sizeof(linkto)-1) { + linkto[sizeof(linkto)-4] = '.'; + linkto[sizeof(linkto)-3] = '.'; + linkto[sizeof(linkto)-2] = '.'; + linkto[sizeof(linkto)-1] = 0; + } else { + linkto[len] = 0; + } + + printf("%s %-8s %-8s %s %s -> %s\n", + mode, user, group, maclabel, name, linkto); + break; + } + default: + printf("%s %-8s %-8s %s %s\n", + mode, user, group, maclabel, name); + + } + + free(maclabel); + + return 0; +} + +static int listfile(const char *dirname, const char *filename, int flags) +{ + struct stat s; + + if ((flags & (LIST_LONG | LIST_SIZE | LIST_CLASSIFY | LIST_MACLABEL | LIST_INODE)) == 0) { + printf("%s\n", filename); + return 0; + } + + char tmp[4096]; + const char* pathname = filename; + + if (dirname != NULL) { + snprintf(tmp, sizeof(tmp), "%s/%s", dirname, filename); + pathname = tmp; + } else { + pathname = filename; + } + + if(lstat(pathname, &s) < 0) { + fprintf(stderr, "lstat '%s' failed: %s\n", pathname, strerror(errno)); + return -1; + } + + if(flags & LIST_INODE) { + printf("%8llu ", (unsigned long long)s.st_ino); + } + + if ((flags & LIST_MACLABEL) != 0) { + return listfile_maclabel(pathname, &s); + } else if ((flags & LIST_LONG) != 0) { + return listfile_long(pathname, &s, flags); + } else /*((flags & LIST_SIZE) != 0)*/ { + return listfile_size(pathname, filename, &s, flags); + } +} + +static int listdir(const char *name, int flags) +{ + char tmp[4096]; + DIR *d; + struct dirent *de; + strlist_t files = STRLIST_INITIALIZER; + + d = opendir(name); + if(d == 0) { + fprintf(stderr, "opendir failed, %s\n", strerror(errno)); + return -1; + } + + if ((flags & LIST_SIZE) != 0) { + show_total_size(name, d, flags); + } + + while((de = readdir(d)) != 0){ + if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) continue; + if(de->d_name[0] == '.' && (flags & LIST_ALL) == 0) continue; + + strlist_append_dup(&files, de->d_name); + } + + strlist_sort(&files); + STRLIST_FOREACH(&files, filename, listfile(name, filename, flags)); + strlist_done(&files); + + if (flags & LIST_RECURSIVE) { + strlist_t subdirs = STRLIST_INITIALIZER; + + rewinddir(d); + + while ((de = readdir(d)) != 0) { + struct stat s; + int err; + + if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) + continue; + if (de->d_name[0] == '.' && (flags & LIST_ALL) == 0) + continue; + + if (!strcmp(name, "/")) + snprintf(tmp, sizeof(tmp), "/%s", de->d_name); + else + snprintf(tmp, sizeof(tmp), "%s/%s", name, de->d_name); + + /* + * If the name ends in a '/', use stat() so we treat it like a + * directory even if it's a symlink. + */ + if (tmp[strlen(tmp)-1] == '/') + err = stat(tmp, &s); + else + err = lstat(tmp, &s); + + if (err < 0) { + perror(tmp); + closedir(d); + return -1; + } + + if (S_ISDIR(s.st_mode)) { + strlist_append_dup(&subdirs, tmp); + } + } + strlist_sort(&subdirs); + STRLIST_FOREACH(&subdirs, path, { + printf("\n%s:\n", path); + listdir(path, flags); + }); + strlist_done(&subdirs); + } + + closedir(d); + return 0; +} + +static int listpath(const char *name, int flags) +{ + struct stat s; + int err; + + /* + * If the name ends in a '/', use stat() so we treat it like a + * directory even if it's a symlink. + */ + if (name[strlen(name)-1] == '/') + err = stat(name, &s); + else + err = lstat(name, &s); + + if (err < 0) { + perror(name); + return -1; + } + + if ((flags & LIST_DIRECTORIES) == 0 && S_ISDIR(s.st_mode)) { + if (flags & LIST_RECURSIVE) + printf("\n%s:\n", name); + return listdir(name, flags); + } else { + /* yeah this calls stat() again*/ + return listfile(NULL, name, flags); + } +} + +int ls_main(int argc, char **argv) +{ + int flags = 0; + + if(argc > 1) { + int i; + int err = 0; + strlist_t files = STRLIST_INITIALIZER; + + for (i = 1; i < argc; i++) { + if (argv[i][0] == '-') { + /* an option ? */ + const char *arg = argv[i]+1; + while (arg[0]) { + switch (arg[0]) { + case 'l': flags |= LIST_LONG; break; + case 'n': flags |= LIST_LONG | LIST_LONG_NUMERIC; break; + case 's': flags |= LIST_SIZE; break; + case 'R': flags |= LIST_RECURSIVE; break; + case 'd': flags |= LIST_DIRECTORIES; break; + case 'Z': flags |= LIST_MACLABEL; break; + case 'a': flags |= LIST_ALL; break; + case 'F': flags |= LIST_CLASSIFY; break; + case 'i': flags |= LIST_INODE; break; + default: + fprintf(stderr, "%s: Unknown option '-%c'. Aborting.\n", "ls", arg[0]); + exit(1); + } + arg++; + } + } else { + /* not an option ? */ + strlist_append_dup(&files, argv[i]); + } + } + + if (files.count > 0) { + STRLIST_FOREACH(&files, path, { + if (listpath(path, flags) != 0) { + err = EXIT_FAILURE; + } + }); + strlist_done(&files); + return err; + } + } + + // list working directory if no files or directories were specified + return listpath(".", flags); +} diff --git a/toolbox/setprop.c b/toolbox/setprop.c new file mode 100644 index 000000000..63ad2b426 --- /dev/null +++ b/toolbox/setprop.c @@ -0,0 +1,18 @@ +#include <stdio.h> + +#include <cutils/properties.h> + +int setprop_main(int argc, char *argv[]) +{ + if(argc != 3) { + fprintf(stderr,"usage: setprop <key> <value>\n"); + return 1; + } + + if(property_set(argv[1], argv[2])){ + fprintf(stderr,"could not set property\n"); + return 1; + } + + return 0; +} |