/* getprop.c - Get an Android system property * * Copyright 2015 The Android Open Source Project USE_GETPROP(NEWTOY(getprop, ">2Z", TOYFLAG_USR|TOYFLAG_SBIN)) config GETPROP bool "getprop" default y depends on TOYBOX_ON_ANDROID && TOYBOX_SELINUX help usage: getprop [NAME [DEFAULT]] Gets an Android system property, or lists them all. */ #define FOR_getprop #include "toys.h" #include <sys/system_properties.h> #include <selinux/android.h> #include <selinux/label.h> #include <selinux/selinux.h> GLOBALS( size_t size; char **nv; // name/value pairs: even=name, odd=value struct selabel_handle *handle; ) static char *get_property_context(const char *property) { char *context = NULL; if (selabel_lookup(TT.handle, &context, property, 1)) { perror_exit("unable to lookup label for \"%s\"", property); } return context; } static void read_callback(void *unused, const char *name, const char *value, unsigned serial) { if (!(TT.size&31)) TT.nv = xrealloc(TT.nv, (TT.size+32)*2*sizeof(char *)); TT.nv[2*TT.size] = xstrdup((char *)name); if (toys.optflags & FLAG_Z) { TT.nv[1+2*TT.size++] = get_property_context(name); } else { TT.nv[1+2*TT.size++] = xstrdup((char *)value); } } static void add_property(const prop_info *pi, void *unused) { __system_property_read_callback(pi, read_callback, NULL); } static void print_callback(void *unused, const char *unused_name, const char *value, unsigned unused_serial) { puts(value); } // Needed to supress extraneous "Loaded property_contexts from" message static int selinux_log_callback_local(int type, const char *fmt, ...) { va_list ap; if (type == SELINUX_INFO) return 0; va_start(ap, fmt); verror_msg((char *)fmt, 0, ap); va_end(ap); return 0; } void getprop_main(void) { if (toys.optflags & FLAG_Z) { union selinux_callback cb; cb.func_log = selinux_log_callback_local; selinux_set_callback(SELINUX_CB_LOG, cb); TT.handle = selinux_android_prop_context_handle(); if (!TT.handle) error_exit("unable to get selinux property context handle"); } if (*toys.optargs) { if (toys.optflags & FLAG_Z) { char *context = get_property_context(*toys.optargs); puts(context); if (CFG_TOYBOX_FREE) free(context); } else { const prop_info* pi = __system_property_find(*toys.optargs); if (pi == NULL) { puts(toys.optargs[1] ? toys.optargs[1] : ""); } else { __system_property_read_callback(pi, print_callback, NULL); } } } else { size_t i; if (__system_property_foreach(add_property, NULL)) error_exit("property_list"); qsort(TT.nv, TT.size, 2*sizeof(char *), qstrcmp); for (i = 0; i<TT.size; i++) printf("[%s]: [%s]\n", TT.nv[i*2],TT.nv[1+i*2]); if (CFG_TOYBOX_FREE) { for (i = 0; i<TT.size; i++) { free(TT.nv[i*2]); free(TT.nv[1+i*2]); } free(TT.nv); } } if (CFG_TOYBOX_FREE && (toys.optflags & FLAG_Z)) selabel_close(TT.handle); }