Motr  M0
index_parser.c
Go to the documentation of this file.
1 /* -*- C -*- */
2 /*
3  * Copyright (c) 2016-2020 Seagate Technology LLC and/or its Affiliates
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * For any questions about this software or licensing,
18  * please email opensource@seagate.com or cortx-questions@seagate.com.
19  *
20  */
21 
22 
23 
30 #define M0_TRACE_SUBSYSTEM M0_TRACE_SUBSYS_CLIENT
31 #include <string.h>
32 #include <stdio.h> /* FILE */
33 #include <stdlib.h> /* strtol */
34 #include "lib/errno.h"
35 #include "lib/assert.h"
36 #include "lib/memory.h"
37 #include "lib/trace.h" /* M0_ERR */
38 #include "lib/buf_xc.h"
39 #include "xcode/xcode.h" /* m0_xcode_read */
40 #include "lib/string.h" /* m0_fop_str */
41 #include "lib/user_space/misc.h" /* ARRAY_SIZE */
42 #include "index_parser.h"
43 #include "common.h"
44 #include "index.h"
45 
46 struct command_descr {
47  int cd_id;
48  const char *cd_name;
49  const char *cd_help_descr;
50 };
51 
52 static const struct command_descr commands[] = {
53  { CRT, "create", "create FID_PARAM, create index" },
54  { DRP, "drop", "drop FID_PARAM, drop existing index"},
55  { LST, "list", "list FID NUM, get indicies" },
56  { LKP, "lookup", "lookup FID_PARAM, lookup index in storage" },
57  { PUT, "put", "put FID_PARAM KEY_PARAM VAL_PARAM, put record" },
58  { DEL, "del", "del FID_PARAM KEY_PARAM, delete record" },
59  { GET, "get", "get FID KEY_PARAM, lookup and returns values by key" },
60  { NXT, "next", "next FID KEY CNT, returns records larger than KEY " },
61  { GENF, "genf", "genf CNT FILE, generate file with several FID" },
62  { GENV, "genv", "genv CNT SIZE FILE, generate file with several "
63  "KEY_PARAM/VAL_PARAM. Note: SIZE > 16" },
64 };
65 
66 static int command_id(const char *name)
67 {
68  int i;
69 
70  for (i = 0; i < ARRAY_SIZE(commands); ++i) {
71  if (!strcmp(name, commands[i].cd_name))
72  return commands[i].cd_id;
73  }
74  return M0_ERR(-EINVAL);
75 }
76 
77 static int file_lines_count(const char *filename)
78 {
79  FILE *f;
80  int c;
81  int count = 0;
82 
83  f = fopen(filename, "r");
84  if (f == NULL)
85  return M0_ERR(-errno);
86  while ((c = fgetc(f)) != EOF) {
87  if (c == '\n' )
88  count++;
89  }
90  fclose(f);
91  return count;
92 }
93 
94 static int fids_load(const char *val, struct m0_fid_arr *fids)
95 {
96  FILE *f;
97  int i;
98  int rc;
99  char buf[255];
100  int fids_nr;
101 
102  if (val == NULL)
103  return -EINVAL;
104  /* Create array for fids. */
105  fids_nr = val[0] == '@' ? file_lines_count(&val[1]) : 1;
106  if (fids_nr < 0)
107  return M0_ERR(fids_nr);
108  M0_ALLOC_ARR(fids->af_elems, fids_nr);
109  fids->af_count = fids_nr;
110  if (fids->af_elems == NULL)
111  return M0_ERR(-ENOMEM);
112  if (val[0] == '@') {
113  /* CmdLine contains FID-FILE value. */
114  f = fopen(&val[1], "r");
115  if (f == NULL)
116  return M0_ERR(-errno);
117  rc = 0;
118  for (i = 0; i < fids_nr && rc == 0 &&
119  fgets(buf, sizeof buf, f) != NULL;
120  ++i) {
121  rc = m0_fid_sscanf(buf, &fids->af_elems[i]);
122  }
123  fclose(f);
124  } else {
125  /* CmdLine contains FID value. */
126  rc = m0_fid_sscanf(&val[0], &fids->af_elems[0]);
127  }
128  return rc;
129 }
130 
131 static int vals_xcode(const char *value, void *buf, m0_bcount_t *size)
132 {
133  struct m0_buf tmp_buf;
134  int rc;
135 
136  tmp_buf.b_addr = buf;
137  tmp_buf.b_nob = 0;
138  rc = m0_xcode_read(&M0_XCODE_OBJ(m0_buf_xc, &tmp_buf), value);
139  *size= tmp_buf.b_nob;
140  return rc;
141 }
142 
143 static int item_load(FILE *f, char **item, int *size)
144 {
145  char buf[100];
146  char *next;
147  char *target;
148  int pos;
149 
150  if (fgets(buf, sizeof buf, f) == NULL)
151  return 1;
152  /* Get first int value from buffer - it's a size of payload. */
153  *size = strtol(buf, &next, 0);
154  if (*size == 0)
155  return M0_ERR(-EPROTO);
156  next++;
157  pos = next - &buf[0] + 1;
158  /* Allocate buffer and load whole value from file. */
159  *item = target = m0_alloc(*size * 2);
160  if (target == NULL)
161  return M0_ERR(-ENOMEM);
162  if (*size >= sizeof buf) {
163  memcpy(target, next, sizeof buf - pos);
164  /* Addition file operation for load whole value. */
165  if (fgets(target + (sizeof buf - pos),
166  *size - (sizeof buf - pos) + 2, f) == NULL)
167  return -1;
168  } else {
169  memcpy(target, next, *size - pos);
170  }
171  return 0;
172 }
173 
174 static int vals_load(const char *value, struct m0_bufvec *vals)
175 {
176  FILE *f;
177  int vals_nr;
178  int i;
179  int rc;
180  int size;
181  char *buf;
182  int keylen;
183 
184  if (value == NULL || (strlen(value) == 0))
185  return M0_ERR(-EINVAL);
186  vals_nr = value[0] == '@' ? file_lines_count(&value[1]) : 1;
187  if (vals_nr < 0)
188  return vals_nr;
189  rc = m0_bufvec_empty_alloc(vals, vals_nr);
190  if (rc < 0)
191  return M0_ERR(rc);
192  if (value[0] == '@') {
193  /* CmdLine contains VAL-FILE value. */
194  f = fopen(&value[1], "r");
195  if (f == NULL)
196  return M0_ERR(-errno);
197  rc = 0;
198  buf = NULL;
199  for (i = 0; rc == 0 && i < vals_nr &&
200  (rc = item_load(f, &buf, &size)) == 0;
201  ++i) {
202  vals->ov_buf[i] = m0_alloc(size);
203  rc = vals_xcode(buf, vals->ov_buf[i],
204  &vals->ov_vec.v_count[i]);
205  m0_free(buf);
206  }
207  /* Drop rc==1 to zero. */
208  rc = (rc == 1) ? 0 : rc;
209  fclose(f);
210  } else {
211  /* CmdLine contains VAL. */
212  keylen = strlen(value);
213  vals->ov_buf[0] = m0_alloc(keylen);
214  if (vals->ov_buf[0] == NULL)
215  return M0_ERR(-errno);
216 
217  if (is_str) {
218  memcpy(vals->ov_buf[0], value, keylen);
219  vals->ov_vec.v_count[0] = keylen;
220  vals->ov_vec.v_nr = 1;
221  } else {
222  rc = vals_xcode(&value[0], vals->ov_buf[0],
223  &vals->ov_vec.v_count[0]);
224  }
225  }
226  return rc;
227 }
228 
229 static int command_assign(struct index_cmd *cmd, int *argc, char ***argv)
230 {
231  char ***params;
232  int rc;
233 
234  params = argv;
235  rc = command_id(**params);
236  if (rc < 0 )
237  return M0_ERR(rc);
238  ++*params;
239  --*argc;
240  cmd->ic_cmd = rc;
241  rc = 0;
242  switch (cmd->ic_cmd) {
243  case CRT:
244  case DRP:
245  case LKP:
246  rc = fids_load(**params, &cmd->ic_fids);
247  ++*params;
248  --*argc;
249  break;
250  case LST:
251  /* Check start and cnt params in cmdline. */
252  if (**params == NULL)
253  rc = M0_ERR(-EINVAL);
254  else {
255  rc = fids_load(**params, &cmd->ic_fids);
256  ++*params;
257  --*argc;
258  }
259  if (rc != 0 || **params == NULL)
260  rc = M0_ERR(-EINVAL);
261  else {
262  cmd->ic_cnt = strtol(**params, (char **)(NULL), 10);
263  rc = cmd->ic_cnt == 0 ? M0_ERR(-EINVAL) : 0;
264  }
265  ++*params;
266  --*argc;
267  break;
268  case PUT:
269  if (*argc < 3)
270  return M0_ERR(-EINVAL);
271  rc = fids_load(**params, &cmd->ic_fids);
272  if (rc < 0)
273  return M0_ERR(rc);
274  ++*params;
275  rc = vals_load(**params, &cmd->ic_keys);
276  if (rc < 0)
277  return M0_ERR(rc);
278  ++*params;
279  rc = vals_load(**params, &cmd->ic_vals);
280  if (rc < 0)
281  return M0_ERR(rc);
282  ++*params;
283  *argc -= 3;
284  break;
285  case DEL:
286  if (*argc < 2)
287  return M0_ERR(-EINVAL);
288  rc = fids_load(**params, &cmd->ic_fids);
289  ++*params;
290  if (rc < 0)
291  return M0_ERR(rc);
292  rc = vals_load(**params, &cmd->ic_keys);
293  if (rc < 0)
294  return M0_ERR(rc);
295  ++*params;
296  *argc -= 2;
297  break;
298  case GET:
299  if (*argc < 2)
300  return M0_ERR(-EINVAL);
301  if (**params[0]=='@')
302  return M0_ERR(-EINVAL);
303  rc = fids_load(**params, &cmd->ic_fids);
304  ++*params;
305  if (rc < 0)
306  return M0_ERR(rc);
307  rc = vals_load(**params, &cmd->ic_keys);
308  if (rc < 0)
309  return M0_ERR(rc);
310  ++*params;
311  *argc -= 2;
312  break;
313  case NXT:
314  if (*argc < 3)
315  return M0_ERR(-EINVAL);
316  if (**params[0]=='@')
317  return M0_ERR(-EINVAL);
318  rc = fids_load(**params, &cmd->ic_fids);
319  ++*params;
320  --*argc;
321  if (rc < 0)
322  return M0_ERR(rc);
323  if (**params[0]=='@')
324  return M0_ERR(-EINVAL);
325  rc = vals_load(**params, &cmd->ic_keys);
326  if (rc < 0)
327  return M0_ERR(rc);
328  ++*params;
329  --*argc;
330  cmd->ic_cnt = strtol(**params,
331  (char **)(NULL), 10);
332  rc = cmd->ic_cnt == 0 ? M0_ERR(-EINVAL) : 0;
333  ++*params;
334  --*argc;
335  break;
336  case GENF:
337  if (*argc < 2)
338  return M0_ERR(-EINVAL);
339  cmd->ic_cnt = strtol(**params, (char **)(NULL), 10);
340  rc = cmd->ic_cnt == 0 ? M0_ERR(-EINVAL) : 0;
341  ++*params;
342  if (rc < 0)
343  return rc;
344  cmd->ic_filename = **params;
345  ++*params;
346  *argc -= 2;
347  break;
348  case GENV:
349  if (*argc < 3)
350  return M0_ERR(-EINVAL);
351  cmd->ic_cnt = strtol(**params, (char **)(NULL), 10);
352  rc = cmd->ic_cnt == 0 ? M0_ERR(-EINVAL) : 0;
353  ++*params;
354  if (rc < 0)
355  return rc;
356  cmd->ic_len = strtol(**params, (char **)(NULL), 10);
357  rc = cmd->ic_len == 0 ? M0_ERR(-EINVAL) : 0;
358  ++*params;
359  if (rc < 0)
360  return rc;
361  cmd->ic_filename = **params;
362  ++*params;
363  *argc -= 3;
364  break;
365  default:
366  M0_IMPOSSIBLE("Wrong command");
367  }
368  *argv = *params;
369  return rc;
370 }
371 
372 static bool command_is_valid(struct index_cmd *cmd)
373 {
374  bool rc;
375 
376  switch(cmd->ic_cmd) {
377  case CRT:
378  case DRP:
379  case LKP:
380  rc = cmd->ic_fids.af_count != 0;
381  break;
382  case LST:
383  /* Do nothing: fids and CNT can be absent. */
384  rc = true;
385  break;
386  case PUT:
387  rc = cmd->ic_fids.af_count != 0 &&
388  cmd->ic_keys.ov_vec.v_nr != 0 &&
389  cmd->ic_keys.ov_vec.v_nr == cmd->ic_vals.ov_vec.v_nr;
390  break;
391  case DEL:
392  rc = cmd->ic_fids.af_count != 0 &&
393  cmd->ic_keys.ov_vec.v_nr != 0;
394  break;
395  case GET:
396  rc = cmd->ic_fids.af_count == 1 &&
397  cmd->ic_keys.ov_vec.v_nr != 0;
398  break;
399  case NXT:
400  rc = cmd->ic_fids.af_count == 1 &&
401  cmd->ic_keys.ov_vec.v_nr == 1 &&
402  cmd->ic_cnt != 0;
403  break;
404  case GENF:
405  rc = cmd->ic_filename != NULL && cmd->ic_cnt != 0;
406  break;
407  case GENV:
408  rc = cmd->ic_filename != NULL &&
409  cmd->ic_cnt != 0 &&
410  cmd->ic_len != 0;
411  break;
412  default:
413  M0_IMPOSSIBLE("Wrong command.");
414  }
415  return rc;
416 }
417 
418 int index_parser_args_process(struct index_ctx *ctx, int argc, char **argv)
419 {
420  char **params;
421  int i;
422  int rc;
423 
424  if (argc < 2 )
425  return M0_ERR(-EINVAL);
426  params = &argv[0];
427  i = 0;
428  do {
429  rc = command_assign(&ctx->ictx_cmd[i], &argc, &params);
430  if (rc == 0)
431  if(!command_is_valid(&ctx->ictx_cmd[i]))
432  rc = -EINVAL;
433  ++i;
434  } while (argc != 0 && *params != NULL &&
435  rc == 0 && i < INDEX_CMD_COUNT);
436  if (rc == 0)
437  ctx->ictx_nr = i;
438  else
439  m0_console_printf("Invalid params for [%s]\n",
440  commands[ctx->ictx_cmd[i-1].ic_cmd].cd_name);
441  return rc;
442 }
443 
445 {
446  int i;
447 
448  for (i = 0; i < ARRAY_SIZE(commands); ++i)
449  if (commands[i].cd_help_descr != NULL)
450  m0_console_printf("\t -'%s'\n",
451  commands[i].cd_help_descr);
453  "\tNOTE:\n"
454  "\t- FID_PARAM - single FID value or @FIDFILENAME\n"
455  "\t- KEY_PARAM - single KEY value or @VFILENAME\n"
456  "\t- VAL_PARAM - single VALUE param or @VFILENAME\n"
457  "\t- FID - value in m0_fid_sscanf format, "
458  "e.g. '<0x780000000000000b:1>', '1:5' and etc\n"
459  "\t- KEY or VALUE - value in m0_xcode_read format, e.g. "
460  "'[0xa:0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a]'\n"
461  "\tExample: \n"
462  "\t\t>m0kv [common args] index create \"1:5\" \n"
463  "\t\t>m0kv [common args] index list \"1:5\" 2 \n"
464  "\t\t>m0kv [common args] index genf 10 fid.txt \n"
465  "\t\t>m0kv [common args] index genv 10 20 keys.txt \n"
466  "\t\t>m0kv [common args] index genv 10 20 vals.txt \n"
467  "\t\t>m0kv [common args] index put \"1:5\" @keys.txt "
468  "@vals.txt \n"
469  "\t\t>m0kv [common args] index get \"1:5\" @keys.txt \n"
470  "\t\t>m0kv [common args] index next \"1:5\" "
471  "'[0x02:0x01,0x02]' 3 \n"
472  "\t\t>m0kv [common args] index next \"1:5\" \"0\" 3 -s \n"
473  "\tPossible to supply multiple commands on command line e.g.:\n"
474  "\t\t>m0kv [common args] index create \"1:5\" put \"1:5\""
475  " \"[0x02:0x01,0x02]\" \"[0x09:0x01,0x02,0x03,0x04,0x05,0x06,"
476  "0x07,0x08,0x09]\"\n"
477  "\t\t>m0kv [common args] index drop \"1:5\" create \"1:5\" "
478  "put \"1:5\" @keys.txt @vals.txt\n"
479  "\t\t>m0kv [common args] -s index put \"1:5\" \"Department\" "
480  "\"Testing\" \n"
481  "\t\tNote: If key already exists put over-write the old value.\n"
482  "\t\t>m0kv [common args] -s index get \"1:5\" \"Department\" "
483  "\n");
484 }
485 
486 #undef M0_TRACE_SUBSYSTEM
487 
490 /*
491  * Local variables:
492  * c-indentation-style: "K&R"
493  * c-basic-offset: 8
494  * tab-width: 8
495  * fill-column: 80
496  * scroll-step: 1
497  * End:
498  */
499 /*
500  * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap
501  */
static const struct command_descr commands[]
Definition: index_parser.c:52
#define M0_ALLOC_ARR(arr, nr)
Definition: memory.h:84
Definition: index.h:38
#define NULL
Definition: misc.h:38
Definition: idx_mock.c:52
void * b_addr
Definition: buf.h:39
static FILE * f
Definition: adieu.c:79
M0_INTERNAL int m0_xcode_read(struct m0_xcode_obj *obj, const char *str)
Definition: string.c:162
void m0_console_printf(const char *fmt,...)
Definition: trace.c:801
static int fids_load(const char *val, struct m0_fid_arr *fids)
Definition: index_parser.c:94
struct m0_vec ov_vec
Definition: vec.h:147
int const char const void * value
Definition: dir.c:325
uint64_t m0_bcount_t
Definition: types.h:77
static int void * buf
Definition: dir.c:1019
Definition: index.h:37
static struct m0_rpc_item * item
Definition: item.c:56
static int command_id(const char *name)
Definition: index_parser.c:66
void ** ov_buf
Definition: vec.h:149
Definition: sock.c:887
static m0_bcount_t count
Definition: xcode.c:167
Definition: buf.h:37
int i
Definition: dir.c:1033
static struct nlx_ping_client_params * params
return M0_ERR(-EOPNOTSUPP)
static int item_load(FILE *f, char **item, int *size)
Definition: index_parser.c:143
const char * name
Definition: trace.c:110
Definition: parser.c:72
m0_bcount_t b_nob
Definition: buf.h:38
bool is_str
Definition: cmd_main.c:64
Definition: index.h:45
static struct m0_addb2_callback c
Definition: consumer.c:41
static int command_assign(struct index_cmd *cmd, int *argc, char ***argv)
Definition: index_parser.c:229
struct m0_bufvec ic_keys
Definition: index.h:57
int ic_cnt
Definition: index.h:59
static int next[]
Definition: cp.c:248
int ic_len
Definition: index.h:60
const char * cd_help_descr
Definition: index_parser.c:49
void * m0_alloc(size_t size)
Definition: memory.c:126
Definition: fid.h:43
uint32_t v_nr
Definition: vec.h:51
static const struct m0_fid fids[]
Definition: diter.c:76
m0_bcount_t * v_count
Definition: vec.h:53
M0_INTERNAL int m0_fid_sscanf(const char *s, struct m0_fid *fid)
Definition: fid.c:227
void index_parser_print_command_help(void)
Definition: index_parser.c:444
static int vals_load(const char *value, struct m0_bufvec *vals)
Definition: index_parser.c:174
Definition: index.h:46
Definition: common.h:34
m0_bcount_t size
Definition: di.c:39
Definition: index.h:40
Definition: index.h:44
static bool command_is_valid(struct index_cmd *cmd)
Definition: index_parser.c:372
#define M0_XCODE_OBJ(type, ptr)
Definition: xcode.h:962
Definition: index.h:39
char * ic_filename
Definition: index.h:61
Definition: nucleus.c:42
static int file_lines_count(const char *filename)
Definition: index_parser.c:77
static int vals_xcode(const char *value, void *buf, m0_bcount_t *size)
Definition: index_parser.c:131
void m0_free(void *data)
Definition: memory.c:146
int ic_cmd
Definition: index.h:55
struct m0_bufvec ic_vals
Definition: index.h:58
const char * cd_name
Definition: index_parser.c:48
int32_t rc
Definition: trigger_fop.h:47
#define ARRAY_SIZE(a)
Definition: misc.h:45
int index_parser_args_process(struct index_ctx *ctx, int argc, char **argv)
Definition: index_parser.c:418
uint32_t af_count
Definition: fid.h:44
struct m0_fid_arr ic_fids
Definition: index.h:56
struct m0_cob_domain_id cd_id
Definition: cob.h:2381
Definition: vec.h:145
M0_INTERNAL int m0_bufvec_empty_alloc(struct m0_bufvec *bufvec, uint32_t num_segs)
Definition: vec.c:213
#define M0_IMPOSSIBLE(fmt,...)