1/* getprop.c - Get an Android system property
2 *
3 * Copyright 2015 The Android Open Source Project
4
5USE_GETPROP(NEWTOY(getprop, ">2Z", TOYFLAG_USR|TOYFLAG_SBIN))
6
7config GETPROP
8  bool "getprop"
9  default y
10  depends on TOYBOX_ON_ANDROID && TOYBOX_SELINUX
11  help
12    usage: getprop [NAME [DEFAULT]]
13
14    Gets an Android system property, or lists them all.
15*/
16
17#define FOR_getprop
18#include "toys.h"
19
20#include <sys/system_properties.h>
21
22#include <selinux/android.h>
23#include <selinux/label.h>
24#include <selinux/selinux.h>
25
26GLOBALS(
27  size_t size;
28  char **nv; // name/value pairs: even=name, odd=value
29  struct selabel_handle *handle;
30)
31
32static char *get_property_context(const char *property)
33{
34  char *context = NULL;
35
36  if (selabel_lookup(TT.handle, &context, property, 1)) {
37    perror_exit("unable to lookup label for \"%s\"", property);
38  }
39  return context;
40}
41
42static void read_callback(void *unused, const char *name, const char *value,
43                          unsigned serial)
44{
45  if (!(TT.size&31)) TT.nv = xrealloc(TT.nv, (TT.size+32)*2*sizeof(char *));
46
47  TT.nv[2*TT.size] = xstrdup((char *)name);
48  if (toys.optflags & FLAG_Z) {
49    TT.nv[1+2*TT.size++] = get_property_context(name);
50  } else {
51    TT.nv[1+2*TT.size++] = xstrdup((char *)value);
52  }
53}
54
55static void add_property(const prop_info *pi, void *unused)
56{
57  __system_property_read_callback(pi, read_callback, NULL);
58}
59
60// Needed to supress extraneous "Loaded property_contexts from" message
61static int selinux_log_callback_local(int type, const char *fmt, ...)
62{
63  va_list ap;
64
65  if (type == SELINUX_INFO) return 0;
66  va_start(ap, fmt);
67  verror_msg((char *)fmt, 0, ap);
68  va_end(ap);
69  return 0;
70}
71
72void getprop_main(void)
73{
74  if (toys.optflags & FLAG_Z) {
75    union selinux_callback cb;
76
77    cb.func_log = selinux_log_callback_local;
78    selinux_set_callback(SELINUX_CB_LOG, cb);
79    TT.handle = selinux_android_prop_context_handle();
80    if (!TT.handle) error_exit("unable to get selinux property context handle");
81  }
82
83  if (*toys.optargs) {
84    if (toys.optflags & FLAG_Z) {
85      char *context = get_property_context(*toys.optargs);
86
87      puts(context);
88      if (CFG_TOYBOX_FREE) free(context);
89    } else {
90      if (__system_property_get(*toys.optargs, toybuf) <= 0)
91        strcpy(toybuf, toys.optargs[1] ? toys.optargs[1] : "");
92      puts(toybuf);
93    }
94  } else {
95    size_t i;
96
97    if (__system_property_foreach(add_property, NULL))
98      error_exit("property_list");
99    qsort(TT.nv, TT.size, 2*sizeof(char *), qstrcmp);
100    for (i = 0; i<TT.size; i++) printf("[%s]: [%s]\n", TT.nv[i*2],TT.nv[1+i*2]);
101    if (CFG_TOYBOX_FREE) {
102      for (i = 0; i<TT.size; i++) {
103        free(TT.nv[i*2]);
104        free(TT.nv[1+i*2]);
105      }
106      free(TT.nv);
107    }
108  }
109  if (CFG_TOYBOX_FREE && (toys.optflags & FLAG_Z)) selabel_close(TT.handle);
110}
111