2012-07-17 07:00:18 +04:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <stdlib.h>
|
2012-08-14 14:50:48 +04:00
|
|
|
#include <arpa/inet.h>
|
2012-08-21 16:27:07 +04:00
|
|
|
#include <ctype.h>
|
2012-07-17 07:00:18 +04:00
|
|
|
|
2012-07-18 13:04:00 +04:00
|
|
|
#include <google/protobuf-c/protobuf-c.h>
|
|
|
|
|
2013-11-06 14:34:30 +04:00
|
|
|
#include "image.h"
|
|
|
|
#include "servicefd.h"
|
2012-07-17 07:00:18 +04:00
|
|
|
#include "compiler.h"
|
2013-01-09 17:02:47 +04:00
|
|
|
#include "asm/types.h"
|
2012-07-17 07:00:18 +04:00
|
|
|
#include "log.h"
|
|
|
|
#include "util.h"
|
2012-08-14 14:49:21 +04:00
|
|
|
#include "string.h"
|
2012-08-14 14:50:48 +04:00
|
|
|
#include "sockets.h"
|
2013-12-27 15:58:27 +04:00
|
|
|
#include "cr_options.h"
|
2012-07-17 07:00:18 +04:00
|
|
|
|
|
|
|
#include "protobuf.h"
|
|
|
|
|
|
|
|
/*
|
|
|
|
* To speed up reading of packed objects
|
|
|
|
* by providing space on stack, this should
|
|
|
|
* be more than enough for most objects.
|
|
|
|
*/
|
|
|
|
#define PB_PKOBJ_LOCAL_SIZE 1024
|
|
|
|
|
2012-08-14 14:50:48 +04:00
|
|
|
#define INET_ADDR_LEN 40
|
|
|
|
|
2012-08-14 14:45:29 +04:00
|
|
|
struct pb_pr_field_s {
|
2012-08-14 14:45:47 +04:00
|
|
|
void *data;
|
2012-08-14 14:49:21 +04:00
|
|
|
int number;
|
2012-08-14 14:45:29 +04:00
|
|
|
int depth;
|
2012-08-14 14:49:21 +04:00
|
|
|
int count;
|
|
|
|
char fmt[32];
|
2012-08-14 14:45:29 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct pb_pr_field_s pb_pr_field_t;
|
|
|
|
|
2012-07-25 18:28:12 +04:00
|
|
|
struct pb_pr_ctrl_s {
|
|
|
|
void *arg;
|
2012-07-25 18:28:14 +04:00
|
|
|
int single_entry;
|
2012-08-14 14:49:21 +04:00
|
|
|
const char *pretty_fmt;
|
2012-08-14 14:45:29 +04:00
|
|
|
pb_pr_field_t cur;
|
2012-07-25 18:28:12 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct pb_pr_ctrl_s pb_pr_ctl_t;
|
2012-08-14 14:49:21 +04:00
|
|
|
typedef int (*pb_pr_show_t)(pb_pr_field_t *field);
|
2012-07-18 13:04:00 +04:00
|
|
|
|
2012-08-14 14:49:21 +04:00
|
|
|
static int pb_msg_int32x(pb_pr_field_t *field)
|
2012-07-18 13:04:00 +04:00
|
|
|
{
|
2012-08-14 14:47:40 +04:00
|
|
|
pr_msg("%#x", *(int *)field->data);
|
2012-08-14 14:49:21 +04:00
|
|
|
return 0;
|
2012-07-18 13:04:00 +04:00
|
|
|
}
|
|
|
|
|
2012-08-14 14:49:21 +04:00
|
|
|
static int pb_msg_int64x(pb_pr_field_t *field)
|
2012-07-18 13:04:00 +04:00
|
|
|
{
|
2012-08-14 14:47:40 +04:00
|
|
|
pr_msg("%#016lx", *(long *)field->data);
|
2012-08-14 14:49:21 +04:00
|
|
|
return 0;
|
2012-07-18 13:04:00 +04:00
|
|
|
}
|
|
|
|
|
2013-10-17 14:48:05 +04:00
|
|
|
static int pb_msg_int64x_r(pb_pr_field_t *field)
|
|
|
|
{
|
|
|
|
long val = *(long *)field->data;
|
|
|
|
if (val)
|
|
|
|
pr_msg("%#016lx", val);
|
|
|
|
else
|
|
|
|
pr_msg("0");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-08-14 14:49:21 +04:00
|
|
|
static int pb_msg_string(pb_pr_field_t *field)
|
2012-07-18 13:04:00 +04:00
|
|
|
{
|
2012-08-14 14:47:40 +04:00
|
|
|
pr_msg("\"%s\"", *(char **)field->data);
|
2012-08-14 14:49:21 +04:00
|
|
|
return 0;
|
2012-07-18 13:04:00 +04:00
|
|
|
}
|
|
|
|
|
2012-08-14 14:49:21 +04:00
|
|
|
static int pb_msg_unk(pb_pr_field_t *field)
|
2012-07-18 13:04:00 +04:00
|
|
|
{
|
2012-08-14 14:47:40 +04:00
|
|
|
pr_msg("unknown object %p", field->data);
|
2012-08-14 14:49:21 +04:00
|
|
|
return 0;
|
2012-07-18 13:04:00 +04:00
|
|
|
}
|
|
|
|
|
2012-07-25 18:28:15 +04:00
|
|
|
static inline void print_tabs(pb_pr_ctl_t *ctl)
|
2012-07-25 18:28:14 +04:00
|
|
|
{
|
2012-08-14 14:45:29 +04:00
|
|
|
int counter = ctl->cur.depth;
|
2012-07-25 18:28:15 +04:00
|
|
|
|
|
|
|
if (!ctl->single_entry)
|
|
|
|
return;
|
|
|
|
|
|
|
|
while (counter--)
|
|
|
|
pr_msg("\t");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void print_nested_message_braces(pb_pr_ctl_t *ctl, int right_brace)
|
|
|
|
{
|
|
|
|
if (right_brace)
|
|
|
|
print_tabs(ctl);
|
2012-07-25 18:28:17 +04:00
|
|
|
pr_msg("%s%s", (right_brace) ? "}" : "{", (ctl->single_entry) ? "\n" : " ");
|
2012-07-25 18:28:14 +04:00
|
|
|
}
|
|
|
|
|
2012-07-25 18:28:12 +04:00
|
|
|
static void pb_show_msg(const void *msg, pb_pr_ctl_t *ctl);
|
2012-07-18 13:04:00 +04:00
|
|
|
|
2012-08-14 14:49:21 +04:00
|
|
|
static int show_nested_message(pb_pr_field_t *field)
|
2012-07-18 13:04:00 +04:00
|
|
|
{
|
2012-08-14 14:47:40 +04:00
|
|
|
pb_pr_ctl_t *ctl = container_of(field, pb_pr_ctl_t, cur);
|
|
|
|
|
2012-07-25 18:28:14 +04:00
|
|
|
print_nested_message_braces(ctl, 0);
|
2012-08-14 14:47:40 +04:00
|
|
|
field->depth++;
|
|
|
|
pb_show_msg(field->data, ctl);
|
|
|
|
field->depth--;
|
2012-07-25 18:28:14 +04:00
|
|
|
print_nested_message_braces(ctl, 1);
|
2012-08-14 14:49:21 +04:00
|
|
|
return 0;
|
2012-07-18 13:04:00 +04:00
|
|
|
}
|
|
|
|
|
2012-08-14 14:49:21 +04:00
|
|
|
static int show_enum(pb_pr_field_t *field)
|
2012-07-19 10:17:40 +04:00
|
|
|
{
|
2012-08-14 14:47:40 +04:00
|
|
|
pb_pr_ctl_t *ctl = container_of(field, pb_pr_ctl_t, cur);
|
2012-07-25 18:28:12 +04:00
|
|
|
ProtobufCEnumDescriptor *d = ctl->arg;
|
2012-07-19 10:17:40 +04:00
|
|
|
const char *val_name = NULL;
|
|
|
|
int val, i;
|
|
|
|
|
2012-08-14 14:47:40 +04:00
|
|
|
val = *(int *)field->data;
|
2012-07-19 10:17:40 +04:00
|
|
|
for (i = 0; i < d->n_values; i++)
|
|
|
|
if (d->values[i].value == val) {
|
|
|
|
val_name = d->values[i].name;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (val_name != NULL)
|
|
|
|
pr_msg("%s", val_name);
|
|
|
|
else
|
|
|
|
pr_msg("%d", val);
|
2012-08-14 14:49:21 +04:00
|
|
|
return 0;
|
2012-07-19 10:17:40 +04:00
|
|
|
}
|
2012-07-18 13:04:00 +04:00
|
|
|
|
2012-08-14 14:49:21 +04:00
|
|
|
static int show_bool(pb_pr_field_t *field)
|
2012-08-09 18:12:22 +04:00
|
|
|
{
|
2012-08-14 14:47:40 +04:00
|
|
|
protobuf_c_boolean val = *(protobuf_c_boolean *)field->data;
|
2012-08-09 18:12:22 +04:00
|
|
|
|
|
|
|
if (val)
|
|
|
|
pr_msg("True");
|
|
|
|
else
|
|
|
|
pr_msg("False");
|
2012-08-14 14:49:21 +04:00
|
|
|
return 0;
|
2012-08-09 18:12:22 +04:00
|
|
|
}
|
|
|
|
|
2012-08-21 16:27:14 +04:00
|
|
|
static int show_bytes(pb_pr_field_t *field)
|
|
|
|
{
|
|
|
|
ProtobufCBinaryData *bytes = (ProtobufCBinaryData *)field->data;
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
while (i < bytes->len)
|
|
|
|
pr_msg("%02x ", bytes->data[i++]);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-08-14 14:46:47 +04:00
|
|
|
static size_t pb_show_prepare_field_context(const ProtobufCFieldDescriptor *fd,
|
|
|
|
pb_pr_ctl_t *ctl)
|
|
|
|
{
|
|
|
|
pb_pr_field_t *field = &ctl->cur;
|
2012-08-14 14:52:21 +04:00
|
|
|
size_t fsize = 0;
|
2012-08-14 14:46:47 +04:00
|
|
|
|
|
|
|
switch (fd->type) {
|
|
|
|
case PROTOBUF_C_TYPE_ENUM:
|
|
|
|
ctl->arg = (void *)fd->descriptor;
|
|
|
|
case PROTOBUF_C_TYPE_INT32:
|
|
|
|
case PROTOBUF_C_TYPE_SINT32:
|
|
|
|
case PROTOBUF_C_TYPE_UINT32:
|
|
|
|
case PROTOBUF_C_TYPE_SFIXED32:
|
|
|
|
case PROTOBUF_C_TYPE_FLOAT:
|
|
|
|
fsize = 4;
|
|
|
|
break;
|
|
|
|
case PROTOBUF_C_TYPE_INT64:
|
|
|
|
case PROTOBUF_C_TYPE_SINT64:
|
|
|
|
case PROTOBUF_C_TYPE_SFIXED64:
|
|
|
|
case PROTOBUF_C_TYPE_FIXED32:
|
|
|
|
case PROTOBUF_C_TYPE_UINT64:
|
|
|
|
case PROTOBUF_C_TYPE_FIXED64:
|
|
|
|
case PROTOBUF_C_TYPE_DOUBLE:
|
|
|
|
fsize = 8;
|
|
|
|
break;
|
|
|
|
case PROTOBUF_C_TYPE_MESSAGE:
|
|
|
|
ctl->arg = (void *)fd->descriptor;
|
2014-02-04 11:52:55 +04:00
|
|
|
if (field->data)
|
|
|
|
field->data = (void *)(*(long *)field->data);
|
2012-08-14 14:46:47 +04:00
|
|
|
case PROTOBUF_C_TYPE_STRING:
|
|
|
|
fsize = sizeof (void *);
|
|
|
|
break;
|
|
|
|
case PROTOBUF_C_TYPE_BOOL:
|
|
|
|
fsize = sizeof (protobuf_c_boolean);
|
|
|
|
break;
|
|
|
|
case PROTOBUF_C_TYPE_BYTES:
|
|
|
|
fsize = sizeof (ProtobufCBinaryData);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
BUG();
|
|
|
|
}
|
|
|
|
return fsize;
|
|
|
|
}
|
|
|
|
|
2012-08-14 14:49:21 +04:00
|
|
|
static int pb_show_pretty(pb_pr_field_t *field)
|
|
|
|
{
|
2012-08-14 14:50:48 +04:00
|
|
|
switch (field->fmt[0]) {
|
|
|
|
case '%':
|
|
|
|
pr_msg(field->fmt, *(long *)field->data);
|
|
|
|
break;
|
2012-08-21 16:27:07 +04:00
|
|
|
case 'S':
|
|
|
|
{
|
|
|
|
ProtobufCBinaryData *name = (ProtobufCBinaryData *)field->data;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < name->len; i++) {
|
|
|
|
char c = (char)name->data[i];
|
|
|
|
|
|
|
|
if (isprint(c))
|
|
|
|
pr_msg("%c", c);
|
|
|
|
else if (c != 0)
|
|
|
|
pr_msg(".");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2012-08-14 14:50:48 +04:00
|
|
|
case 'A':
|
|
|
|
{
|
|
|
|
char addr[INET_ADDR_LEN] = "<unknown>";
|
|
|
|
int family = (field->count == 1) ? AF_INET : AF_INET6;
|
|
|
|
|
|
|
|
if (inet_ntop(family, (void *)field->data, addr,
|
|
|
|
INET_ADDR_LEN) == NULL)
|
|
|
|
pr_msg("failed to translate");
|
|
|
|
else
|
|
|
|
pr_msg("%s", addr);
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
2012-08-14 14:49:21 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-05-14 14:30:10 +04:00
|
|
|
static void pb_copy_fmt(const char *fmt, char *to)
|
|
|
|
{
|
2013-05-15 15:37:42 +04:00
|
|
|
while (*fmt != ' ' && *fmt != '\0') {
|
2013-05-14 14:30:10 +04:00
|
|
|
*to = *fmt;
|
|
|
|
to++;
|
|
|
|
fmt++;
|
|
|
|
}
|
|
|
|
|
|
|
|
*to = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *pb_next_pretty(const char *pfmt)
|
|
|
|
{
|
|
|
|
pfmt = strchr(pfmt, ' ');
|
|
|
|
if (pfmt) {
|
|
|
|
while (*pfmt == ' ')
|
|
|
|
pfmt++;
|
|
|
|
|
|
|
|
if (*pfmt == '\0')
|
|
|
|
pfmt = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return pfmt;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int pb_find_fmt(char *what, pb_pr_ctl_t *ctl)
|
|
|
|
{
|
|
|
|
int len;
|
|
|
|
const char *pretty = ctl->pretty_fmt;
|
|
|
|
|
|
|
|
len = strlen(what);
|
|
|
|
while (1) {
|
|
|
|
if (!strncmp(pretty, what, len)) {
|
|
|
|
pb_copy_fmt(pretty + len, ctl->cur.fmt);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
pretty = pb_next_pretty(pretty + len);
|
|
|
|
if (!pretty)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int pb_field_show_pretty(const ProtobufCFieldDescriptor *fd, pb_pr_ctl_t *ctl)
|
2012-08-14 14:49:21 +04:00
|
|
|
{
|
|
|
|
char cookie[32];
|
|
|
|
|
2013-05-09 22:40:43 +04:00
|
|
|
if (!ctl->pretty_fmt)
|
2012-08-14 14:49:21 +04:00
|
|
|
return 0;
|
|
|
|
|
2013-05-14 14:30:10 +04:00
|
|
|
sprintf(cookie, "%s:", fd->name);
|
|
|
|
if (pb_find_fmt(cookie, ctl))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (!ctl->cur.depth)
|
|
|
|
sprintf(cookie, "%d:", ctl->cur.number);
|
2013-05-09 22:40:43 +04:00
|
|
|
else
|
2013-05-14 14:30:10 +04:00
|
|
|
sprintf(cookie, "%d.%d:", ctl->cur.depth, ctl->cur.number);
|
2013-05-09 22:40:43 +04:00
|
|
|
|
2013-05-14 14:30:10 +04:00
|
|
|
if (pb_find_fmt(cookie, ctl))
|
|
|
|
return 1;
|
|
|
|
|
2013-05-14 14:40:17 +04:00
|
|
|
sprintf(cookie, "*:");
|
|
|
|
if (pb_find_fmt(cookie, ctl))
|
|
|
|
return 1;
|
|
|
|
|
2013-05-14 14:30:10 +04:00
|
|
|
return 0;
|
2012-08-14 14:49:21 +04:00
|
|
|
}
|
|
|
|
|
2013-10-17 14:48:05 +04:00
|
|
|
static pb_pr_show_t get_pb_show_function(int type, int label)
|
2012-08-14 14:46:49 +04:00
|
|
|
{
|
|
|
|
switch (type) {
|
|
|
|
case PROTOBUF_C_TYPE_INT32:
|
|
|
|
case PROTOBUF_C_TYPE_SINT32:
|
|
|
|
case PROTOBUF_C_TYPE_UINT32:
|
|
|
|
case PROTOBUF_C_TYPE_SFIXED32:
|
|
|
|
return pb_msg_int32x;
|
|
|
|
case PROTOBUF_C_TYPE_INT64:
|
|
|
|
case PROTOBUF_C_TYPE_SINT64:
|
|
|
|
case PROTOBUF_C_TYPE_SFIXED64:
|
|
|
|
case PROTOBUF_C_TYPE_FIXED32:
|
|
|
|
case PROTOBUF_C_TYPE_UINT64:
|
|
|
|
case PROTOBUF_C_TYPE_FIXED64:
|
2013-10-17 14:48:05 +04:00
|
|
|
return (label == PROTOBUF_C_LABEL_REPEATED ?
|
|
|
|
pb_msg_int64x_r : pb_msg_int64x);
|
2012-08-14 14:46:49 +04:00
|
|
|
case PROTOBUF_C_TYPE_STRING:
|
|
|
|
return pb_msg_string;
|
|
|
|
case PROTOBUF_C_TYPE_MESSAGE:
|
|
|
|
return show_nested_message;
|
|
|
|
case PROTOBUF_C_TYPE_ENUM:
|
|
|
|
return show_enum;
|
2012-08-15 20:53:35 +04:00
|
|
|
case PROTOBUF_C_TYPE_BOOL:
|
|
|
|
return show_bool;
|
2012-08-21 16:27:14 +04:00
|
|
|
case PROTOBUF_C_TYPE_BYTES:
|
|
|
|
return show_bytes;
|
2012-08-14 14:46:49 +04:00
|
|
|
case PROTOBUF_C_TYPE_FLOAT:
|
|
|
|
case PROTOBUF_C_TYPE_DOUBLE:
|
2012-08-15 20:53:35 +04:00
|
|
|
break;
|
2012-08-14 14:46:49 +04:00
|
|
|
default:
|
|
|
|
BUG();
|
|
|
|
}
|
|
|
|
return pb_msg_unk;
|
|
|
|
}
|
|
|
|
|
2013-05-14 14:30:10 +04:00
|
|
|
static pb_pr_show_t get_show_function(const ProtobufCFieldDescriptor *fd, pb_pr_ctl_t *ctl)
|
2012-08-14 14:49:21 +04:00
|
|
|
{
|
2013-05-14 14:30:10 +04:00
|
|
|
if (pb_field_show_pretty(fd, ctl))
|
2012-08-14 14:49:21 +04:00
|
|
|
return pb_show_pretty;
|
2013-10-17 14:48:05 +04:00
|
|
|
return get_pb_show_function(fd->type, fd->label);
|
2012-08-14 14:49:21 +04:00
|
|
|
}
|
|
|
|
|
2012-08-14 14:47:03 +04:00
|
|
|
static void pb_show_repeated(pb_pr_ctl_t *ctl, int nr_fields, pb_pr_show_t show,
|
2012-08-14 14:49:21 +04:00
|
|
|
size_t fsize)
|
2012-07-18 13:04:00 +04:00
|
|
|
{
|
2012-08-14 14:45:47 +04:00
|
|
|
pb_pr_field_t *field = &ctl->cur;
|
2012-07-18 13:04:00 +04:00
|
|
|
unsigned long counter;
|
2012-08-14 14:49:21 +04:00
|
|
|
int done;
|
|
|
|
|
2012-11-06 16:46:42 +04:00
|
|
|
if (nr_fields == 0) {
|
|
|
|
pr_msg("<empty>");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-08-14 14:49:21 +04:00
|
|
|
field->count = nr_fields;
|
|
|
|
done = show(field);
|
|
|
|
if (done)
|
|
|
|
return;
|
2012-07-18 13:04:00 +04:00
|
|
|
|
2012-08-14 14:45:47 +04:00
|
|
|
field->data += fsize;
|
2012-07-18 13:04:00 +04:00
|
|
|
|
2012-08-14 14:45:47 +04:00
|
|
|
for (counter = 0; counter < nr_fields - 1; counter++, field->data += fsize) {
|
2012-07-18 13:04:00 +04:00
|
|
|
pr_msg(":");
|
2012-08-14 14:47:40 +04:00
|
|
|
show(field);
|
2012-07-18 13:04:00 +04:00
|
|
|
}
|
2012-08-14 14:47:03 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void pb_show_field(const ProtobufCFieldDescriptor *fd,
|
|
|
|
int nr_fields, pb_pr_ctl_t *ctl)
|
|
|
|
{
|
|
|
|
pb_pr_show_t show;
|
|
|
|
|
|
|
|
print_tabs(ctl);
|
|
|
|
pr_msg("%s: ", fd->name);
|
|
|
|
|
2013-05-14 14:30:10 +04:00
|
|
|
show = get_show_function(fd, ctl);
|
2012-08-14 14:47:03 +04:00
|
|
|
|
|
|
|
pb_show_repeated(ctl, nr_fields, show, pb_show_prepare_field_context(fd, ctl));
|
2012-07-18 13:04:00 +04:00
|
|
|
|
2012-07-25 18:28:14 +04:00
|
|
|
if (ctl->single_entry)
|
|
|
|
pr_msg("\n");
|
|
|
|
else
|
|
|
|
pr_msg(" ");
|
2012-07-18 13:04:00 +04:00
|
|
|
}
|
|
|
|
|
2012-07-25 18:28:15 +04:00
|
|
|
static int pb_optional_field_present(const ProtobufCFieldDescriptor *field,
|
2012-08-09 22:40:18 +04:00
|
|
|
const void *msg)
|
2012-07-25 18:28:15 +04:00
|
|
|
{
|
|
|
|
if ((field->type == PROTOBUF_C_TYPE_MESSAGE) ||
|
|
|
|
(field->type == PROTOBUF_C_TYPE_STRING)) {
|
|
|
|
const void *opt_flag = * (const void * const *)(msg + field->offset);
|
|
|
|
|
|
|
|
if ((opt_flag == NULL) || (opt_flag == field->default_value))
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
const protobuf_c_boolean *has = msg + field->quantifier_offset;
|
|
|
|
|
|
|
|
if (!*has)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2013-12-27 15:58:27 +04:00
|
|
|
static bool should_show_field(const char *name)
|
|
|
|
{
|
|
|
|
char *s, *e;
|
|
|
|
int len;
|
|
|
|
|
|
|
|
if (!opts.show_fmt)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
len = strlen(name);
|
|
|
|
s = opts.show_fmt;
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
e = strchrnul(s, ',');
|
|
|
|
if (e - s == len) {
|
|
|
|
if (!strncmp(name, s, len))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (*e == '\0')
|
|
|
|
return false;
|
|
|
|
s = e + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-25 18:28:12 +04:00
|
|
|
static void pb_show_msg(const void *msg, pb_pr_ctl_t *ctl)
|
2012-07-18 13:04:00 +04:00
|
|
|
{
|
|
|
|
int i;
|
2012-07-25 18:28:12 +04:00
|
|
|
const ProtobufCMessageDescriptor *md = ctl->arg;
|
2012-07-18 13:04:00 +04:00
|
|
|
|
|
|
|
BUG_ON(md == NULL);
|
|
|
|
|
|
|
|
for (i = 0; i < md->n_fields; i++) {
|
|
|
|
const ProtobufCFieldDescriptor fd = md->fields[i];
|
|
|
|
unsigned long *data;
|
|
|
|
size_t nr_fields;
|
|
|
|
|
|
|
|
nr_fields = 1;
|
|
|
|
data = (unsigned long *)(msg + fd.offset);
|
|
|
|
|
2012-07-25 18:28:15 +04:00
|
|
|
if (fd.label == PROTOBUF_C_LABEL_OPTIONAL) {
|
2012-08-09 22:40:18 +04:00
|
|
|
if (!pb_optional_field_present(&fd, msg))
|
2012-07-25 18:28:15 +04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2013-12-27 15:58:27 +04:00
|
|
|
if (!should_show_field(fd.name))
|
|
|
|
continue;
|
|
|
|
|
2012-07-18 13:04:00 +04:00
|
|
|
if (fd.label == PROTOBUF_C_LABEL_REPEATED) {
|
|
|
|
nr_fields = *(size_t *)(msg + fd.quantifier_offset);
|
|
|
|
data = (unsigned long *)*data;
|
|
|
|
}
|
|
|
|
|
2012-08-14 14:45:47 +04:00
|
|
|
ctl->cur.data = data;
|
2012-08-14 14:49:21 +04:00
|
|
|
ctl->cur.number = i + 1;
|
2012-08-14 14:45:47 +04:00
|
|
|
|
|
|
|
pb_show_field(&fd, nr_fields, ctl);
|
2012-07-18 13:04:00 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-08 00:00:24 +04:00
|
|
|
static inline void pb_no_payload(int fd, void *obj) { }
|
2012-07-25 18:32:41 +04:00
|
|
|
|
2012-08-07 02:51:34 +04:00
|
|
|
void do_pb_show_plain(int fd, int type, int single_entry,
|
2013-05-08 00:00:24 +04:00
|
|
|
void (*payload_hadler)(int fd, void *obj),
|
|
|
|
const char *pretty_fmt)
|
2012-07-18 19:09:51 +04:00
|
|
|
{
|
2012-08-14 14:49:21 +04:00
|
|
|
pb_pr_ctl_t ctl = {NULL, single_entry, pretty_fmt};
|
2013-05-08 00:00:24 +04:00
|
|
|
void (*handle_payload)(int fd, void *obj);
|
2012-07-26 12:43:00 +04:00
|
|
|
|
2012-08-07 02:51:34 +04:00
|
|
|
if (!cr_pb_descs[type].pb_desc) {
|
|
|
|
pr_err("Wrong object requested %d\n", type);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-07-26 12:43:00 +04:00
|
|
|
handle_payload = (payload_hadler) ? : pb_no_payload;
|
2012-07-25 18:28:12 +04:00
|
|
|
|
2012-07-18 19:09:51 +04:00
|
|
|
while (1) {
|
|
|
|
void *obj;
|
|
|
|
|
2012-08-07 02:51:34 +04:00
|
|
|
if (pb_read_one_eof(fd, &obj, type) <= 0)
|
2012-07-18 19:09:51 +04:00
|
|
|
break;
|
|
|
|
|
2012-08-07 02:51:34 +04:00
|
|
|
ctl.arg = (void *)cr_pb_descs[type].pb_desc;
|
2012-07-25 18:28:12 +04:00
|
|
|
pb_show_msg(obj, &ctl);
|
2013-05-08 00:00:24 +04:00
|
|
|
handle_payload(fd, obj);
|
2012-08-07 02:51:34 +04:00
|
|
|
cr_pb_descs[type].free(obj, NULL);
|
2012-07-25 18:28:14 +04:00
|
|
|
if (single_entry)
|
|
|
|
break;
|
|
|
|
pr_msg("\n");
|
2012-07-18 19:09:51 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-15 15:03:17 +04:00
|
|
|
static char *image_name(int fd)
|
|
|
|
{
|
|
|
|
static char image_path[PATH_MAX];
|
|
|
|
|
2013-05-07 19:01:24 +04:00
|
|
|
if (read_fd_link(fd, image_path, sizeof(image_path)) > 0)
|
2013-03-15 15:03:17 +04:00
|
|
|
return image_path;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-07-17 07:00:18 +04:00
|
|
|
/*
|
|
|
|
* Reads PB record (header + packed object) from file @fd and unpack
|
|
|
|
* it with @unpack procedure to the pointer @pobj
|
|
|
|
*
|
|
|
|
* 1 on success
|
|
|
|
* -1 on error (or EOF met and @eof set to false)
|
|
|
|
* 0 on EOF and @eof set to true
|
|
|
|
*
|
|
|
|
* Don't forget to free memory granted to unpacked object in calling code if needed
|
|
|
|
*/
|
2012-08-07 02:51:34 +04:00
|
|
|
|
|
|
|
int do_pb_read_one(int fd, void **pobj, int type, bool eof)
|
2012-07-17 07:00:18 +04:00
|
|
|
{
|
|
|
|
u8 local[PB_PKOBJ_LOCAL_SIZE];
|
|
|
|
void *buf = (void *)&local;
|
|
|
|
u32 size;
|
|
|
|
int ret;
|
|
|
|
|
2012-08-07 02:51:34 +04:00
|
|
|
if (!cr_pb_descs[type].pb_desc) {
|
2013-03-15 15:03:17 +04:00
|
|
|
pr_err("Wrong object requested %d on %s\n",
|
|
|
|
type, image_name(fd));
|
2012-08-07 02:51:34 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-07-17 07:00:18 +04:00
|
|
|
*pobj = NULL;
|
|
|
|
|
|
|
|
ret = read(fd, &size, sizeof(size));
|
|
|
|
if (ret == 0) {
|
|
|
|
if (eof) {
|
|
|
|
return 0;
|
|
|
|
} else {
|
2013-03-15 15:03:17 +04:00
|
|
|
pr_err("Unexpected EOF on %s\n",
|
|
|
|
image_name(fd));
|
2012-07-17 07:00:18 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else if (ret < sizeof(size)) {
|
2013-03-15 15:03:17 +04:00
|
|
|
pr_perror("Read %d bytes while %d expected on %s",
|
|
|
|
ret, (int)sizeof(size),
|
|
|
|
image_name(fd));
|
2012-07-17 07:00:18 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (size > sizeof(local)) {
|
|
|
|
ret = -1;
|
|
|
|
buf = xmalloc(size);
|
|
|
|
if (!buf)
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = read(fd, buf, size);
|
|
|
|
if (ret < 0) {
|
2013-03-15 15:03:17 +04:00
|
|
|
pr_perror("Can't read %d bytes from file %s",
|
|
|
|
size, image_name(fd));
|
2012-07-17 07:00:18 +04:00
|
|
|
goto err;
|
|
|
|
} else if (ret != size) {
|
2013-03-15 15:03:17 +04:00
|
|
|
pr_perror("Read %d bytes while %d expected from %s",
|
|
|
|
ret, size, image_name(fd));
|
2012-11-11 13:28:25 +04:00
|
|
|
ret = -1;
|
2012-07-17 07:00:18 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2012-08-07 02:51:34 +04:00
|
|
|
*pobj = cr_pb_descs[type].unpack(NULL, size, buf);
|
2012-07-17 07:00:18 +04:00
|
|
|
if (!*pobj) {
|
|
|
|
ret = -1;
|
2013-03-15 15:03:17 +04:00
|
|
|
pr_err("Failed unpacking object %p from %s\n",
|
|
|
|
pobj, image_name(fd));
|
2012-07-17 07:00:18 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 1;
|
|
|
|
err:
|
|
|
|
if (buf != (void *)&local)
|
|
|
|
xfree(buf);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Writes PB record (header + packed object pointed by @obj)
|
|
|
|
* to file @fd, using @getpksize to get packed size and @pack
|
|
|
|
* to implement packing
|
|
|
|
*
|
|
|
|
* 0 on success
|
|
|
|
* -1 on error
|
|
|
|
*/
|
2012-08-07 02:26:50 +04:00
|
|
|
int pb_write_one(int fd, void *obj, int type)
|
2012-07-17 07:00:18 +04:00
|
|
|
{
|
|
|
|
u8 local[PB_PKOBJ_LOCAL_SIZE];
|
|
|
|
void *buf = (void *)&local;
|
|
|
|
u32 size, packed;
|
|
|
|
int ret = -1;
|
2014-01-31 20:51:32 +04:00
|
|
|
struct iovec iov[2];
|
2012-07-17 07:00:18 +04:00
|
|
|
|
2012-08-07 02:26:50 +04:00
|
|
|
if (!cr_pb_descs[type].pb_desc) {
|
2012-10-03 16:04:48 +04:00
|
|
|
pr_err("Wrong object requested %d\n", type);
|
2012-08-07 02:26:50 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
size = cr_pb_descs[type].getpksize(obj);
|
2012-07-17 07:00:18 +04:00
|
|
|
if (size > (u32)sizeof(local)) {
|
|
|
|
buf = xmalloc(size);
|
|
|
|
if (!buf)
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2012-08-07 02:26:50 +04:00
|
|
|
packed = cr_pb_descs[type].pack(obj, buf);
|
2012-07-17 07:00:18 +04:00
|
|
|
if (packed != size) {
|
|
|
|
pr_err("Failed packing PB object %p\n", obj);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2014-01-31 20:51:32 +04:00
|
|
|
iov[0].iov_base = &size;
|
|
|
|
iov[0].iov_len = sizeof(size);
|
|
|
|
iov[1].iov_base = buf;
|
|
|
|
iov[1].iov_len = size;
|
2012-07-17 07:00:18 +04:00
|
|
|
|
2014-01-31 20:51:32 +04:00
|
|
|
ret = writev(fd, iov, 2);
|
|
|
|
if (ret != size + sizeof(size)) {
|
|
|
|
pr_perror("Can't write %d bytes", (int)(size + sizeof(size)));
|
2012-07-17 07:00:18 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
err:
|
|
|
|
if (buf != (void *)&local)
|
|
|
|
xfree(buf);
|
|
|
|
return ret;
|
|
|
|
}
|
2012-08-09 13:16:46 +04:00
|
|
|
|
2013-08-21 03:27:06 +04:00
|
|
|
int collect_image(struct collect_image_info *cinfo)
|
2012-08-09 13:16:46 +04:00
|
|
|
{
|
|
|
|
int fd, ret;
|
2013-08-21 03:27:06 +04:00
|
|
|
void *(*o_alloc)(size_t size) = malloc;
|
|
|
|
void (*o_free)(void *ptr) = free;
|
2012-08-09 13:16:46 +04:00
|
|
|
|
2013-08-21 03:27:06 +04:00
|
|
|
pr_info("Collecting %d/%d (flags %x)\n",
|
|
|
|
cinfo->fd_type, cinfo->pb_type, cinfo->flags);
|
|
|
|
|
|
|
|
fd = open_image(cinfo->fd_type, O_RSTR);
|
|
|
|
if (fd < 0) {
|
|
|
|
if ((cinfo->flags & COLLECT_OPTIONAL) && (errno == ENOENT))
|
|
|
|
return 0;
|
|
|
|
else
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cinfo->flags & COLLECT_SHARED) {
|
|
|
|
o_alloc = shmalloc;
|
|
|
|
o_free = shfree_last;
|
|
|
|
}
|
2012-08-09 13:16:46 +04:00
|
|
|
|
|
|
|
while (1) {
|
|
|
|
void *obj;
|
|
|
|
ProtobufCMessage *msg;
|
|
|
|
|
2013-08-21 03:27:06 +04:00
|
|
|
if (cinfo->priv_size) {
|
2012-08-09 13:16:46 +04:00
|
|
|
ret = -1;
|
2013-08-21 03:27:06 +04:00
|
|
|
obj = o_alloc(cinfo->priv_size);
|
2012-08-09 13:16:46 +04:00
|
|
|
if (!obj)
|
|
|
|
break;
|
|
|
|
} else
|
|
|
|
obj = NULL;
|
|
|
|
|
2013-08-21 03:27:06 +04:00
|
|
|
ret = pb_read_one_eof(fd, &msg, cinfo->pb_type);
|
2012-08-09 13:16:46 +04:00
|
|
|
if (ret <= 0) {
|
2013-08-21 03:27:06 +04:00
|
|
|
o_free(obj);
|
2012-08-09 13:16:46 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-08-21 03:27:06 +04:00
|
|
|
ret = cinfo->collect(obj, msg);
|
2012-08-09 13:16:46 +04:00
|
|
|
if (ret < 0) {
|
2013-08-21 03:27:06 +04:00
|
|
|
o_free(obj);
|
|
|
|
cr_pb_descs[cinfo->pb_type].free(msg, NULL);
|
2012-08-09 13:16:46 +04:00
|
|
|
break;
|
|
|
|
}
|
2013-08-20 03:22:38 +04:00
|
|
|
|
2013-08-21 03:27:06 +04:00
|
|
|
if (!cinfo->priv_size)
|
|
|
|
cr_pb_descs[cinfo->pb_type].free(msg, NULL);
|
2012-08-09 13:16:46 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
close(fd);
|
2013-08-21 03:27:06 +04:00
|
|
|
pr_debug(" `- ... done\n");
|
2012-08-09 13:16:46 +04:00
|
|
|
return ret;
|
|
|
|
}
|