You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2261 lines
65 KiB

  1. /*
  2. * virsh-pool.c: Commands to manage storage pool
  3. *
  4. * Copyright (C) 2005, 2007-2016 Red Hat, Inc.
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library. If not, see
  18. * <http://www.gnu.org/licenses/>.
  19. */
  20. #include <config.h>
  21. #include "virsh-pool.h"
  22. #include "internal.h"
  23. #include "virbuffer.h"
  24. #include "viralloc.h"
  25. #include "virfile.h"
  26. #include "conf/storage_conf.h"
  27. #include "virstring.h"
  28. #include "virtime.h"
  29. #include "vsh-table.h"
  30. #include "virenum.h"
  31. #define VIRSH_COMMON_OPT_POOL_FULL(cflags) \
  32. VIRSH_COMMON_OPT_POOL(N_("pool name or uuid"), cflags)
  33. #define VIRSH_COMMON_OPT_POOL_BUILD \
  34. {.name = "build", \
  35. .type = VSH_OT_BOOL, \
  36. .flags = 0, \
  37. .help = N_("build the pool as normal") \
  38. }
  39. #define VIRSH_COMMON_OPT_POOL_NO_OVERWRITE \
  40. {.name = "no-overwrite", \
  41. .type = VSH_OT_BOOL, \
  42. .flags = 0, \
  43. .help = N_("do not overwrite any existing data") \
  44. }
  45. #define VIRSH_COMMON_OPT_POOL_OVERWRITE \
  46. {.name = "overwrite", \
  47. .type = VSH_OT_BOOL, \
  48. .flags = 0, \
  49. .help = N_("overwrite any existing data") \
  50. }
  51. #define VIRSH_COMMON_OPT_POOL_X_AS \
  52. {.name = "name", \
  53. .type = VSH_OT_DATA, \
  54. .flags = VSH_OFLAG_REQ, \
  55. .help = N_("name of the pool") \
  56. }, \
  57. {.name = "type", \
  58. .type = VSH_OT_DATA, \
  59. .flags = VSH_OFLAG_REQ, \
  60. .help = N_("type of the pool") \
  61. }, \
  62. {.name = "print-xml", \
  63. .type = VSH_OT_BOOL, \
  64. .help = N_("print XML document, but don't define/create") \
  65. }, \
  66. {.name = "source-host", \
  67. .type = VSH_OT_STRING, \
  68. .help = N_("source-host for underlying storage") \
  69. }, \
  70. {.name = "source-path", \
  71. .type = VSH_OT_STRING, \
  72. .help = N_("source path for underlying storage") \
  73. }, \
  74. {.name = "source-dev", \
  75. .type = VSH_OT_STRING, \
  76. .help = N_("source device for underlying storage") \
  77. }, \
  78. {.name = "source-name", \
  79. .type = VSH_OT_STRING, \
  80. .help = N_("source name for underlying storage") \
  81. }, \
  82. {.name = "target", \
  83. .type = VSH_OT_STRING, \
  84. .help = N_("target for underlying storage") \
  85. }, \
  86. {.name = "source-format", \
  87. .type = VSH_OT_STRING, \
  88. .help = N_("format for underlying storage") \
  89. }, \
  90. {.name = "auth-type", \
  91. .type = VSH_OT_STRING, \
  92. .help = N_("auth type to be used for underlying storage") \
  93. }, \
  94. {.name = "auth-username", \
  95. .type = VSH_OT_STRING, \
  96. .help = N_("auth username to be used for underlying storage") \
  97. }, \
  98. {.name = "secret-usage", \
  99. .type = VSH_OT_STRING, \
  100. .help = N_("auth secret usage to be used for underlying storage") \
  101. }, \
  102. {.name = "secret-uuid", \
  103. .type = VSH_OT_STRING, \
  104. .help = N_("auth secret UUID to be used for underlying storage") \
  105. }, \
  106. {.name = "adapter-name", \
  107. .type = VSH_OT_STRING, \
  108. .help = N_("adapter name to be used for underlying storage") \
  109. }, \
  110. {.name = "adapter-wwnn", \
  111. .type = VSH_OT_STRING, \
  112. .help = N_("adapter wwnn to be used for underlying storage") \
  113. }, \
  114. {.name = "adapter-wwpn", \
  115. .type = VSH_OT_STRING, \
  116. .help = N_("adapter wwpn to be used for underlying storage") \
  117. }, \
  118. {.name = "adapter-parent", \
  119. .type = VSH_OT_STRING, \
  120. .help = N_("adapter parent scsi_hostN to be used for underlying vHBA storage") \
  121. }, \
  122. {.name = "adapter-parent-wwnn", \
  123. .type = VSH_OT_STRING, \
  124. .help = N_("adapter parent scsi_hostN wwnn to be used for underlying vHBA storage") \
  125. }, \
  126. {.name = "adapter-parent-wwpn", \
  127. .type = VSH_OT_STRING, \
  128. .help = N_("adapter parent scsi_hostN wwpn to be used for underlying vHBA storage") \
  129. }, \
  130. {.name = "adapter-parent-fabric-wwn", \
  131. .type = VSH_OT_STRING, \
  132. .help = N_("adapter parent scsi_hostN fabric_wwn to be used for underlying vHBA storage") \
  133. }, \
  134. {.name = "source-protocol-ver", \
  135. .type = VSH_OT_STRING, \
  136. .help = N_("nfsvers value for NFS pool mount option") \
  137. }
  138. virStoragePoolPtr
  139. virshCommandOptPoolBy(vshControl *ctl, const vshCmd *cmd, const char *optname,
  140. const char **name, unsigned int flags)
  141. {
  142. virStoragePoolPtr pool = NULL;
  143. const char *n = NULL;
  144. virshControlPtr priv = ctl->privData;
  145. virCheckFlags(VIRSH_BYUUID | VIRSH_BYNAME, NULL);
  146. if (vshCommandOptStringReq(ctl, cmd, optname, &n) < 0)
  147. return NULL;
  148. if (cmd->skipChecks && !n)
  149. return NULL;
  150. vshDebug(ctl, VSH_ERR_INFO, "%s: found option <%s>: %s\n",
  151. cmd->def->name, optname, n);
  152. if (name)
  153. *name = n;
  154. /* try it by UUID */
  155. if ((flags & VIRSH_BYUUID) && strlen(n) == VIR_UUID_STRING_BUFLEN-1) {
  156. vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as pool UUID\n",
  157. cmd->def->name, optname);
  158. pool = virStoragePoolLookupByUUIDString(priv->conn, n);
  159. }
  160. /* try it by NAME */
  161. if (!pool && (flags & VIRSH_BYNAME)) {
  162. vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as pool NAME\n",
  163. cmd->def->name, optname);
  164. pool = virStoragePoolLookupByName(priv->conn, n);
  165. }
  166. if (!pool)
  167. vshError(ctl, _("failed to get pool '%s'"), n);
  168. return pool;
  169. }
  170. /*
  171. * "pool-autostart" command
  172. */
  173. static const vshCmdInfo info_pool_autostart[] = {
  174. {.name = "help",
  175. .data = N_("autostart a pool")
  176. },
  177. {.name = "desc",
  178. .data = N_("Configure a pool to be automatically started at boot.")
  179. },
  180. {.name = NULL}
  181. };
  182. static const vshCmdOptDef opts_pool_autostart[] = {
  183. VIRSH_COMMON_OPT_POOL_FULL(VIR_CONNECT_LIST_STORAGE_POOLS_PERSISTENT),
  184. {.name = "disable",
  185. .type = VSH_OT_BOOL,
  186. .help = N_("disable autostarting")
  187. },
  188. {.name = NULL}
  189. };
  190. static bool
  191. cmdPoolAutostart(vshControl *ctl, const vshCmd *cmd)
  192. {
  193. virStoragePoolPtr pool;
  194. const char *name;
  195. int autostart;
  196. if (!(pool = virshCommandOptPool(ctl, cmd, "pool", &name)))
  197. return false;
  198. autostart = !vshCommandOptBool(cmd, "disable");
  199. if (virStoragePoolSetAutostart(pool, autostart) < 0) {
  200. if (autostart)
  201. vshError(ctl, _("failed to mark pool %s as autostarted"), name);
  202. else
  203. vshError(ctl, _("failed to unmark pool %s as autostarted"), name);
  204. virStoragePoolFree(pool);
  205. return false;
  206. }
  207. if (autostart)
  208. vshPrintExtra(ctl, _("Pool %s marked as autostarted\n"), name);
  209. else
  210. vshPrintExtra(ctl, _("Pool %s unmarked as autostarted\n"), name);
  211. virStoragePoolFree(pool);
  212. return true;
  213. }
  214. /*
  215. * "pool-create" command
  216. */
  217. static const vshCmdInfo info_pool_create[] = {
  218. {.name = "help",
  219. .data = N_("create a pool from an XML file")
  220. },
  221. {.name = "desc",
  222. .data = N_("Create a pool.")
  223. },
  224. {.name = NULL}
  225. };
  226. static const vshCmdOptDef opts_pool_create[] = {
  227. VIRSH_COMMON_OPT_FILE(N_("file containing an XML pool description")),
  228. VIRSH_COMMON_OPT_POOL_BUILD,
  229. VIRSH_COMMON_OPT_POOL_NO_OVERWRITE,
  230. VIRSH_COMMON_OPT_POOL_OVERWRITE,
  231. {.name = NULL}
  232. };
  233. static bool
  234. cmdPoolCreate(vshControl *ctl, const vshCmd *cmd)
  235. {
  236. virStoragePoolPtr pool;
  237. const char *from = NULL;
  238. bool ret = true;
  239. char *buffer;
  240. bool build;
  241. bool overwrite;
  242. bool no_overwrite;
  243. unsigned int flags = 0;
  244. virshControlPtr priv = ctl->privData;
  245. if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0)
  246. return false;
  247. build = vshCommandOptBool(cmd, "build");
  248. overwrite = vshCommandOptBool(cmd, "overwrite");
  249. no_overwrite = vshCommandOptBool(cmd, "no-overwrite");
  250. VSH_EXCLUSIVE_OPTIONS_EXPR("overwrite", overwrite,
  251. "no-overwrite", no_overwrite);
  252. if (build)
  253. flags |= VIR_STORAGE_POOL_CREATE_WITH_BUILD;
  254. if (overwrite)
  255. flags |= VIR_STORAGE_POOL_CREATE_WITH_BUILD_OVERWRITE;
  256. if (no_overwrite)
  257. flags |= VIR_STORAGE_POOL_CREATE_WITH_BUILD_NO_OVERWRITE;
  258. if (virFileReadAll(from, VSH_MAX_XML_FILE, &buffer) < 0)
  259. return false;
  260. pool = virStoragePoolCreateXML(priv->conn, buffer, flags);
  261. VIR_FREE(buffer);
  262. if (pool != NULL) {
  263. vshPrintExtra(ctl, _("Pool %s created from %s\n"),
  264. virStoragePoolGetName(pool), from);
  265. virStoragePoolFree(pool);
  266. } else {
  267. vshError(ctl, _("Failed to create pool from %s"), from);
  268. ret = false;
  269. }
  270. return ret;
  271. }
  272. static const vshCmdOptDef opts_pool_define_as[] = {
  273. VIRSH_COMMON_OPT_POOL_X_AS,
  274. {.name = NULL}
  275. };
  276. static int
  277. virshBuildPoolXML(vshControl *ctl,
  278. const vshCmd *cmd,
  279. const char **retname,
  280. char **xml)
  281. {
  282. const char *name = NULL, *type = NULL, *srcHost = NULL, *srcPath = NULL,
  283. *srcDev = NULL, *srcName = NULL, *srcFormat = NULL,
  284. *target = NULL, *authType = NULL, *authUsername = NULL,
  285. *secretUsage = NULL, *adapterName = NULL, *adapterParent = NULL,
  286. *adapterWwnn = NULL, *adapterWwpn = NULL, *secretUUID = NULL,
  287. *adapterParentWwnn = NULL, *adapterParentWwpn = NULL,
  288. *adapterParentFabricWwn = NULL, *protoVer = NULL;
  289. virBuffer buf = VIR_BUFFER_INITIALIZER;
  290. VSH_EXCLUSIVE_OPTIONS("secret-usage", "secret-uuid");
  291. if (vshCommandOptStringReq(ctl, cmd, "name", &name) < 0)
  292. goto cleanup;
  293. if (vshCommandOptStringReq(ctl, cmd, "type", &type) < 0)
  294. goto cleanup;
  295. if (vshCommandOptStringReq(ctl, cmd, "source-host", &srcHost) < 0 ||
  296. vshCommandOptStringReq(ctl, cmd, "source-path", &srcPath) < 0 ||
  297. vshCommandOptStringReq(ctl, cmd, "source-dev", &srcDev) < 0 ||
  298. vshCommandOptStringReq(ctl, cmd, "source-name", &srcName) < 0 ||
  299. vshCommandOptStringReq(ctl, cmd, "source-format", &srcFormat) < 0 ||
  300. vshCommandOptStringReq(ctl, cmd, "target", &target) < 0 ||
  301. vshCommandOptStringReq(ctl, cmd, "auth-type", &authType) < 0 ||
  302. vshCommandOptStringReq(ctl, cmd, "auth-username", &authUsername) < 0 ||
  303. vshCommandOptStringReq(ctl, cmd, "secret-usage", &secretUsage) < 0 ||
  304. vshCommandOptStringReq(ctl, cmd, "secret-uuid", &secretUUID) < 0 ||
  305. vshCommandOptStringReq(ctl, cmd, "adapter-name", &adapterName) < 0 ||
  306. vshCommandOptStringReq(ctl, cmd, "adapter-wwnn", &adapterWwnn) < 0 ||
  307. vshCommandOptStringReq(ctl, cmd, "adapter-wwpn", &adapterWwpn) < 0 ||
  308. vshCommandOptStringReq(ctl, cmd, "adapter-parent", &adapterParent) < 0 ||
  309. vshCommandOptStringReq(ctl, cmd, "adapter-parent-wwnn", &adapterParentWwnn) < 0 ||
  310. vshCommandOptStringReq(ctl, cmd, "adapter-parent-wwpn", &adapterParentWwpn) < 0 ||
  311. vshCommandOptStringReq(ctl, cmd, "adapter-parent-fabric-wwn", &adapterParentFabricWwn) < 0 ||
  312. vshCommandOptStringReq(ctl, cmd, "source-protocol-ver", &protoVer) < 0)
  313. goto cleanup;
  314. virBufferAsprintf(&buf, "<pool type='%s'>\n", type);
  315. virBufferAdjustIndent(&buf, 2);
  316. virBufferAsprintf(&buf, "<name>%s</name>\n", name);
  317. if (srcHost || srcPath || srcDev || srcFormat || srcName ||
  318. (adapterWwnn && adapterWwpn) || adapterName) {
  319. virBufferAddLit(&buf, "<source>\n");
  320. virBufferAdjustIndent(&buf, 2);
  321. if (srcHost)
  322. virBufferAsprintf(&buf, "<host name='%s'/>\n", srcHost);
  323. if (srcPath)
  324. virBufferAsprintf(&buf, "<dir path='%s'/>\n", srcPath);
  325. if (srcDev)
  326. virBufferAsprintf(&buf, "<device path='%s'/>\n", srcDev);
  327. if (adapterWwnn && adapterWwpn) {
  328. virBufferAddLit(&buf, "<adapter type='fc_host'");
  329. if (adapterParent)
  330. virBufferAsprintf(&buf, " parent='%s'", adapterParent);
  331. else if (adapterParentWwnn && adapterParentWwpn)
  332. virBufferAsprintf(&buf, " parent_wwnn='%s' parent_wwpn='%s'",
  333. adapterParentWwnn, adapterParentWwpn);
  334. else if (adapterParentFabricWwn)
  335. virBufferAsprintf(&buf, " parent_fabric_wwn='%s'",
  336. adapterParentFabricWwn);
  337. virBufferAsprintf(&buf, " wwnn='%s' wwpn='%s'/>\n",
  338. adapterWwnn, adapterWwpn);
  339. } else if (adapterName) {
  340. virBufferAsprintf(&buf, "<adapter type='scsi_host' name='%s'/>\n",
  341. adapterName);
  342. }
  343. if (authType && authUsername && (secretUsage || secretUUID)) {
  344. virBufferAsprintf(&buf, "<auth type='%s' username='%s'>\n",
  345. authType, authUsername);
  346. virBufferAdjustIndent(&buf, 2);
  347. if (secretUsage)
  348. virBufferAsprintf(&buf, "<secret usage='%s'/>\n", secretUsage);
  349. else
  350. virBufferAsprintf(&buf, "<secret uuid='%s'/>\n", secretUUID);
  351. virBufferAdjustIndent(&buf, -2);
  352. virBufferAddLit(&buf, "</auth>\n");
  353. }
  354. if (srcFormat)
  355. virBufferAsprintf(&buf, "<format type='%s'/>\n", srcFormat);
  356. if (srcName)
  357. virBufferAsprintf(&buf, "<name>%s</name>\n", srcName);
  358. if (protoVer)
  359. virBufferAsprintf(&buf, "<protocol ver='%s'/>\n", protoVer);
  360. virBufferAdjustIndent(&buf, -2);
  361. virBufferAddLit(&buf, "</source>\n");
  362. }
  363. if (target) {
  364. virBufferAddLit(&buf, "<target>\n");
  365. virBufferAdjustIndent(&buf, 2);
  366. virBufferAsprintf(&buf, "<path>%s</path>\n", target);
  367. virBufferAdjustIndent(&buf, -2);
  368. virBufferAddLit(&buf, "</target>\n");
  369. }
  370. virBufferAdjustIndent(&buf, -2);
  371. virBufferAddLit(&buf, "</pool>\n");
  372. *xml = virBufferContentAndReset(&buf);
  373. *retname = name;
  374. return true;
  375. cleanup:
  376. virBufferFreeAndReset(&buf);
  377. return false;
  378. }
  379. /*
  380. * "pool-create-as" command
  381. */
  382. static const vshCmdInfo info_pool_create_as[] = {
  383. {.name = "help",
  384. .data = N_("create a pool from a set of args")
  385. },
  386. {.name = "desc",
  387. .data = N_("Create a pool.")
  388. },
  389. {.name = NULL}
  390. };
  391. static const vshCmdOptDef opts_pool_create_as[] = {
  392. VIRSH_COMMON_OPT_POOL_X_AS,
  393. VIRSH_COMMON_OPT_POOL_BUILD,
  394. VIRSH_COMMON_OPT_POOL_NO_OVERWRITE,
  395. VIRSH_COMMON_OPT_POOL_OVERWRITE,
  396. {.name = NULL}
  397. };
  398. static bool
  399. cmdPoolCreateAs(vshControl *ctl, const vshCmd *cmd)
  400. {
  401. virStoragePoolPtr pool;
  402. const char *name;
  403. char *xml;
  404. bool printXML = vshCommandOptBool(cmd, "print-xml");
  405. bool build;
  406. bool overwrite;
  407. bool no_overwrite;
  408. unsigned int flags = 0;
  409. virshControlPtr priv = ctl->privData;
  410. build = vshCommandOptBool(cmd, "build");
  411. overwrite = vshCommandOptBool(cmd, "overwrite");
  412. no_overwrite = vshCommandOptBool(cmd, "no-overwrite");
  413. VSH_EXCLUSIVE_OPTIONS_EXPR("overwrite", overwrite,
  414. "no-overwrite", no_overwrite);
  415. if (build)
  416. flags |= VIR_STORAGE_POOL_CREATE_WITH_BUILD;
  417. if (overwrite)
  418. flags |= VIR_STORAGE_POOL_CREATE_WITH_BUILD_OVERWRITE;
  419. if (no_overwrite)
  420. flags |= VIR_STORAGE_POOL_CREATE_WITH_BUILD_NO_OVERWRITE;
  421. if (!virshBuildPoolXML(ctl, cmd, &name, &xml))
  422. return false;
  423. if (printXML) {
  424. vshPrint(ctl, "%s", xml);
  425. VIR_FREE(xml);
  426. } else {
  427. pool = virStoragePoolCreateXML(priv->conn, xml, flags);
  428. VIR_FREE(xml);
  429. if (pool != NULL) {
  430. vshPrintExtra(ctl, _("Pool %s created\n"), name);
  431. virStoragePoolFree(pool);
  432. } else {
  433. vshError(ctl, _("Failed to create pool %s"), name);
  434. return false;
  435. }
  436. }
  437. return true;
  438. }
  439. /*
  440. * "pool-define" command
  441. */
  442. static const vshCmdInfo info_pool_define[] = {
  443. {.name = "help",
  444. .data = N_("define an inactive persistent storage pool or modify "
  445. "an existing persistent one from an XML file")
  446. },
  447. {.name = "desc",
  448. .data = N_("Define or modify a persistent storage pool.")
  449. },
  450. {.name = NULL}
  451. };
  452. static const vshCmdOptDef opts_pool_define[] = {
  453. VIRSH_COMMON_OPT_FILE(N_("file containing an XML pool description")),
  454. {.name = NULL}
  455. };
  456. static bool
  457. cmdPoolDefine(vshControl *ctl, const vshCmd *cmd)
  458. {
  459. virStoragePoolPtr pool;
  460. const char *from = NULL;
  461. bool ret = true;
  462. char *buffer;
  463. virshControlPtr priv = ctl->privData;
  464. if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0)
  465. return false;
  466. if (virFileReadAll(from, VSH_MAX_XML_FILE, &buffer) < 0)
  467. return false;
  468. pool = virStoragePoolDefineXML(priv->conn, buffer, 0);
  469. VIR_FREE(buffer);
  470. if (pool != NULL) {
  471. vshPrintExtra(ctl, _("Pool %s defined from %s\n"),
  472. virStoragePoolGetName(pool), from);
  473. virStoragePoolFree(pool);
  474. } else {
  475. vshError(ctl, _("Failed to define pool from %s"), from);
  476. ret = false;
  477. }
  478. return ret;
  479. }
  480. /*
  481. * "pool-define-as" command
  482. */
  483. static const vshCmdInfo info_pool_define_as[] = {
  484. {.name = "help",
  485. .data = N_("define a pool from a set of args")
  486. },
  487. {.name = "desc",
  488. .data = N_("Define a pool.")
  489. },
  490. {.name = NULL}
  491. };
  492. static bool
  493. cmdPoolDefineAs(vshControl *ctl, const vshCmd *cmd)
  494. {
  495. virStoragePoolPtr pool;
  496. const char *name;
  497. char *xml;
  498. bool printXML = vshCommandOptBool(cmd, "print-xml");
  499. virshControlPtr priv = ctl->privData;
  500. if (!virshBuildPoolXML(ctl, cmd, &name, &xml))
  501. return false;
  502. if (printXML) {
  503. vshPrint(ctl, "%s", xml);
  504. VIR_FREE(xml);
  505. } else {
  506. pool = virStoragePoolDefineXML(priv->conn, xml, 0);
  507. VIR_FREE(xml);
  508. if (pool != NULL) {
  509. vshPrintExtra(ctl, _("Pool %s defined\n"), name);
  510. virStoragePoolFree(pool);
  511. } else {
  512. vshError(ctl, _("Failed to define pool %s"), name);
  513. return false;
  514. }
  515. }
  516. return true;
  517. }
  518. /*
  519. * "pool-build" command
  520. */
  521. static const vshCmdInfo info_pool_build[] = {
  522. {.name = "help",
  523. .data = N_("build a pool")
  524. },
  525. {.name = "desc",
  526. .data = N_("Build a given pool.")
  527. },
  528. {.name = NULL}
  529. };
  530. static const vshCmdOptDef opts_pool_build[] = {
  531. VIRSH_COMMON_OPT_POOL_FULL(0),
  532. VIRSH_COMMON_OPT_POOL_NO_OVERWRITE,
  533. VIRSH_COMMON_OPT_POOL_OVERWRITE,
  534. {.name = NULL}
  535. };
  536. static bool
  537. cmdPoolBuild(vshControl *ctl, const vshCmd *cmd)
  538. {
  539. virStoragePoolPtr pool;
  540. bool ret = true;
  541. const char *name;
  542. unsigned int flags = 0;
  543. if (!(pool = virshCommandOptPool(ctl, cmd, "pool", &name)))
  544. return false;
  545. if (vshCommandOptBool(cmd, "no-overwrite"))
  546. flags |= VIR_STORAGE_POOL_BUILD_NO_OVERWRITE;
  547. if (vshCommandOptBool(cmd, "overwrite"))
  548. flags |= VIR_STORAGE_POOL_BUILD_OVERWRITE;
  549. if (virStoragePoolBuild(pool, flags) == 0) {
  550. vshPrintExtra(ctl, _("Pool %s built\n"), name);
  551. } else {
  552. vshError(ctl, _("Failed to build pool %s"), name);
  553. ret = false;
  554. }
  555. virStoragePoolFree(pool);
  556. return ret;
  557. }
  558. /*
  559. * "pool-destroy" command
  560. */
  561. static const vshCmdInfo info_pool_destroy[] = {
  562. {.name = "help",
  563. .data = N_("destroy (stop) a pool")
  564. },
  565. {.name = "desc",
  566. .data = N_("Forcefully stop a given pool. Raw data in the pool is untouched")
  567. },
  568. {.name = NULL}
  569. };
  570. static const vshCmdOptDef opts_pool_destroy[] = {
  571. VIRSH_COMMON_OPT_POOL_FULL(VIR_CONNECT_LIST_STORAGE_POOLS_ACTIVE),
  572. {.name = NULL}
  573. };
  574. static bool
  575. cmdPoolDestroy(vshControl *ctl, const vshCmd *cmd)
  576. {
  577. virStoragePoolPtr pool;
  578. bool ret = true;
  579. const char *name;
  580. if (!(pool = virshCommandOptPool(ctl, cmd, "pool", &name)))
  581. return false;
  582. if (virStoragePoolDestroy(pool) == 0) {
  583. vshPrintExtra(ctl, _("Pool %s destroyed\n"), name);
  584. } else {
  585. vshError(ctl, _("Failed to destroy pool %s"), name);
  586. ret = false;
  587. }
  588. virStoragePoolFree(pool);
  589. return ret;
  590. }
  591. /*
  592. * "pool-delete" command
  593. */
  594. static const vshCmdInfo info_pool_delete[] = {
  595. {.name = "help",
  596. .data = N_("delete a pool")
  597. },
  598. {.name = "desc",
  599. .data = N_("Delete a given pool.")
  600. },
  601. {.name = NULL}
  602. };
  603. static const vshCmdOptDef opts_pool_delete[] = {
  604. VIRSH_COMMON_OPT_POOL_FULL(VIR_CONNECT_LIST_STORAGE_POOLS_INACTIVE),
  605. {.name = NULL}
  606. };
  607. static bool
  608. cmdPoolDelete(vshControl *ctl, const vshCmd *cmd)
  609. {
  610. virStoragePoolPtr pool;
  611. bool ret = true;
  612. const char *name;
  613. if (!(pool = virshCommandOptPool(ctl, cmd, "pool", &name)))
  614. return false;
  615. if (virStoragePoolDelete(pool, 0) == 0) {
  616. vshPrintExtra(ctl, _("Pool %s deleted\n"), name);
  617. } else {
  618. vshError(ctl, _("Failed to delete pool %s"), name);
  619. ret = false;
  620. }
  621. virStoragePoolFree(pool);
  622. return ret;
  623. }
  624. /*
  625. * "pool-refresh" command
  626. */
  627. static const vshCmdInfo info_pool_refresh[] = {
  628. {.name = "help",
  629. .data = N_("refresh a pool")
  630. },
  631. {.name = "desc",
  632. .data = N_("Refresh a given pool.")
  633. },
  634. {.name = NULL}
  635. };
  636. static const vshCmdOptDef opts_pool_refresh[] = {
  637. VIRSH_COMMON_OPT_POOL_FULL(VIR_CONNECT_LIST_STORAGE_POOLS_ACTIVE),
  638. {.name = NULL}
  639. };
  640. static bool
  641. cmdPoolRefresh(vshControl *ctl, const vshCmd *cmd)
  642. {
  643. virStoragePoolPtr pool;
  644. bool ret = true;
  645. const char *name;
  646. if (!(pool = virshCommandOptPool(ctl, cmd, "pool", &name)))
  647. return false;
  648. if (virStoragePoolRefresh(pool, 0) == 0) {
  649. vshPrintExtra(ctl, _("Pool %s refreshed\n"), name);
  650. } else {
  651. vshError(ctl, _("Failed to refresh pool %s"), name);
  652. ret = false;
  653. }
  654. virStoragePoolFree(pool);
  655. return ret;
  656. }
  657. /*
  658. * "pool-dumpxml" command
  659. */
  660. static const vshCmdInfo info_pool_dumpxml[] = {
  661. {.name = "help",
  662. .data = N_("pool information in XML")
  663. },
  664. {.name = "desc",
  665. .data = N_("Output the pool information as an XML dump to stdout.")
  666. },
  667. {.name = NULL}
  668. };
  669. static const vshCmdOptDef opts_pool_dumpxml[] = {
  670. VIRSH_COMMON_OPT_POOL_FULL(0),
  671. {.name = "inactive",
  672. .type = VSH_OT_BOOL,
  673. .help = N_("show inactive defined XML")
  674. },
  675. {.name = NULL}
  676. };
  677. static bool
  678. cmdPoolDumpXML(vshControl *ctl, const vshCmd *cmd)
  679. {
  680. virStoragePoolPtr pool;
  681. bool ret = true;
  682. bool inactive = vshCommandOptBool(cmd, "inactive");
  683. unsigned int flags = 0;
  684. char *dump;
  685. if (inactive)
  686. flags |= VIR_STORAGE_XML_INACTIVE;
  687. if (!(pool = virshCommandOptPool(ctl, cmd, "pool", NULL)))
  688. return false;
  689. dump = virStoragePoolGetXMLDesc(pool, flags);
  690. if (dump != NULL) {
  691. vshPrint(ctl, "%s", dump);
  692. VIR_FREE(dump);
  693. } else {
  694. ret = false;
  695. }
  696. virStoragePoolFree(pool);
  697. return ret;
  698. }
  699. static int
  700. virshStoragePoolSorter(const void *a, const void *b)
  701. {
  702. virStoragePoolPtr *pa = (virStoragePoolPtr *) a;
  703. virStoragePoolPtr *pb = (virStoragePoolPtr *) b;
  704. if (*pa && !*pb)
  705. return -1;
  706. if (!*pa)
  707. return *pb != NULL;
  708. return vshStrcasecmp(virStoragePoolGetName(*pa),
  709. virStoragePoolGetName(*pb));
  710. }
  711. struct virshStoragePoolList {
  712. virStoragePoolPtr *pools;
  713. size_t npools;
  714. };
  715. typedef struct virshStoragePoolList *virshStoragePoolListPtr;
  716. static void
  717. virshStoragePoolListFree(virshStoragePoolListPtr list)
  718. {
  719. size_t i;
  720. if (list && list->pools) {
  721. for (i = 0; i < list->npools; i++) {
  722. if (list->pools[i])
  723. virStoragePoolFree(list->pools[i]);
  724. }
  725. VIR_FREE(list->pools);
  726. }
  727. VIR_FREE(list);
  728. }
  729. static virshStoragePoolListPtr
  730. virshStoragePoolListCollect(vshControl *ctl,
  731. unsigned int flags)
  732. {
  733. virshStoragePoolListPtr list = vshMalloc(ctl, sizeof(*list));
  734. size_t i;
  735. int ret;
  736. char **names = NULL;
  737. virStoragePoolPtr pool;
  738. bool success = false;
  739. size_t deleted = 0;
  740. int persistent;
  741. int autostart;
  742. int nActivePools = 0;
  743. int nInactivePools = 0;
  744. int nAllPools = 0;
  745. virshControlPtr priv = ctl->privData;
  746. /* try the list with flags support (0.10.2 and later) */
  747. if ((ret = virConnectListAllStoragePools(priv->conn,
  748. &list->pools,
  749. flags)) >= 0) {
  750. list->npools = ret;
  751. goto finished;
  752. }
  753. /* check if the command is actually supported */
  754. if (last_error && last_error->code == VIR_ERR_NO_SUPPORT)
  755. goto fallback;
  756. if (last_error && last_error->code == VIR_ERR_INVALID_ARG) {
  757. /* try the new API again but mask non-guaranteed flags */
  758. unsigned int newflags = flags & (VIR_CONNECT_LIST_STORAGE_POOLS_ACTIVE |
  759. VIR_CONNECT_LIST_STORAGE_POOLS_INACTIVE);
  760. vshResetLibvirtError();
  761. if ((ret = virConnectListAllStoragePools(priv->conn, &list->pools,
  762. newflags)) >= 0) {
  763. list->npools = ret;
  764. goto filter;
  765. }
  766. }
  767. /* there was an error during the first or second call */
  768. vshError(ctl, "%s", _("Failed to list pools"));
  769. goto cleanup;
  770. fallback:
  771. /* fall back to old method (0.10.1 and older) */
  772. vshResetLibvirtError();
  773. /* There is no way to get the pool type */
  774. if (VSH_MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_POOL_TYPE)) {
  775. vshError(ctl, "%s", _("Filtering using --type is not supported "
  776. "by this libvirt"));
  777. goto cleanup;
  778. }
  779. /* Get the number of active pools */
  780. if (!VSH_MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_ACTIVE) ||
  781. VSH_MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_ACTIVE)) {
  782. if ((nActivePools = virConnectNumOfStoragePools(priv->conn)) < 0) {
  783. vshError(ctl, "%s", _("Failed to get the number of active pools "));
  784. goto cleanup;
  785. }
  786. }
  787. /* Get the number of inactive pools */
  788. if (!VSH_MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_ACTIVE) ||
  789. VSH_MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_INACTIVE)) {
  790. if ((nInactivePools = virConnectNumOfDefinedStoragePools(priv->conn)) < 0) {
  791. vshError(ctl, "%s", _("Failed to get the number of inactive pools"));
  792. goto cleanup;
  793. }
  794. }
  795. nAllPools = nActivePools + nInactivePools;
  796. if (nAllPools == 0)
  797. return list;
  798. names = vshMalloc(ctl, sizeof(char *) * nAllPools);
  799. /* Retrieve a list of active storage pool names */
  800. if (!VSH_MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_ACTIVE) ||
  801. VSH_MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_ACTIVE)) {
  802. if (virConnectListStoragePools(priv->conn,
  803. names, nActivePools) < 0) {
  804. vshError(ctl, "%s", _("Failed to list active pools"));
  805. goto cleanup;
  806. }
  807. }
  808. /* Add the inactive storage pools to the end of the name list */
  809. if (!VSH_MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_ACTIVE) ||
  810. VSH_MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_ACTIVE)) {
  811. if (virConnectListDefinedStoragePools(priv->conn,
  812. &names[nActivePools],
  813. nInactivePools) < 0) {
  814. vshError(ctl, "%s", _("Failed to list inactive pools"));
  815. goto cleanup;
  816. }
  817. }
  818. list->pools = vshMalloc(ctl, sizeof(virStoragePoolPtr) * (nAllPools));
  819. list->npools = 0;
  820. /* get active pools */
  821. for (i = 0; i < nActivePools; i++) {
  822. if (!(pool = virStoragePoolLookupByName(priv->conn, names[i])))
  823. continue;
  824. list->pools[list->npools++] = pool;
  825. }
  826. /* get inactive pools */
  827. for (i = 0; i < nInactivePools; i++) {
  828. if (!(pool = virStoragePoolLookupByName(priv->conn, names[i])))
  829. continue;
  830. list->pools[list->npools++] = pool;
  831. }
  832. /* truncate pools that weren't found */
  833. deleted = nAllPools - list->npools;
  834. filter:
  835. /* filter list the list if the list was acquired by fallback means */
  836. for (i = 0; i < list->npools; i++) {
  837. pool = list->pools[i];
  838. /* persistence filter */
  839. if (VSH_MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_PERSISTENT)) {
  840. if ((persistent = virStoragePoolIsPersistent(pool)) < 0) {
  841. vshError(ctl, "%s", _("Failed to get pool persistence info"));
  842. goto cleanup;
  843. }
  844. if (!((VSH_MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_PERSISTENT) && persistent) ||
  845. (VSH_MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_TRANSIENT) && !persistent)))
  846. goto remove_entry;
  847. }
  848. /* autostart filter */
  849. if (VSH_MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_AUTOSTART)) {
  850. if (virStoragePoolGetAutostart(pool, &autostart) < 0) {
  851. vshError(ctl, "%s", _("Failed to get pool autostart state"));
  852. goto cleanup;
  853. }
  854. if (!((VSH_MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_AUTOSTART) && autostart) ||
  855. (VSH_MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_NO_AUTOSTART) && !autostart)))
  856. goto remove_entry;
  857. }
  858. /* the pool matched all filters, it may stay */
  859. continue;
  860. remove_entry:
  861. /* the pool has to be removed as it failed one of the filters */
  862. virStoragePoolFree(list->pools[i]);
  863. list->pools[i] = NULL;
  864. deleted++;
  865. }
  866. finished:
  867. /* sort the list */
  868. if (list->pools && list->npools)
  869. qsort(list->pools, list->npools,
  870. sizeof(*list->pools), virshStoragePoolSorter);
  871. /* truncate the list if filter simulation deleted entries */
  872. if (deleted)
  873. VIR_SHRINK_N(list->pools, list->npools, deleted);
  874. success = true;
  875. cleanup:
  876. for (i = 0; i < nAllPools; i++)
  877. VIR_FREE(names[i]);
  878. if (!success) {
  879. virshStoragePoolListFree(list);
  880. list = NULL;
  881. }
  882. VIR_FREE(names);
  883. return list;
  884. }
  885. VIR_ENUM_DECL(virshStoragePoolState);
  886. VIR_ENUM_IMPL(virshStoragePoolState,
  887. VIR_STORAGE_POOL_STATE_LAST,
  888. N_("inactive"),
  889. N_("building"),
  890. N_("running"),
  891. N_("degraded"),
  892. N_("inaccessible"));
  893. static const char *
  894. virshStoragePoolStateToString(int state)
  895. {
  896. const char *str = virshStoragePoolStateTypeToString(state);
  897. return str ? _(str) : _("unknown");
  898. }
  899. /*
  900. * "pool-list" command
  901. */
  902. static const vshCmdInfo info_pool_list[] = {
  903. {.name = "help",
  904. .data = N_("list pools")
  905. },
  906. {.name = "desc",
  907. .data = N_("Returns list of pools.")
  908. },
  909. {.name = NULL}
  910. };
  911. static const vshCmdOptDef opts_pool_list[] = {
  912. {.name = "inactive",
  913. .type = VSH_OT_BOOL,
  914. .help = N_("list inactive pools")
  915. },
  916. {.name = "all",
  917. .type = VSH_OT_BOOL,
  918. .help = N_("list inactive & active pools")
  919. },
  920. {.name = "transient",
  921. .type = VSH_OT_BOOL,
  922. .help = N_("list transient pools")
  923. },
  924. {.name = "persistent",
  925. .type = VSH_OT_BOOL,
  926. .help = N_("list persistent pools")
  927. },
  928. {.name = "autostart",
  929. .type = VSH_OT_BOOL,
  930. .help = N_("list pools with autostart enabled")
  931. },
  932. {.name = "no-autostart",
  933. .type = VSH_OT_BOOL,
  934. .help = N_("list pools with autostart disabled")
  935. },
  936. {.name = "type",
  937. .type = VSH_OT_STRING,
  938. .completer = virshPoolTypeCompleter,
  939. .help = N_("only list pool of specified type(s) (if supported)")
  940. },
  941. {.name = "details",
  942. .type = VSH_OT_BOOL,
  943. .help = N_("display extended details for pools")
  944. },
  945. {.name = "uuid",
  946. .type = VSH_OT_BOOL,
  947. .help = N_("list UUID of active pools only")
  948. },
  949. {.name = "name",
  950. .type = VSH_OT_BOOL,
  951. .help = N_("list name of active pools only")
  952. },
  953. {.name = NULL}
  954. };
  955. static bool
  956. cmdPoolList(vshControl *ctl, const vshCmd *cmd G_GNUC_UNUSED)
  957. {
  958. virStoragePoolInfo info;
  959. size_t i;
  960. bool ret = false;
  961. struct poolInfoText {
  962. char *state;
  963. char *autostart;
  964. char *persistent;
  965. char *capacity;
  966. char *allocation;
  967. char *available;
  968. };
  969. struct poolInfoText *poolInfoTexts = NULL;
  970. unsigned int flags = VIR_CONNECT_LIST_STORAGE_POOLS_ACTIVE;
  971. virshStoragePoolListPtr list = NULL;
  972. const char *type = NULL;
  973. bool details = vshCommandOptBool(cmd, "details");
  974. bool inactive, all;
  975. bool uuid = false;
  976. bool name = false;
  977. vshTablePtr table = NULL;
  978. inactive = vshCommandOptBool(cmd, "inactive");
  979. all = vshCommandOptBool(cmd, "all");
  980. if (inactive)
  981. flags = VIR_CONNECT_LIST_STORAGE_POOLS_INACTIVE;
  982. if (all)
  983. flags = VIR_CONNECT_LIST_STORAGE_POOLS_ACTIVE |
  984. VIR_CONNECT_LIST_STORAGE_POOLS_INACTIVE;
  985. if (vshCommandOptBool(cmd, "autostart"))
  986. flags |= VIR_CONNECT_LIST_STORAGE_POOLS_AUTOSTART;
  987. if (vshCommandOptBool(cmd, "no-autostart"))
  988. flags |= VIR_CONNECT_LIST_STORAGE_POOLS_NO_AUTOSTART;
  989. if (vshCommandOptBool(cmd, "persistent"))
  990. flags |= VIR_CONNECT_LIST_STORAGE_POOLS_PERSISTENT;
  991. if (vshCommandOptBool(cmd, "transient"))
  992. flags |= VIR_CONNECT_LIST_STORAGE_POOLS_TRANSIENT;
  993. if (vshCommandOptBool(cmd, "uuid"))
  994. uuid = true;
  995. if (vshCommandOptBool(cmd, "name"))
  996. name = true;
  997. if (vshCommandOptStringReq(ctl, cmd, "type", &type) < 0)
  998. return false;
  999. VSH_EXCLUSIVE_OPTIONS("details", "uuid");
  1000. VSH_EXCLUSIVE_OPTIONS("details", "name");
  1001. if (type) {
  1002. int poolType = -1;
  1003. char **poolTypes = NULL;
  1004. int npoolTypes = 0;
  1005. if ((npoolTypes = vshStringToArray(type, &poolTypes)) < 0)
  1006. return false;
  1007. for (i = 0; i < npoolTypes; i++) {
  1008. if ((poolType = virStoragePoolTypeFromString(poolTypes[i])) < 0) {
  1009. vshError(ctl, _("Invalid pool type '%s'"), poolTypes[i]);
  1010. virStringListFree(poolTypes);
  1011. return false;
  1012. }
  1013. switch ((virStoragePoolType) poolType) {
  1014. case VIR_STORAGE_POOL_DIR:
  1015. flags |= VIR_CONNECT_LIST_STORAGE_POOLS_DIR;
  1016. break;
  1017. case VIR_STORAGE_POOL_FS:
  1018. flags |= VIR_CONNECT_LIST_STORAGE_POOLS_FS;
  1019. break;
  1020. case VIR_STORAGE_POOL_NETFS:
  1021. flags |= VIR_CONNECT_LIST_STORAGE_POOLS_NETFS;
  1022. break;
  1023. case VIR_STORAGE_POOL_LOGICAL:
  1024. flags |= VIR_CONNECT_LIST_STORAGE_POOLS_LOGICAL;
  1025. break;
  1026. case VIR_STORAGE_POOL_DISK:
  1027. flags |= VIR_CONNECT_LIST_STORAGE_POOLS_DISK;
  1028. break;
  1029. case VIR_STORAGE_POOL_ISCSI:
  1030. flags |= VIR_CONNECT_LIST_STORAGE_POOLS_ISCSI;
  1031. break;
  1032. case VIR_STORAGE_POOL_ISCSI_DIRECT:
  1033. flags |= VIR_CONNECT_LIST_STORAGE_POOLS_ISCSI_DIRECT;
  1034. break;
  1035. case VIR_STORAGE_POOL_SCSI:
  1036. flags |= VIR_CONNECT_LIST_STORAGE_POOLS_SCSI;
  1037. break;
  1038. case VIR_STORAGE_POOL_MPATH:
  1039. flags |= VIR_CONNECT_LIST_STORAGE_POOLS_MPATH;
  1040. break;
  1041. case VIR_STORAGE_POOL_RBD:
  1042. flags |= VIR_CONNECT_LIST_STORAGE_POOLS_RBD;
  1043. break;
  1044. case VIR_STORAGE_POOL_SHEEPDOG:
  1045. flags |= VIR_CONNECT_LIST_STORAGE_POOLS_SHEEPDOG;
  1046. break;
  1047. case VIR_STORAGE_POOL_GLUSTER:
  1048. flags |= VIR_CONNECT_LIST_STORAGE_POOLS_GLUSTER;
  1049. break;
  1050. case VIR_STORAGE_POOL_ZFS:
  1051. flags |= VIR_CONNECT_LIST_STORAGE_POOLS_ZFS;
  1052. break;
  1053. case VIR_STORAGE_POOL_VSTORAGE:
  1054. flags |= VIR_CONNECT_LIST_STORAGE_POOLS_VSTORAGE;
  1055. break;
  1056. case VIR_STORAGE_POOL_LAST:
  1057. break;
  1058. }
  1059. }
  1060. virStringListFree(poolTypes);
  1061. }
  1062. if (!(list = virshStoragePoolListCollect(ctl, flags)))
  1063. goto cleanup;
  1064. poolInfoTexts = vshCalloc(ctl, list->npools, sizeof(*poolInfoTexts));
  1065. /* Collect the storage pool information for display */
  1066. for (i = 0; i < list->npools; i++) {
  1067. int autostart = 0, persistent = 0;
  1068. /* Retrieve the autostart status of the pool */
  1069. if (virStoragePoolGetAutostart(list->pools[i], &autostart) < 0)
  1070. poolInfoTexts[i].autostart = g_strdup(_("no autostart"));
  1071. else
  1072. poolInfoTexts[i].autostart = g_strdup(autostart ? _("yes") : _("no"));
  1073. /* Retrieve the persistence status of the pool */
  1074. if (details) {
  1075. persistent = virStoragePoolIsPersistent(list->pools[i]);
  1076. vshDebug(ctl, VSH_ERR_DEBUG, "Persistent flag value: %d\n",
  1077. persistent);
  1078. if (persistent < 0)
  1079. poolInfoTexts[i].persistent = g_strdup(_("unknown"));
  1080. else
  1081. poolInfoTexts[i].persistent = g_strdup(persistent ? _("yes") : _("no"));
  1082. }
  1083. /* Collect further extended information about the pool */
  1084. if (virStoragePoolGetInfo(list->pools[i], &info) != 0) {
  1085. /* Something went wrong retrieving pool info, cope with it */
  1086. vshError(ctl, "%s", _("Could not retrieve pool information"));
  1087. poolInfoTexts[i].state = g_strdup(_("unknown"));
  1088. if (details) {
  1089. poolInfoTexts[i].capacity = g_strdup(_("unknown"));
  1090. poolInfoTexts[i].allocation = g_strdup(_("unknown"));
  1091. poolInfoTexts[i].available = g_strdup(_("unknown"));
  1092. }
  1093. } else {
  1094. /* Decide which state string to display */
  1095. if (details) {
  1096. const char *state = virshStoragePoolStateToString(info.state);
  1097. poolInfoTexts[i].state = g_strdup(state);
  1098. /* Create the pool size related strings */
  1099. if (info.state == VIR_STORAGE_POOL_RUNNING ||
  1100. info.state == VIR_STORAGE_POOL_DEGRADED) {
  1101. double val;
  1102. const char *unit;
  1103. val = vshPrettyCapacity(info.capacity, &unit);
  1104. poolInfoTexts[i].capacity = g_strdup_printf("%.2lf %s", val,
  1105. unit);
  1106. val = vshPrettyCapacity(info.allocation, &unit);
  1107. poolInfoTexts[i].allocation = g_strdup_printf("%.2lf %s", val,
  1108. unit);
  1109. val = vshPrettyCapacity(info.available, &unit);
  1110. poolInfoTexts[i].available = g_strdup_printf("%.2lf %s", val,
  1111. unit);
  1112. } else {
  1113. /* Capacity related information isn't available */
  1114. poolInfoTexts[i].capacity = g_strdup(_("-"));
  1115. poolInfoTexts[i].allocation = g_strdup(_("-"));
  1116. poolInfoTexts[i].available = g_strdup(_("-"));
  1117. }
  1118. } else {
  1119. /* --details option was not specified, only active/inactive
  1120. * state strings are used */
  1121. if (virStoragePoolIsActive(list->pools[i]))
  1122. poolInfoTexts[i].state = g_strdup(_("active"));
  1123. else
  1124. poolInfoTexts[i].state = g_strdup(_("inactive"));
  1125. }
  1126. }
  1127. }
  1128. /* If the --details option wasn't selected, we output the pool
  1129. * info using the fixed string format from previous versions to
  1130. * maintain backward compatibility.
  1131. */
  1132. /* Output basic info then return if --details option not selected */
  1133. if (!details) {
  1134. if (uuid || name) {
  1135. for (i = 0; i < list->npools; i++) {
  1136. if (uuid) {
  1137. char uuid_str[VIR_UUID_STRING_BUFLEN];
  1138. virStoragePoolGetUUIDString(list->pools[i], uuid_str);
  1139. vshPrint(ctl, "%-36s%c", uuid_str, name ? ' ': '\n');
  1140. }
  1141. if (name) {
  1142. const char *name_str =
  1143. virStoragePoolGetName(list->pools[i]);
  1144. vshPrint(ctl, "%-20s\n", name_str);
  1145. }
  1146. }
  1147. ret = true;
  1148. goto cleanup;
  1149. }
  1150. /* Output old style header */
  1151. table = vshTableNew(_("Name"), _("State"), _("Autostart"), NULL);
  1152. if (!table)
  1153. goto cleanup;
  1154. /* Output old style pool info */
  1155. for (i = 0; i < list->npools; i++) {
  1156. const char *name_str = virStoragePoolGetName(list->pools[i]);
  1157. if (vshTableRowAppend(table,
  1158. name_str,
  1159. poolInfoTexts[i].state,
  1160. poolInfoTexts[i].autostart,
  1161. NULL) < 0)
  1162. goto cleanup;
  1163. }
  1164. vshTablePrintToStdout(table, ctl);
  1165. /* Cleanup and return */
  1166. ret = true;
  1167. goto cleanup;
  1168. }
  1169. /* We only get here if the --details option was selected. */
  1170. /* Insert the header into table */
  1171. table = vshTableNew(_("Name"), _("State"), _("Autostart"), _("Persistent"),
  1172. _("Capacity"), _("Allocation"), _("Available"), NULL);
  1173. if (!table)
  1174. goto cleanup;
  1175. /* Insert the pool info rows into table */
  1176. for (i = 0; i < list->npools; i++) {
  1177. if (vshTableRowAppend(table,
  1178. virStoragePoolGetName(list->pools[i]),
  1179. poolInfoTexts[i].state,
  1180. poolInfoTexts[i].autostart,
  1181. poolInfoTexts[i].persistent,
  1182. poolInfoTexts[i].capacity,
  1183. poolInfoTexts[i].allocation,
  1184. poolInfoTexts[i].available,
  1185. NULL) < 0)
  1186. goto cleanup;
  1187. }
  1188. vshTablePrintToStdout(table, ctl);
  1189. /* Cleanup and return */
  1190. ret = true;
  1191. cleanup:
  1192. vshTableFree(table);
  1193. if (list && list->npools) {
  1194. for (i = 0; i < list->npools; i++) {
  1195. VIR_FREE(poolInfoTexts[i].state);
  1196. VIR_FREE(poolInfoTexts[i].autostart);
  1197. VIR_FREE(poolInfoTexts[i].persistent);
  1198. VIR_FREE(poolInfoTexts[i].capacity);
  1199. VIR_FREE(poolInfoTexts[i].allocation);
  1200. VIR_FREE(poolInfoTexts[i].available);
  1201. }
  1202. }
  1203. VIR_FREE(poolInfoTexts);
  1204. virshStoragePoolListFree(list);
  1205. return ret;
  1206. }
  1207. /*
  1208. * "find-storage-pool-sources-as" command
  1209. */
  1210. static const vshCmdInfo info_find_storage_pool_sources_as[] = {
  1211. {.name = "help",
  1212. .data = N_("find potential storage pool sources")
  1213. },
  1214. {.name = "desc",
  1215. .data = N_("Returns XML <sources> document.")
  1216. },
  1217. {.name = NULL}
  1218. };
  1219. static const vshCmdOptDef opts_find_storage_pool_sources_as[] = {
  1220. {.name = "type",
  1221. .type = VSH_OT_DATA,
  1222. .flags = VSH_OFLAG_REQ,
  1223. .help = N_("type of storage pool sources to find")
  1224. },
  1225. {.name = "host",
  1226. .type = VSH_OT_STRING,
  1227. .help = N_("optional host to query")
  1228. },
  1229. {.name = "port",
  1230. .type = VSH_OT_STRING,
  1231. .help = N_("optional port to query")
  1232. },
  1233. {.name = "initiator",
  1234. .type = VSH_OT_STRING,
  1235. .help = N_("optional initiator IQN to use for query")
  1236. },
  1237. {.name = NULL}
  1238. };
  1239. static bool
  1240. cmdPoolDiscoverSourcesAs(vshControl * ctl, const vshCmd * cmd G_GNUC_UNUSED)
  1241. {
  1242. const char *type = NULL, *host = NULL;
  1243. char *srcSpec = NULL;
  1244. char *srcList;
  1245. const char *initiator = NULL;
  1246. virshControlPtr priv = ctl->privData;
  1247. if (vshCommandOptStringReq(ctl, cmd, "type", &type) < 0 ||
  1248. vshCommandOptStringReq(ctl, cmd, "host", &host) < 0 ||
  1249. vshCommandOptStringReq(ctl, cmd, "initiator", &initiator) < 0)
  1250. return false;
  1251. if (host) {
  1252. const char *port = NULL;
  1253. virBuffer buf = VIR_BUFFER_INITIALIZER;
  1254. if (vshCommandOptStringReq(ctl, cmd, "port", &port) < 0) {
  1255. vshError(ctl, "%s", _("missing argument"));
  1256. virBufferFreeAndReset(&buf);
  1257. return false;
  1258. }
  1259. virBufferAddLit(&buf, "<source>\n");
  1260. virBufferAdjustIndent(&buf, 2);
  1261. virBufferAsprintf(&buf, "<host name='%s'", host);
  1262. if (port)
  1263. virBufferAsprintf(&buf, " port='%s'", port);
  1264. virBufferAddLit(&buf, "/>\n");
  1265. if (initiator) {
  1266. virBufferAddLit(&buf, "<initiator>\n");
  1267. virBufferAdjustIndent(&buf, 2);
  1268. virBufferAsprintf(&buf, "<iqn name='%s'/>\n", initiator);
  1269. virBufferAdjustIndent(&buf, -2);
  1270. virBufferAddLit(&buf, "</initiator>\n");
  1271. }
  1272. virBufferAdjustIndent(&buf, -2);
  1273. virBufferAddLit(&buf, "</source>\n");
  1274. srcSpec = virBufferContentAndReset(&buf);
  1275. }
  1276. srcList = virConnectFindStoragePoolSources(priv->conn, type, srcSpec, 0);
  1277. VIR_FREE(srcSpec);
  1278. if (srcList == NULL) {
  1279. vshError(ctl, _("Failed to find any %s pool sources"), type);
  1280. return false;
  1281. }
  1282. vshPrint(ctl, "%s", srcList);
  1283. VIR_FREE(srcList);
  1284. return true;
  1285. }
  1286. /*
  1287. * "find-storage-pool-sources" command
  1288. */
  1289. static const vshCmdInfo info_find_storage_pool_sources[] = {
  1290. {.name = "help",
  1291. .data = N_("discover potential storage pool sources")
  1292. },
  1293. {.name = "desc",
  1294. .data = N_("Returns XML <sources> document.")
  1295. },
  1296. {.name = NULL}
  1297. };
  1298. static const vshCmdOptDef opts_find_storage_pool_sources[] = {
  1299. {.name = "type",
  1300. .type = VSH_OT_DATA,
  1301. .flags = VSH_OFLAG_REQ,
  1302. .help = N_("type of storage pool sources to discover")
  1303. },
  1304. {.name = "srcSpec",
  1305. .type = VSH_OT_STRING,
  1306. .help = N_("optional file of source xml to query for pools")
  1307. },
  1308. {.name = NULL}
  1309. };
  1310. static bool
  1311. cmdPoolDiscoverSources(vshControl * ctl, const vshCmd * cmd G_GNUC_UNUSED)
  1312. {
  1313. const char *type = NULL, *srcSpecFile = NULL;
  1314. char *srcSpec = NULL, *srcList;
  1315. virshControlPtr priv = ctl->privData;
  1316. if (vshCommandOptStringReq(ctl, cmd, "type", &type) < 0)
  1317. return false;
  1318. if (vshCommandOptStringReq(ctl, cmd, "srcSpec", &srcSpecFile) < 0)
  1319. return false;
  1320. if (srcSpecFile && virFileReadAll(srcSpecFile, VSH_MAX_XML_FILE,
  1321. &srcSpec) < 0)
  1322. return false;
  1323. srcList = virConnectFindStoragePoolSources(priv->conn, type, srcSpec, 0);
  1324. VIR_FREE(srcSpec);
  1325. if (srcList == NULL) {
  1326. vshError(ctl, _("Failed to find any %s pool sources"), type);
  1327. return false;
  1328. }
  1329. vshPrint(ctl, "%s", srcList);
  1330. VIR_FREE(srcList);
  1331. return true;
  1332. }
  1333. /*
  1334. * "pool-info" command
  1335. */
  1336. static const vshCmdInfo info_pool_info[] = {
  1337. {.name = "help",
  1338. .data = N_("storage pool information")
  1339. },
  1340. {.name = "desc",
  1341. .data = N_("Returns basic information about the storage pool.")
  1342. },
  1343. {.name = NULL}
  1344. };
  1345. static const vshCmdOptDef opts_pool_info[] = {
  1346. VIRSH_COMMON_OPT_POOL_FULL(0),
  1347. {.name = "bytes",
  1348. .type = VSH_OT_BOOL,
  1349. .help = N_("Reture pool info in bytes"),
  1350. },
  1351. {.name = NULL}
  1352. };
  1353. static bool
  1354. cmdPoolInfo(vshControl *ctl, const vshCmd *cmd)
  1355. {
  1356. virStoragePoolInfo info;
  1357. virStoragePoolPtr pool;
  1358. int autostart = 0;
  1359. int persistent = 0;
  1360. bool ret = true;
  1361. bool bytes = false;
  1362. char uuid[VIR_UUID_STRING_BUFLEN];
  1363. if (!(pool = virshCommandOptPool(ctl, cmd, "pool", NULL)))
  1364. return false;
  1365. bytes = vshCommandOptBool(cmd, "bytes");
  1366. vshPrint(ctl, "%-15s %s\n", _("Name:"), virStoragePoolGetName(pool));
  1367. if (virStoragePoolGetUUIDString(pool, &uuid[0]) == 0)
  1368. vshPrint(ctl, "%-15s %s\n", _("UUID:"), uuid);
  1369. if (virStoragePoolGetInfo(pool, &info) == 0) {
  1370. double val;
  1371. const char *unit;
  1372. vshPrint(ctl, "%-15s %s\n", _("State:"),
  1373. virshStoragePoolStateToString(info.state));
  1374. /* Check and display whether the pool is persistent or not */
  1375. persistent = virStoragePoolIsPersistent(pool);
  1376. vshDebug(ctl, VSH_ERR_DEBUG, "Pool persistent flag value: %d\n",
  1377. persistent);
  1378. if (persistent < 0)
  1379. vshPrint(ctl, "%-15s %s\n", _("Persistent:"), _("unknown"));
  1380. else
  1381. vshPrint(ctl, "%-15s %s\n", _("Persistent:"), persistent ? _("yes") : _("no"));
  1382. /* Check and display whether the pool is autostarted or not */
  1383. if (virStoragePoolGetAutostart(pool, &autostart) < 0)
  1384. vshPrint(ctl, "%-15s %s\n", _("Autostart:"), _("no autostart"));
  1385. else
  1386. vshPrint(ctl, "%-15s %s\n", _("Autostart:"), autostart ? _("yes") : _("no"));
  1387. if (info.state == VIR_STORAGE_POOL_RUNNING ||
  1388. info.state == VIR_STORAGE_POOL_DEGRADED) {
  1389. if (bytes) {
  1390. vshPrint(ctl, "%-15s %llu\n", _("Capacity:"), info.capacity);
  1391. vshPrint(ctl, "%-15s %llu\n", _("Allocation:"), info.allocation);
  1392. vshPrint(ctl, "%-15s %llu\n", _("Available:"), info.available);
  1393. } else {
  1394. val = vshPrettyCapacity(info.capacity, &unit);
  1395. vshPrint(ctl, "%-15s %2.2lf %s\n", _("Capacity:"), val, unit);
  1396. val = vshPrettyCapacity(info.allocation, &unit);
  1397. vshPrint(ctl, "%-15s %2.2lf %s\n", _("Allocation:"), val, unit);
  1398. val = vshPrettyCapacity(info.available, &unit);
  1399. vshPrint(ctl, "%-15s %2.2lf %s\n", _("Available:"), val, unit);
  1400. }
  1401. }
  1402. } else {
  1403. ret = false;
  1404. }
  1405. virStoragePoolFree(pool);
  1406. return ret;
  1407. }
  1408. /*
  1409. * "pool-name" command
  1410. */
  1411. static const vshCmdInfo info_pool_name[] = {
  1412. {.name = "help",
  1413. .data = N_("convert a pool UUID to pool name")
  1414. },
  1415. {.name = "desc",
  1416. .data = ""
  1417. },
  1418. {.name = NULL}
  1419. };
  1420. static const vshCmdOptDef opts_pool_name[] = {
  1421. VIRSH_COMMON_OPT_POOL_FULL(0),
  1422. {.name = NULL}
  1423. };
  1424. static bool
  1425. cmdPoolName(vshControl *ctl, const vshCmd *cmd)
  1426. {
  1427. virStoragePoolPtr pool;
  1428. if (!(pool = virshCommandOptPoolBy(ctl, cmd, "pool", NULL, VIRSH_BYUUID)))
  1429. return false;
  1430. vshPrint(ctl, "%s\n", virStoragePoolGetName(pool));
  1431. virStoragePoolFree(pool);
  1432. return true;
  1433. }
  1434. /*
  1435. * "pool-start" command
  1436. */
  1437. static const vshCmdInfo info_pool_start[] = {
  1438. {.name = "help",
  1439. .data = N_("start a (previously defined) inactive pool")
  1440. },
  1441. {.name = "desc",
  1442. .data = N_("Start a pool.")
  1443. },
  1444. {.name = NULL}
  1445. };
  1446. static const vshCmdOptDef opts_pool_start[] = {
  1447. VIRSH_COMMON_OPT_POOL_FULL(VIR_CONNECT_LIST_STORAGE_POOLS_INACTIVE),
  1448. VIRSH_COMMON_OPT_POOL_BUILD,
  1449. VIRSH_COMMON_OPT_POOL_NO_OVERWRITE,
  1450. VIRSH_COMMON_OPT_POOL_OVERWRITE,
  1451. {.name = NULL}
  1452. };
  1453. static bool
  1454. cmdPoolStart(vshControl *ctl, const vshCmd *cmd)
  1455. {
  1456. virStoragePoolPtr pool;
  1457. bool ret = true;
  1458. const char *name = NULL;
  1459. bool build;
  1460. bool overwrite;
  1461. bool no_overwrite;
  1462. unsigned int flags = 0;
  1463. if (!(pool = virshCommandOptPool(ctl, cmd, "pool", &name)))
  1464. return false;
  1465. build = vshCommandOptBool(cmd, "build");
  1466. overwrite = vshCommandOptBool(cmd, "overwrite");
  1467. no_overwrite = vshCommandOptBool(cmd, "no-overwrite");
  1468. VSH_EXCLUSIVE_OPTIONS_EXPR("overwrite", overwrite,
  1469. "no-overwrite", no_overwrite);
  1470. if (build)
  1471. flags |= VIR_STORAGE_POOL_CREATE_WITH_BUILD;
  1472. if (overwrite)
  1473. flags |= VIR_STORAGE_POOL_CREATE_WITH_BUILD_OVERWRITE;
  1474. if (no_overwrite)
  1475. flags |= VIR_STORAGE_POOL_CREATE_WITH_BUILD_NO_OVERWRITE;
  1476. if (virStoragePoolCreate(pool, flags) == 0) {
  1477. vshPrintExtra(ctl, _("Pool %s started\n"), name);
  1478. } else {
  1479. vshError(ctl, _("Failed to start pool %s"), name);
  1480. ret = false;
  1481. }
  1482. virStoragePoolFree(pool);
  1483. return ret;
  1484. }
  1485. /*
  1486. * "pool-undefine" command
  1487. */
  1488. static const vshCmdInfo info_pool_undefine[] = {
  1489. {.name = "help",
  1490. .data = N_("undefine an inactive pool")
  1491. },
  1492. {.name = "desc",
  1493. .data = N_("Undefine the configuration for an inactive pool.")
  1494. },
  1495. {.name = NULL}
  1496. };
  1497. static const vshCmdOptDef opts_pool_undefine[] = {
  1498. VIRSH_COMMON_OPT_POOL_FULL(VIR_CONNECT_LIST_STORAGE_POOLS_PERSISTENT),
  1499. {.name = NULL}
  1500. };
  1501. static bool
  1502. cmdPoolUndefine(vshControl *ctl, const vshCmd *cmd)
  1503. {
  1504. virStoragePoolPtr pool;
  1505. bool ret = true;
  1506. const char *name;
  1507. if (!(pool = virshCommandOptPool(ctl, cmd, "pool", &name)))
  1508. return false;
  1509. if (virStoragePoolUndefine(pool) == 0) {
  1510. vshPrintExtra(ctl, _("Pool %s has been undefined\n"), name);
  1511. } else {
  1512. vshError(ctl, _("Failed to undefine pool %s"), name);
  1513. ret = false;
  1514. }
  1515. virStoragePoolFree(pool);
  1516. return ret;
  1517. }
  1518. /*
  1519. * "pool-uuid" command
  1520. */
  1521. static const vshCmdInfo info_pool_uuid[] = {
  1522. {.name = "help",
  1523. .data = N_("convert a pool name to pool UUID")
  1524. },
  1525. {.name = "desc",
  1526. .data = ""
  1527. },
  1528. {.name = NULL}
  1529. };
  1530. static const vshCmdOptDef opts_pool_uuid[] = {
  1531. VIRSH_COMMON_OPT_POOL_FULL(0),
  1532. {.name = NULL}
  1533. };
  1534. static bool
  1535. cmdPoolUuid(vshControl *ctl, const vshCmd *cmd)
  1536. {
  1537. virStoragePoolPtr pool;
  1538. char uuid[VIR_UUID_STRING_BUFLEN];
  1539. if (!(pool = virshCommandOptPoolBy(ctl, cmd, "pool", NULL, VIRSH_BYNAME)))
  1540. return false;
  1541. if (virStoragePoolGetUUIDString(pool, uuid) != -1)
  1542. vshPrint(ctl, "%s\n", uuid);
  1543. else
  1544. vshError(ctl, "%s", _("failed to get pool UUID"));
  1545. virStoragePoolFree(pool);
  1546. return true;
  1547. }
  1548. /*
  1549. * "pool-edit" command
  1550. */
  1551. static const vshCmdInfo info_pool_edit[] = {
  1552. {.name = "help",
  1553. .data = N_("edit XML configuration for a storage pool")
  1554. },
  1555. {.name = "desc",
  1556. .data = N_("Edit the XML configuration for a storage pool.")
  1557. },
  1558. {.name = NULL}
  1559. };
  1560. static const vshCmdOptDef opts_pool_edit[] = {
  1561. VIRSH_COMMON_OPT_POOL_FULL(0),
  1562. {.name = NULL}
  1563. };
  1564. static bool
  1565. cmdPoolEdit(vshControl *ctl, const vshCmd *cmd)
  1566. {
  1567. bool ret = false;
  1568. virStoragePoolPtr pool = NULL;
  1569. virStoragePoolPtr pool_edited = NULL;
  1570. unsigned int flags = VIR_STORAGE_XML_INACTIVE;
  1571. char *tmp_desc = NULL;
  1572. virshControlPtr priv = ctl->privData;
  1573. pool = virshCommandOptPool(ctl, cmd, "pool", NULL);
  1574. if (pool == NULL)
  1575. goto cleanup;
  1576. /* Some old daemons don't support _INACTIVE flag */
  1577. if (!(tmp_desc = virStoragePoolGetXMLDesc(pool, flags))) {
  1578. if (last_error->code == VIR_ERR_INVALID_ARG) {
  1579. flags &= ~VIR_STORAGE_XML_INACTIVE;
  1580. vshResetLibvirtError();
  1581. } else {
  1582. goto cleanup;
  1583. }
  1584. } else {
  1585. VIR_FREE(tmp_desc);
  1586. }
  1587. #define EDIT_GET_XML virStoragePoolGetXMLDesc(pool, flags)
  1588. #define EDIT_NOT_CHANGED \
  1589. do { \
  1590. vshPrintExtra(ctl, _("Pool %s XML configuration not changed.\n"), \
  1591. virStoragePoolGetName(pool)); \
  1592. ret = true; \
  1593. goto edit_cleanup; \
  1594. } while (0)
  1595. #define EDIT_DEFINE \
  1596. (pool_edited = virStoragePoolDefineXML(priv->conn, doc_edited, 0))
  1597. #include "virsh-edit.c"
  1598. vshPrintExtra(ctl, _("Pool %s XML configuration edited.\n"),
  1599. virStoragePoolGetName(pool_edited));
  1600. ret = true;
  1601. cleanup:
  1602. if (pool)
  1603. virStoragePoolFree(pool);
  1604. if (pool_edited)
  1605. virStoragePoolFree(pool_edited);
  1606. return ret;
  1607. }
  1608. /*
  1609. * "pool-event" command
  1610. */
  1611. VIR_ENUM_DECL(virshPoolEvent);
  1612. VIR_ENUM_IMPL(virshPoolEvent,
  1613. VIR_STORAGE_POOL_EVENT_LAST,
  1614. N_("Defined"),
  1615. N_("Undefined"),
  1616. N_("Started"),
  1617. N_("Stopped"),
  1618. N_("Created"),
  1619. N_("Deleted"));
  1620. static const char *
  1621. virshPoolEventToString(int event)
  1622. {
  1623. const char *str = virshPoolEventTypeToString(event);
  1624. return str ? _(str) : _("unknown");
  1625. }
  1626. struct virshPoolEventData {
  1627. vshControl *ctl;
  1628. bool loop;
  1629. bool timestamp;
  1630. int count;
  1631. virshPoolEventCallback *cb;
  1632. };
  1633. typedef struct virshPoolEventData virshPoolEventData;
  1634. static void
  1635. vshEventLifecyclePrint(virConnectPtr conn G_GNUC_UNUSED,
  1636. virStoragePoolPtr pool,
  1637. int event,
  1638. int detail G_GNUC_UNUSED,
  1639. void *opaque)
  1640. {
  1641. virshPoolEventData *data = opaque;
  1642. if (!data->loop && data->count)
  1643. return;
  1644. if (data->timestamp) {
  1645. char timestamp[VIR_TIME_STRING_BUFLEN];
  1646. if (virTimeStringNowRaw(timestamp) < 0)
  1647. timestamp[0] = '\0';
  1648. vshPrint(data->ctl, _("%s: event 'lifecycle' for storage pool %s: %s\n"),
  1649. timestamp,
  1650. virStoragePoolGetName(pool),
  1651. virshPoolEventToString(event));
  1652. } else {
  1653. vshPrint(data->ctl, _("event 'lifecycle' for storage pool %s: %s\n"),
  1654. virStoragePoolGetName(pool),
  1655. virshPoolEventToString(event));
  1656. }
  1657. data->count++;
  1658. if (!data->loop)
  1659. vshEventDone(data->ctl);
  1660. }
  1661. static void
  1662. vshEventGenericPrint(virConnectPtr conn G_GNUC_UNUSED,
  1663. virStoragePoolPtr pool,
  1664. void *opaque)
  1665. {
  1666. virshPoolEventData *data = opaque;
  1667. if (!data->loop && data->count)
  1668. return;
  1669. if (data->timestamp) {
  1670. char timestamp[VIR_TIME_STRING_BUFLEN];
  1671. if (virTimeStringNowRaw(timestamp) < 0)
  1672. timestamp[0] = '\0';
  1673. vshPrint(data->ctl, _("%s: event '%s' for storage pool %s\n"),
  1674. timestamp,
  1675. data->cb->name,
  1676. virStoragePoolGetName(pool));
  1677. } else {
  1678. vshPrint(data->ctl, _("event '%s' for storage pool %s\n"),
  1679. data->cb->name,
  1680. virStoragePoolGetName(pool));
  1681. }
  1682. data->count++;
  1683. if (!data->loop)
  1684. vshEventDone(data->ctl);
  1685. }
  1686. virshPoolEventCallback virshPoolEventCallbacks[] = {
  1687. { "lifecycle",
  1688. VIR_STORAGE_POOL_EVENT_CALLBACK(vshEventLifecyclePrint), },
  1689. { "refresh", vshEventGenericPrint, }
  1690. };
  1691. G_STATIC_ASSERT(VIR_STORAGE_POOL_EVENT_ID_LAST == G_N_ELEMENTS(virshPoolEventCallbacks));
  1692. static const vshCmdInfo info_pool_event[] = {
  1693. {.name = "help",
  1694. .data = N_("Storage Pool Events")
  1695. },
  1696. {.name = "desc",
  1697. .data = N_("List event types, or wait for storage pool events to occur")
  1698. },
  1699. {.name = NULL}
  1700. };
  1701. static const vshCmdOptDef opts_pool_event[] = {
  1702. {.name = "pool",
  1703. .type = VSH_OT_STRING,
  1704. .help = N_("filter by storage pool name or uuid")
  1705. },
  1706. {.name = "event",
  1707. .type = VSH_OT_STRING,
  1708. .completer = virshPoolEventNameCompleter,
  1709. .help = N_("which event type to wait for")
  1710. },
  1711. {.name = "loop",
  1712. .type = VSH_OT_BOOL,
  1713. .help = N_("loop until timeout or interrupt, rather than one-shot")
  1714. },
  1715. {.name = "timeout",
  1716. .type = VSH_OT_INT,
  1717. .help = N_("timeout seconds")
  1718. },
  1719. {.name = "list",
  1720. .type = VSH_OT_BOOL,
  1721. .help = N_("list valid event types")
  1722. },
  1723. {.name = "timestamp",
  1724. .type = VSH_OT_BOOL,
  1725. .help = N_("show timestamp for each printed event")
  1726. },
  1727. {.name = NULL}
  1728. };
  1729. static bool
  1730. cmdPoolEvent(vshControl *ctl, const vshCmd *cmd)
  1731. {
  1732. virStoragePoolPtr pool = NULL;
  1733. bool ret = false;
  1734. int eventId = -1;
  1735. int timeout = 0;
  1736. virshPoolEventData data;
  1737. const char *eventName = NULL;
  1738. int event;
  1739. virshControlPtr priv = ctl->privData;
  1740. if (vshCommandOptBool(cmd, "list")) {
  1741. size_t i;
  1742. for (i = 0; i < VIR_STORAGE_POOL_EVENT_ID_LAST; i++)
  1743. vshPrint(ctl, "%s\n", virshPoolEventCallbacks[i].name);
  1744. return true;
  1745. }
  1746. if (vshCommandOptStringReq(ctl, cmd, "event", &eventName) < 0)
  1747. return false;
  1748. if (!eventName) {
  1749. vshError(ctl, "%s", _("either --list or --event <type> is required"));
  1750. return false;
  1751. }
  1752. for (event = 0; event < VIR_STORAGE_POOL_EVENT_ID_LAST; event++)
  1753. if (STREQ(eventName, virshPoolEventCallbacks[event].name))
  1754. break;
  1755. if (event == VIR_STORAGE_POOL_EVENT_ID_LAST) {
  1756. vshError(ctl, _("unknown event type %s"), eventName);
  1757. return false;
  1758. }
  1759. data.ctl = ctl;
  1760. data.loop = vshCommandOptBool(cmd, "loop");
  1761. data.timestamp = vshCommandOptBool(cmd, "timestamp");
  1762. data.count = 0;
  1763. data.cb = &virshPoolEventCallbacks[event];
  1764. if (vshCommandOptTimeoutToMs(ctl, cmd, &timeout) < 0)
  1765. return false;
  1766. if (vshCommandOptBool(cmd, "pool"))
  1767. pool = virshCommandOptPool(ctl, cmd, "pool", NULL);
  1768. if (vshEventStart(ctl, timeout) < 0)
  1769. goto cleanup;
  1770. if ((eventId = virConnectStoragePoolEventRegisterAny(priv->conn, pool, event,
  1771. data.cb->cb,
  1772. &data, NULL)) < 0)
  1773. goto cleanup;
  1774. switch (vshEventWait(ctl)) {
  1775. case VSH_EVENT_INTERRUPT:
  1776. vshPrint(ctl, "%s", _("event loop interrupted\n"));
  1777. break;
  1778. case VSH_EVENT_TIMEOUT:
  1779. vshPrint(ctl, "%s", _("event loop timed out\n"));
  1780. break;
  1781. case VSH_EVENT_DONE:
  1782. break;
  1783. default:
  1784. goto cleanup;
  1785. }
  1786. vshPrint(ctl, _("events received: %d\n"), data.count);
  1787. if (data.count)
  1788. ret = true;
  1789. cleanup:
  1790. vshEventCleanup(ctl);
  1791. if (eventId >= 0 &&
  1792. virConnectStoragePoolEventDeregisterAny(priv->conn, eventId) < 0)
  1793. ret = false;
  1794. if (pool)
  1795. virStoragePoolFree(pool);
  1796. return ret;
  1797. }
  1798. /*
  1799. * "pool-capabilities" command
  1800. */
  1801. static const vshCmdInfo info_pool_capabilities[] = {
  1802. {.name = "help",
  1803. .data = N_("storage pool capabilities")
  1804. },
  1805. {.name = "desc",
  1806. .data = N_("Returns capabilities of storage pool support.")
  1807. },
  1808. {.name = NULL}
  1809. };
  1810. static const vshCmdOptDef opts_pool_capabilities[] = {
  1811. {.name = NULL}
  1812. };
  1813. static bool
  1814. cmdPoolCapabilities(vshControl *ctl,
  1815. const vshCmd *cmd G_GNUC_UNUSED)
  1816. {
  1817. const unsigned int flags = 0; /* No flags so far */
  1818. virshControlPtr priv = ctl->privData;
  1819. g_autofree char *caps = NULL;
  1820. caps = virConnectGetStoragePoolCapabilities(priv->conn, flags);
  1821. if (!caps) {
  1822. vshError(ctl, "%s", _("failed to get storage pool capabilities"));
  1823. return false;
  1824. }
  1825. vshPrint(ctl, "%s\n", caps);
  1826. return true;
  1827. }
  1828. const vshCmdDef storagePoolCmds[] = {
  1829. {.name = "find-storage-pool-sources-as",
  1830. .handler = cmdPoolDiscoverSourcesAs,
  1831. .opts = opts_find_storage_pool_sources_as,
  1832. .info = info_find_storage_pool_sources_as,
  1833. .flags = 0
  1834. },
  1835. {.name = "find-storage-pool-sources",
  1836. .handler = cmdPoolDiscoverSources,
  1837. .opts = opts_find_storage_pool_sources,
  1838. .info = info_find_storage_pool_sources,
  1839. .flags = 0
  1840. },
  1841. {.name = "pool-autostart",
  1842. .handler = cmdPoolAutostart,
  1843. .opts = opts_pool_autostart,
  1844. .info = info_pool_autostart,
  1845. .flags = 0
  1846. },
  1847. {.name = "pool-build",
  1848. .handler = cmdPoolBuild,
  1849. .opts = opts_pool_build,
  1850. .info = info_pool_build,
  1851. .flags = 0
  1852. },
  1853. {.name = "pool-create-as",
  1854. .handler = cmdPoolCreateAs,
  1855. .opts = opts_pool_create_as,
  1856. .info = info_pool_create_as,
  1857. .flags = 0
  1858. },
  1859. {.name = "pool-create",
  1860. .handler = cmdPoolCreate,
  1861. .opts = opts_pool_create,
  1862. .info = info_pool_create,
  1863. .flags = 0
  1864. },
  1865. {.name = "pool-define-as",
  1866. .handler = cmdPoolDefineAs,
  1867. .opts = opts_pool_define_as,
  1868. .info = info_pool_define_as,
  1869. .flags = 0
  1870. },
  1871. {.name = "pool-define",
  1872. .handler = cmdPoolDefine,
  1873. .opts = opts_pool_define,
  1874. .info = info_pool_define,
  1875. .flags = 0
  1876. },
  1877. {.name = "pool-delete",
  1878. .handler = cmdPoolDelete,
  1879. .opts = opts_pool_delete,
  1880. .info = info_pool_delete,
  1881. .flags = 0
  1882. },
  1883. {.name = "pool-destroy",
  1884. .handler = cmdPoolDestroy,
  1885. .opts = opts_pool_destroy,
  1886. .info = info_pool_destroy,
  1887. .flags = 0
  1888. },
  1889. {.name = "pool-dumpxml",
  1890. .handler = cmdPoolDumpXML,
  1891. .opts = opts_pool_dumpxml,
  1892. .info = info_pool_dumpxml,
  1893. .flags = 0
  1894. },
  1895. {.name = "pool-edit",
  1896. .handler = cmdPoolEdit,
  1897. .opts = opts_pool_edit,
  1898. .info = info_pool_edit,
  1899. .flags = 0
  1900. },
  1901. {.name = "pool-info",
  1902. .handler = cmdPoolInfo,
  1903. .opts = opts_pool_info,
  1904. .info = info_pool_info,
  1905. .flags = 0
  1906. },
  1907. {.name = "pool-list",
  1908. .handler = cmdPoolList,
  1909. .opts = opts_pool_list,
  1910. .info = info_pool_list,
  1911. .flags = 0
  1912. },
  1913. {.name = "pool-name",
  1914. .handler = cmdPoolName,
  1915. .opts = opts_pool_name,
  1916. .info = info_pool_name,
  1917. .flags = 0
  1918. },
  1919. {.name = "pool-refresh",
  1920. .handler = cmdPoolRefresh,
  1921. .opts = opts_pool_refresh,
  1922. .info = info_pool_refresh,
  1923. .flags = 0
  1924. },
  1925. {.name = "pool-start",
  1926. .handler = cmdPoolStart,
  1927. .opts = opts_pool_start,
  1928. .info = info_pool_start,
  1929. .flags = 0
  1930. },
  1931. {.name = "pool-undefine",
  1932. .handler = cmdPoolUndefine,
  1933. .opts = opts_pool_undefine,
  1934. .info = info_pool_undefine,
  1935. .flags = 0
  1936. },
  1937. {.name = "pool-uuid",
  1938. .handler = cmdPoolUuid,
  1939. .opts = opts_pool_uuid,
  1940. .info = info_pool_uuid,
  1941. .flags = 0
  1942. },
  1943. {.name = "pool-event",
  1944. .handler = cmdPoolEvent,
  1945. .opts = opts_pool_event,
  1946. .info = info_pool_event,
  1947. .flags = 0
  1948. },
  1949. {.name = "pool-capabilities",
  1950. .handler = cmdPoolCapabilities,
  1951. .opts = opts_pool_capabilities,
  1952. .info = info_pool_capabilities,
  1953. .flags = 0
  1954. },
  1955. {.name = NULL}
  1956. };