ipmi_cfgp.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542
  1. /*
  2. * Copyright (c) 2016 Pentair Technical Products. All right reserved
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * Redistribution of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. *
  11. * Redistribution in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. *
  15. * Neither the name of Pentair Technical Products or the names of
  16. * contributors may be used to endorse or promote products derived
  17. * from this software without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  22. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
  23. * PENTAIR TECHNICAL SOLUTIONS BE LIABLE FOR ANY DIRECT, INDIRECT,
  24. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  25. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  26. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  27. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  28. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  29. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  30. * POSSIBILITY OF SUCH DAMAGE.
  31. */
  32. #include <malloc.h>
  33. #include <string.h>
  34. #include <ipmitool/helper.h>
  35. #include <ipmitool/ipmi_cfgp.h>
  36. #include <ipmitool/log.h>
  37. /* ipmi_cfgp_init initialize configuration parameter context
  38. * @param ctx context to initialize
  39. * @param set array of parameter descriptors
  40. * @param count amount of descriptors supplied
  41. * @param handler function to do real job on parameters from the set
  42. * @param priv private data for the handler
  43. */
  44. int
  45. ipmi_cfgp_init(struct ipmi_cfgp_ctx *ctx, const struct ipmi_cfgp *set,
  46. unsigned int count, const char *cmdname,
  47. ipmi_cfgp_handler_t handler, void *priv)
  48. {
  49. if (ctx == NULL || set == NULL || handler == NULL || !cmdname) {
  50. return -1;
  51. }
  52. memset(ctx, 0, sizeof(struct ipmi_cfgp_ctx));
  53. ctx->set = set;
  54. ctx->count = count;
  55. ctx->cmdname = cmdname;
  56. ctx->handler = handler;
  57. ctx->priv = priv;
  58. return 0;
  59. }
  60. /* ipmi_cfgp_uninit destroy data list attached to context
  61. * @param ctx parameter context to clear
  62. * @returns 0 -- list destroyed
  63. * -1 -- ctx is NULL
  64. */
  65. int
  66. ipmi_cfgp_uninit(struct ipmi_cfgp_ctx *ctx)
  67. {
  68. struct ipmi_cfgp_data *d;
  69. if (ctx == NULL) {
  70. return -1;
  71. }
  72. while (ctx->v) {
  73. d = ctx->v;
  74. ctx->v = d->next;
  75. free(d);
  76. d = NULL;
  77. }
  78. return 0;
  79. }
  80. /* lookup_cfgp -- find a parameter in a set*/
  81. static const struct ipmi_cfgp *
  82. lookup_cfgp(const struct ipmi_cfgp_ctx *ctx, const char *name)
  83. {
  84. const struct ipmi_cfgp *p;
  85. int i;
  86. for (i = 0; i < ctx->count; i++) {
  87. p = &ctx->set[i];
  88. if (p->name && !strcasecmp(p->name, name)) {
  89. return p;
  90. }
  91. }
  92. return NULL;
  93. }
  94. /* ipmi_cfgp_parse_sel parse parameter selector
  95. * (parameter ID, set selector, block selector) from cmdline.
  96. *
  97. * @param ctx configuration parameter context to use
  98. * @param argc elements left in argv
  99. * @param argv array of arguments
  100. * @param sel where to store parsed selector
  101. *
  102. * @returns >=0 number of argv elements used
  103. * <0 error
  104. */
  105. int
  106. ipmi_cfgp_parse_sel(struct ipmi_cfgp_ctx *ctx,
  107. int argc, const char **argv, struct ipmi_cfgp_sel *sel)
  108. {
  109. const struct ipmi_cfgp *p;
  110. if (ctx == NULL || argv == NULL || sel == NULL) {
  111. return -1;
  112. }
  113. sel->param = -1;
  114. sel->set = -1;
  115. sel->block = -1;
  116. if (argc == 0) {
  117. /* no parameter specified, good for print, save */
  118. return 0;
  119. }
  120. p = lookup_cfgp(ctx, argv[0]);
  121. if (p == NULL) {
  122. lprintf(LOG_ERR, "invalid parameter");
  123. return -1;
  124. }
  125. sel->param = p - ctx->set;
  126. sel->set = p->is_set ? -1 : 0;
  127. sel->block = p->has_blocks ? -1 : 0;
  128. if (argc == 1 || !p->is_set) {
  129. /* No set and block selector applicable or specified */
  130. return 1;
  131. }
  132. if (str2int(argv[1], &sel->set)
  133. || sel->set < 0
  134. || (sel->set == 0 && p->first_set)) {
  135. lprintf(LOG_ERR, "invalid set selector");
  136. return -1;
  137. }
  138. if (argc == 2 || !p->has_blocks) {
  139. /* No block selector applicable or specified */
  140. return 2;
  141. }
  142. if (str2int(argv[2], &sel->block)
  143. || sel->block < 0
  144. || (sel->block == 0 && p->first_block)) {
  145. lprintf(LOG_ERR, "invalid block selector");
  146. return -1;
  147. }
  148. return 3;
  149. }
  150. /* cfgp_add_data adds block of data to list in the configuration
  151. * parameter context
  152. *
  153. * @param ctx context to add data to
  154. * @param data parameter data
  155. */
  156. static void
  157. cfgp_add_data(struct ipmi_cfgp_ctx *ctx, struct ipmi_cfgp_data *data)
  158. {
  159. struct ipmi_cfgp_data **pprev = &ctx->v;
  160. data->next = NULL;
  161. while (*pprev) {
  162. pprev = &(*pprev)->next;
  163. }
  164. *pprev = data;
  165. }
  166. /* cfgp_usage prints format for configuration parameter
  167. *
  168. * @param p configuration parameter descriptor
  169. * @param write 0 if no value is expected, !=0 otherwise
  170. */
  171. static void
  172. cfgp_usage(const struct ipmi_cfgp *p, int write)
  173. {
  174. if (p->name == NULL) {
  175. return;
  176. }
  177. if (write && p->format == NULL) {
  178. return;
  179. }
  180. printf(" %s%s%s %s\n",
  181. p->name, p->is_set ? " <set_sel>" : "",
  182. p->has_blocks ? " <block_sel>" : "",
  183. write ? p->format : "");
  184. }
  185. /* ipmi_cfgp_usage prints format for configuration parameter set
  186. *
  187. * @param set configuration parameter descriptor array
  188. * @param count number of elements in set
  189. * @param write 0 if no value is expected, !=0 otherwise
  190. */
  191. void
  192. ipmi_cfgp_usage(const struct ipmi_cfgp *set, int count, int write)
  193. {
  194. const struct ipmi_cfgp *p;
  195. int i;
  196. if (set == NULL) {
  197. return;
  198. }
  199. for (i = 0; i < count; i++) {
  200. p = &set[i];
  201. if (write && p->access == CFGP_RDONLY) {
  202. continue;
  203. }
  204. if (!write && p->access == CFGP_WRONLY) {
  205. continue;
  206. }
  207. cfgp_usage(p, write);
  208. }
  209. }
  210. /* ipmi_cfgp_parse_data parse parameter data from command line into context
  211. * @param ctx context to add data
  212. * @param sel parameter selector
  213. * @param argc number of elements in argv
  214. * @param argv array of unparsed arguments
  215. *
  216. * @returns 0 on success
  217. * <0 on error
  218. */
  219. int
  220. ipmi_cfgp_parse_data(struct ipmi_cfgp_ctx *ctx,
  221. const struct ipmi_cfgp_sel *sel, int argc, const char **argv)
  222. {
  223. const struct ipmi_cfgp *p;
  224. struct ipmi_cfgp_data *data;
  225. struct ipmi_cfgp_action action;
  226. if (ctx == NULL || sel == NULL || argv == NULL) {
  227. return -1;
  228. }
  229. if (sel->param == -1 || sel->param >= ctx->count) {
  230. lprintf(LOG_ERR, "invalid parameter, must be one of:");
  231. ipmi_cfgp_usage(ctx->set, ctx->count, 1);
  232. return -1;
  233. }
  234. if (sel->set == -1) {
  235. lprintf(LOG_ERR, "set selector is not specified");
  236. return -1;
  237. }
  238. if (sel->block == -1) {
  239. lprintf(LOG_ERR, "block selector is not specified");
  240. return -1;
  241. }
  242. p = &ctx->set[sel->param];
  243. if (p->size == 0) {
  244. return -1;
  245. }
  246. data = malloc(sizeof(struct ipmi_cfgp_data) + p->size);
  247. if (data == NULL) {
  248. return -1;
  249. }
  250. memset(data, 0, sizeof(struct ipmi_cfgp_data) + p->size);
  251. action.type = CFGP_PARSE;
  252. action.set = sel->set;
  253. action.block = sel->block;
  254. action.argc = argc;
  255. action.argv = argv;
  256. action.file = NULL;
  257. if (ctx->handler(ctx->priv, p, &action, data->data) != 0) {
  258. ipmi_cfgp_usage(p, 1, 1);
  259. free(data);
  260. data = NULL;
  261. return -1;
  262. }
  263. data->sel = *sel;
  264. cfgp_add_data(ctx, data);
  265. return 0;
  266. }
  267. /* cfgp_get_param -- get parameter data from MC into data list within context
  268. *
  269. * @param ctx context
  270. * @param p parameter descriptor
  271. * @param set parameter set selector, can be -1 to scan all set selectors
  272. * @param block parameter block selector, can be -1 to get all blocks
  273. * @param quiet set to non-zero to continue on errors
  274. * (required for -1 to work)
  275. * @returns 0 on success, non-zero otherwise
  276. */
  277. static int
  278. cfgp_get_param(struct ipmi_cfgp_ctx *ctx, const struct ipmi_cfgp *p,
  279. int set, int block, int quiet)
  280. {
  281. struct ipmi_cfgp_data *data;
  282. struct ipmi_cfgp_action action;
  283. int cset;
  284. int cblock;
  285. int ret;
  286. if (p->size == 0) {
  287. return -1;
  288. }
  289. action.type = CFGP_GET;
  290. action.argc = 0;
  291. action.argv = NULL;
  292. action.file = NULL;
  293. if (set == -1 && !p->is_set) {
  294. set = 0;
  295. }
  296. if (block == -1 && !p->has_blocks) {
  297. block = 0;
  298. }
  299. if (set == -1) {
  300. cset = p->first_set;
  301. } else {
  302. cset = set;
  303. }
  304. action.quiet = quiet;
  305. do {
  306. if (block == -1) {
  307. cblock = p->first_block;
  308. } else {
  309. cblock = block;
  310. }
  311. do {
  312. data = malloc(sizeof(struct ipmi_cfgp_data) + p->size);
  313. if (data == NULL) {
  314. return -1;
  315. }
  316. memset(data, 0, sizeof(struct ipmi_cfgp_data) + p->size);
  317. action.set = cset;
  318. action.block = cblock;
  319. ret = ctx->handler(ctx->priv, p, &action, data->data);
  320. if (ret != 0) {
  321. free(data);
  322. data = NULL;
  323. if (!action.quiet) {
  324. return ret;
  325. }
  326. break;
  327. }
  328. data->sel.param = p - ctx->set;
  329. data->sel.set = cset;
  330. data->sel.block = cblock;
  331. cfgp_add_data(ctx, data);
  332. cblock++;
  333. action.quiet = 1;
  334. } while (block == -1);
  335. if (ret != 0 && cblock == p->first_block) {
  336. break;
  337. }
  338. cset++;
  339. } while (set == -1);
  340. return 0;
  341. }
  342. /* ipmi_cfgp_get -- get parameters data from MC into data list within context
  343. *
  344. * @param ctx context
  345. * @param sel parameter selector
  346. * @returns 0 on success, non-zero otherwise
  347. */
  348. int
  349. ipmi_cfgp_get(struct ipmi_cfgp_ctx *ctx, const struct ipmi_cfgp_sel *sel)
  350. {
  351. int i;
  352. int ret;
  353. if (ctx == NULL || sel == NULL) {
  354. return -1;
  355. }
  356. if (sel->param != -1) {
  357. if (sel->param >= ctx->count) {
  358. return -1;
  359. }
  360. ret = cfgp_get_param(ctx, &ctx->set[sel->param],
  361. sel->set, sel->block, 0);
  362. if (ret) {
  363. return -1;
  364. }
  365. return 0;
  366. }
  367. for (i = 0; i < ctx->count; i++) {
  368. if (ctx->set[i].access == CFGP_WRONLY) {
  369. continue;
  370. }
  371. if (cfgp_get_param(ctx, &ctx->set[i], sel->set, sel->block, 1)) {
  372. return -1;
  373. }
  374. }
  375. return 0;
  376. }
  377. static int
  378. cfgp_do_action(struct ipmi_cfgp_ctx *ctx, int action_type,
  379. const struct ipmi_cfgp_sel *sel, FILE *file, int filter)
  380. {
  381. const struct ipmi_cfgp *p;
  382. struct ipmi_cfgp_data *data;
  383. struct ipmi_cfgp_action action;
  384. int ret;
  385. if (ctx == NULL || sel == NULL) {
  386. return -1;
  387. }
  388. action.type = action_type;
  389. action.argc = 0;
  390. action.argv = NULL;
  391. action.file = file;
  392. for (data = ctx->v; data != NULL; data = data->next) {
  393. if (sel->param != -1 && sel->param != data->sel.param) {
  394. continue;
  395. }
  396. if (sel->set != -1 && sel->set != data->sel.set) {
  397. continue;
  398. }
  399. if (sel->block != -1 && sel->block != data->sel.block) {
  400. continue;
  401. }
  402. if (ctx->set[data->sel.param].access == filter) {
  403. continue;
  404. }
  405. p = &ctx->set[data->sel.param];
  406. action.set = data->sel.set;
  407. action.block = data->sel.block;
  408. if (action_type == CFGP_SAVE) {
  409. fprintf(file, "%s %s ", ctx->cmdname, p->name);
  410. if (p->is_set) {
  411. fprintf(file, "%d ", data->sel.set);
  412. }
  413. if (p->has_blocks) {
  414. fprintf(file, "%d ", data->sel.block);
  415. }
  416. }
  417. ret = ctx->handler(ctx->priv, p, &action, data->data);
  418. if (action_type == CFGP_SAVE) {
  419. fputc('\n', file);
  420. }
  421. if (ret != 0) {
  422. return -1;
  423. }
  424. }
  425. return 0;
  426. }
  427. int
  428. ipmi_cfgp_set(struct ipmi_cfgp_ctx *ctx, const struct ipmi_cfgp_sel *sel)
  429. {
  430. return cfgp_do_action(ctx, CFGP_SET, sel, NULL, CFGP_RDONLY);
  431. }
  432. int
  433. ipmi_cfgp_save(struct ipmi_cfgp_ctx *ctx,
  434. const struct ipmi_cfgp_sel *sel, FILE *file)
  435. {
  436. if (file == NULL) {
  437. return -1;
  438. }
  439. return cfgp_do_action(ctx, CFGP_SAVE, sel, file, CFGP_RDONLY);
  440. }
  441. int
  442. ipmi_cfgp_print(struct ipmi_cfgp_ctx *ctx,
  443. const struct ipmi_cfgp_sel *sel, FILE *file)
  444. {
  445. if (file == NULL) {
  446. return -1;
  447. }
  448. return cfgp_do_action(ctx, CFGP_PRINT, sel, file, CFGP_RESERVED);
  449. }