1
0
mirror of git://sourceware.org/git/lvm2.git synced 2026-01-25 00:32:58 +03:00

Compare commits

...

41 Commits

Author SHA1 Message Date
Alasdair Kergon
154e9a2c47 pre-release 2007-03-19 21:12:54 +00:00
Milan Broz
84574a1257 Fix processing of exit status in init scripts 2007-03-16 17:15:36 +00:00
Alasdair Kergon
bf83527b64 Remove unnecessary memset() return value checks. [Jim Meyering] 2007-03-16 14:36:14 +00:00
Milan Broz
12c53622a0 Fix vgremove to require at least one vg argument. 2007-03-15 14:00:30 +00:00
Alasdair Kergon
d8f54cf891 Try to fix reading in of lvm1 striped LVs.
There are two fixes other than improving variable names and updating code
layout etc.
The loop counter is incremented by area_len instead of area_len * stripes;
the 3rd _check_stripe parameter is no longer multiplied by number of stripes.
2007-03-15 13:38:28 +00:00
Patrick Caulfield
625a671189 Flag nolocking as a clustered locking module as we need to be able
to look at clustered LVs at clvmd startup
2007-03-13 14:59:21 +00:00
Alasdair Kergon
6ebdad3102 Add a few missing pieces of vgname command line validation. 2007-03-09 21:25:33 +00:00
Alasdair Kergon
9a8f21aa03 Support the /dev/mapper prefix on most command lines. 2007-03-09 20:47:41 +00:00
Alasdair Kergon
291dd8edc2 post-release 2007-03-08 21:37:48 +00:00
Alasdair Kergon
de4c1daf29 pre-release 2007-03-08 21:28:13 +00:00
Alasdair Kergon
0b55d7d0d8 Fix vgrename active LV check to ignore differing vgids. 2007-03-08 21:08:25 +00:00
Alasdair Kergon
5d86fd8fdb Remove no-longer-used uuid_out parameter from activation info functions. 2007-03-08 19:58:04 +00:00
Alasdair Kergon
1b76eb1f59 Fix two more segfaults if an empty config file section encountered. 2007-03-08 19:22:52 +00:00
Alasdair Kergon
b05678d8bf Move .cache file into a new /etc/lvm/cache directory by default.
Add devices/cache_dir & devices/cache_file_prefix, deprecating devices/cache.
Create directory in fcntl_lock_file() if required.
2007-02-28 18:27:13 +00:00
Alasdair Kergon
781f4971c6 Exclude readline support from lvm.static 2007-02-14 16:51:48 +00:00
Alasdair Kergon
d02ac7b99a Fix a leak in a reporting error path. 2007-02-14 15:18:31 +00:00
Alasdair Kergon
b1b6c97f7c Fix a few leaks in reporting error paths. 2007-02-14 15:12:16 +00:00
Alasdair Kergon
baee28ab5c post-release 2007-02-13 16:16:15 +00:00
Alasdair Kergon
83edf68ff9 pre-release 2007-02-13 16:12:24 +00:00
Alasdair Kergon
c7588f91dd Correct -b and -P on a couple of man pages.
Add global/units to example.conf.
2007-02-13 16:04:01 +00:00
Alasdair Kergon
30b432adc5 Fix loading of segment_libraries. [gentoo] 2007-02-08 17:31:02 +00:00
Alasdair Kergon
7c9733eb5d If a PV reappears after it was removed from its VG, make it an orphan. 2007-02-07 13:29:52 +00:00
Alasdair Kergon
a223c3fea3 Improve dmeventd messaging protocol: drain pipe and tag messages. 2007-02-02 17:08:51 +00:00
Alasdair Kergon
d5250f4901 Fix some &->&& vgreduce cmdline validation. [Andre Noll] 2007-01-31 16:26:23 +00:00
Alasdair Kergon
25f29f4712 post-release 2007-01-30 21:37:18 +00:00
Alasdair Kergon
382af5563d pre-release 2007-01-30 18:08:17 +00:00
Alasdair Kergon
8cf3d165d3 Add warning to lvm2_monitoring_init_rhel4 if attempting to stop monitoring. 2007-01-30 18:02:15 +00:00
Alasdair Kergon
0fd6ce546f Fix vgsplit to handle mirrors.
Reorder fields in reporting field definitions.
2007-01-29 23:01:18 +00:00
Alasdair Kergon
b881c372bc post-release 2007-01-29 20:25:19 +00:00
Alasdair Kergon
94c5e7deb0 pre-release 2007-01-29 19:57:24 +00:00
Alasdair Kergon
c344766f3c Add recent reporting options to dmsetup man page.
Revise some report fields names.
2007-01-29 19:35:24 +00:00
Alasdair Kergon
67895de0bc help on help 2007-01-29 18:45:08 +00:00
Alasdair Kergon
ff00cb6990 help unused attr 2007-01-29 18:43:27 +00:00
Alasdair Kergon
2cc75c11ed add help -c for field list 2007-01-29 18:37:57 +00:00
Alasdair Kergon
cd79e58eda Add dmsetup 'help' command and update usage text. 2007-01-29 18:18:41 +00:00
Alasdair Kergon
6fa801f3d8 reorder report field definitions 2007-01-29 17:45:32 +00:00
Alasdair Kergon
684eecba1d Use fixed-size fields in report interface. 2007-01-29 17:23:54 +00:00
Alasdair Kergon
da9cf7e5de fix pvsegs report too 2007-01-27 02:32:31 +00:00
Alasdair Kergon
f57e7445fd Fix vgs to treat args as VGs even when PV fields are displayed. 2007-01-27 02:09:06 +00:00
Alasdair Kergon
fba1388719 Fix md signature check to handle both endiannesses. 2007-01-26 17:15:16 +00:00
Alasdair Kergon
80ed029c17 post-release 2007-01-25 23:40:33 +00:00
47 changed files with 968 additions and 511 deletions

View File

@@ -1 +1 @@
2.02.20-cvs (2007-01-25)
2.02.24-cvs (2007-03-19)

View File

@@ -1,3 +1,40 @@
Version 2.02.24 - 19th March 2007
=================================
Fix processing of exit status in init scripts
Fix vgremove to require at least one vg argument.
Fix reading of striped LVs in LVM1 format.
Flag nolocking as clustered so clvmd startup sees clustered LVs. (2.02.10)
Add a few missing pieces of vgname command line validation.
Support the /dev/mapper prefix on most command lines.
Version 2.02.23 - 8th March 2007
================================
Fix vgrename active LV check to ignore differing vgids.
Remove no-longer-used uuid_out parameter from activation info functions.
Fix two more segfaults if an empty config file section encountered.
Move .cache file into a new /etc/lvm/cache directory by default.
Add devices/cache_dir & devices/cache_file_prefix, deprecating devices/cache.
Create directory in fcntl_lock_file() if required.
Exclude readline support from lvm.static.
Fix a leak in a reporting error path (2.02.19).
Version 2.02.22 - 13th February 2007
====================================
Correct -b and -P on a couple of man pages.
Add global/units to example.conf.
Fix loading of segment_libraries.
If a PV reappears after it was removed from its VG, make it an orphan.
Don't update metadata automatically if VGIDs don't match.
Fix some vgreduce --removemissing command line validation.
Version 2.02.21 - 30th January 2007
===================================
Add warning to lvm2_monitoring_init_rhel4 if attempting to stop monitoring.
Fix vgsplit to handle mirrors.
Reorder fields in reporting field definitions.
Fix vgs to treat args as VGs even when PV fields are displayed.
Fix md signature check to handle both endiannesses.
Version 2.02.20 - 25th January 2007
===================================
dmeventd mirror sets ignore_suspended_devices and avoids scanning mirrors.

View File

@@ -1,3 +1,19 @@
Version 1.02.19 -
====================================
Remove unnecessary memset() return value checks.
Fix a few leaks in reporting error paths. [1.02.15+]
Version 1.02.18 - 13th February 2007
====================================
Improve dmeventd messaging protocol: drain pipe and tag messages.
Version 1.02.17 - 29th January 2007
===================================
Add recent reporting options to dmsetup man page.
Revise some report fields names.
Add dmsetup 'help' command and update usage text.
Use fixed-size fields in report interface and reorder.
Version 1.02.16 - 25th January 2007
===================================
Add some missing close() and fclose() return value checks.

View File

@@ -146,6 +146,7 @@ static LIST_INIT(_dso_registry);
/* Structure to keep parsed register variables from client message. */
struct message_data {
char *id;
char *dso_name; /* Name of DSO. */
char *device_uuid; /* Mapped device path. */
union {
@@ -225,8 +226,8 @@ static struct thread_status *_alloc_thread_status(struct message_data *data,
if (!ret)
return NULL;
if (!memset(ret, 0, sizeof(*ret)) ||
!(ret->device.uuid = dm_strdup(data->device_uuid))) {
memset(ret, 0, sizeof(*ret));
if (!(ret->device.uuid = dm_strdup(data->device_uuid))) {
dm_free(ret);
return NULL;
}
@@ -257,8 +258,8 @@ static struct dso_data *_alloc_dso_data(struct message_data *data)
if (!ret)
return NULL;
if (!memset(ret, 0, sizeof(*ret)) ||
!(ret->dso_name = dm_strdup(data->dso_name))) {
memset(ret, 0, sizeof(*ret));
if (!(ret->dso_name = dm_strdup(data->dso_name))) {
dm_free(ret);
return NULL;
}
@@ -320,6 +321,8 @@ static int _fetch_string(char **ptr, char **src, const int delimiter)
/* Free message memory. */
static void _free_message(struct message_data *message_data)
{
if (message_data->id)
dm_free(message_data->id);
if (message_data->dso_name)
dm_free(message_data->dso_name);
@@ -342,7 +345,8 @@ static int _parse_message(struct message_data *message_data)
* Retrieve application identifier, mapped device
* path and events # string from message.
*/
if (_fetch_string(&message_data->dso_name, &p, ' ') &&
if (_fetch_string(&message_data->id, &p, ' ') &&
_fetch_string(&message_data->dso_name, &p, ' ') &&
_fetch_string(&message_data->device_uuid, &p, ' ') &&
_fetch_string(&message_data->events.str, &p, ' ') &&
_fetch_string(&message_data->timeout.str, &p, ' ')) {
@@ -875,8 +879,8 @@ static struct dso_data *_load_dso(struct message_data *data)
syslog(LOG_ERR, "dmeventd %s dlopen failed: %s", data->dso_name,
dlerr);
data->msg->size =
dm_asprintf(&(data->msg->data), "%s dlopen failed: %s",
data->dso_name, dlerr);
dm_asprintf(&(data->msg->data), "%s %s dlopen failed: %s",
data->id, data->dso_name, dlerr);
return NULL;
}
@@ -1056,7 +1060,8 @@ static int _registered_device(struct message_data *message_data,
{
struct dm_event_daemon_message *msg = message_data->msg;
const char *fmt = "%s %s %u";
const char *fmt = "%s %s %s %u";
const char *id = message_data->id;
const char *dso = thread->dso_data->dso_name;
const char *dev = thread->device.uuid;
unsigned events = ((thread->status == DM_THREAD_RUNNING)
@@ -1066,7 +1071,7 @@ static int _registered_device(struct message_data *message_data,
if (msg->data)
dm_free(msg->data);
msg->size = dm_asprintf(&(msg->data), fmt, dso, dev, events);
msg->size = dm_asprintf(&(msg->data), fmt, id, dso, dev, events);
_unlock_mutex();
@@ -1180,7 +1185,8 @@ static int _get_timeout(struct message_data *message_data)
_lock_mutex();
if ((thread = _lookup_thread_status(message_data))) {
msg->size =
dm_asprintf(&(msg->data), "%" PRIu32, thread->timeout);
dm_asprintf(&(msg->data), "%s %" PRIu32, message_data->id,
thread->timeout);
} else {
msg->data = NULL;
msg->size = 0;
@@ -1375,17 +1381,32 @@ static int _handle_request(struct dm_event_daemon_message *msg,
static int _do_process_request(struct dm_event_daemon_message *msg)
{
int ret;
char *answer;
static struct message_data message_data;
/* Parse the message. */
memset(&message_data, 0, sizeof(message_data));
message_data.msg = msg;
if (msg->cmd != DM_EVENT_CMD_ACTIVE && !_parse_message(&message_data)) {
if (msg->cmd == DM_EVENT_CMD_HELLO) {
ret = 0;
answer = dm_strdup(msg->data);
if (answer) {
msg->size = dm_asprintf(&(msg->data), "%s HELLO", answer);
dm_free(answer);
} else {
msg->size = 0;
msg->data = NULL;
}
} else if (msg->cmd != DM_EVENT_CMD_ACTIVE && !_parse_message(&message_data)) {
stack;
ret = -EINVAL;
} else
ret = _handle_request(msg, &message_data);
msg->cmd = ret;
if (!msg->data)
msg->size = dm_asprintf(&(msg->data), "%s %s", message_data.id, strerror(-ret));
_free_message(&message_data);
return ret;
@@ -1405,16 +1426,9 @@ static void _process_request(struct dm_event_fifos *fifos)
if (!_client_read(fifos, &msg))
return;
msg.cmd = _do_process_request(&msg);
if (!msg.data) {
msg.data = dm_strdup(strerror(-msg.cmd));
if (msg.data)
msg.size = strlen(msg.data) + 1;
else {
msg.size = 0;
stack;
}
}
/* _do_process_request fills in msg (if memory allows for
data, otherwise just cmd and size = 0) */
_do_process_request(&msg);
if (!_client_write(fifos, &msg))
stack;

View File

@@ -20,6 +20,7 @@ enum dm_event_command {
DM_EVENT_CMD_GET_NEXT_REGISTERED_DEVICE,
DM_EVENT_CMD_SET_TIMEOUT,
DM_EVENT_CMD_GET_TIMEOUT,
DM_EVENT_CMD_HELLO,
};
/* Message passed between client and daemon. */

View File

@@ -30,6 +30,8 @@
#include <sys/wait.h>
#include <arpa/inet.h> /* for htonl, ntohl */
static int _sequence_nr = 0;
struct dm_event_handler {
char *dso;
@@ -182,6 +184,21 @@ enum dm_event_mask dm_event_handler_get_event_mask(const struct dm_event_handler
return dmevh->mask;
}
static int _check_message_id(struct dm_event_daemon_message *msg)
{
int pid, seq_nr;
if ((sscanf(msg->data, "%d:%d", &pid, &seq_nr) != 2) ||
(pid != getpid()) || (seq_nr != _sequence_nr)) {
log_error("Ignoring out-of-sequence reply from dmeventd. "
"Expected %d:%d but received %s", getpid(),
_sequence_nr, msg->data);
return 0;
}
return 1;
}
/*
* daemon_read
* @fifos
@@ -260,11 +277,28 @@ static int _daemon_write(struct dm_event_fifos *fifos,
size_t size = 2 * sizeof(uint32_t) + msg->size;
char *buf = alloca(size);
char drainbuf[128];
struct timeval tval = { 0, 0 };
*((uint32_t *)buf) = htonl(msg->cmd);
*((uint32_t *)buf + 1) = htonl(msg->size);
memcpy(buf + 2 * sizeof(uint32_t), msg->data, msg->size);
/* drain the answer fifo */
while (1) {
FD_ZERO(&fds);
FD_SET(fifos->server, &fds);
tval.tv_usec = 100;
ret = select(fifos->server + 1, &fds, NULL, NULL, &tval);
if ((ret < 0) && (errno != EINTR)) {
log_error("Unable to talk to event daemon");
return 0;
}
if (ret == 0)
break;
read(fifos->server, drainbuf, 127);
}
while (bytes < size) {
do {
/* Watch daemon write FIFO to be ready for output. */
@@ -301,7 +335,7 @@ static int _daemon_talk(struct dm_event_fifos *fifos,
{
const char *dso = dso_name ? dso_name : "";
const char *dev = dev_name ? dev_name : "";
const char *fmt = "%s %s %u %" PRIu32;
const char *fmt = "%d:%d %s %s %u %" PRIu32;
int msg_size;
memset(msg, 0, sizeof(*msg));
@@ -310,8 +344,10 @@ static int _daemon_talk(struct dm_event_fifos *fifos,
* into ASCII message string.
*/
msg->cmd = cmd;
if ((msg_size = dm_asprintf(&(msg->data), fmt, dso, dev, evmask,
timeout)) < 0) {
if (cmd == DM_EVENT_CMD_HELLO)
fmt = "%d:%d HELLO";
if ((msg_size = dm_asprintf(&(msg->data), fmt, getpid(), _sequence_nr,
dso, dev, evmask, timeout)) < 0) {
log_error("_daemon_talk: message allocation failed");
return -ENOMEM;
}
@@ -326,10 +362,14 @@ static int _daemon_talk(struct dm_event_fifos *fifos,
return -EIO;
}
if (!_daemon_read(fifos, msg)) {
stack;
return -EIO;
}
do {
if (!_daemon_read(fifos, msg)) {
stack;
return -EIO;
}
} while (!_check_message_id(msg));
_sequence_nr++;
return (int32_t) msg->cmd;
}
@@ -507,7 +547,9 @@ static int _do_event(int cmd, struct dm_event_daemon_message *msg,
return -ESRCH;
}
ret = _daemon_talk(&fifos, msg, cmd, dso_name, dev_name, evmask, timeout);
ret = _daemon_talk(&fifos, msg, DM_EVENT_CMD_HELLO, 0, 0, 0, 0);
if (!ret)
ret = _daemon_talk(&fifos, msg, cmd, dso_name, dev_name, evmask, timeout);
/* what is the opposite of init? */
_dtr_client(&fifos);
@@ -521,7 +563,7 @@ int dm_event_register_handler(const struct dm_event_handler *dmevh)
int ret = 1, err;
const char *uuid;
struct dm_task *dmt;
struct dm_event_daemon_message msg;
struct dm_event_daemon_message msg = { 0, 0, NULL };
if (!(dmt = _get_device_info(dmevh))) {
stack;
@@ -551,7 +593,7 @@ int dm_event_unregister_handler(const struct dm_event_handler *dmevh)
int ret = 1, err;
const char *uuid;
struct dm_task *dmt;
struct dm_event_daemon_message msg;
struct dm_event_daemon_message msg = { 0, 0, NULL };
if (!(dmt = _get_device_info(dmevh))) {
stack;
@@ -598,15 +640,20 @@ static char *_fetch_string(char **src, const int delimiter)
static int _parse_message(struct dm_event_daemon_message *msg, char **dso_name,
char **uuid, enum dm_event_mask *evmask)
{
char *id = NULL;
char *p = msg->data;
if ((*dso_name = _fetch_string(&p, ' ')) &&
if ((id = _fetch_string(&p, ' ')) &&
(*dso_name = _fetch_string(&p, ' ')) &&
(*uuid = _fetch_string(&p, ' '))) {
*evmask = atoi(p);
dm_free(id);
return 0;
}
if (id)
dm_free(id);
return -ENOMEM;
}
@@ -621,12 +668,12 @@ static int _parse_message(struct dm_event_daemon_message *msg, char **dso_name,
*/
int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
{
int ret;
int ret = 0;
const char *uuid = NULL;
char *reply_dso = NULL, *reply_uuid = NULL;
enum dm_event_mask reply_mask;
struct dm_task *dmt;
struct dm_event_daemon_message msg;
enum dm_event_mask reply_mask = 0;
struct dm_task *dmt = NULL;
struct dm_event_daemon_message msg = { 0, 0, NULL };
if (!(dmt = _get_device_info(dmevh))) {
stack;
@@ -696,9 +743,17 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
#if 0 /* left out for now */
static char *_skip_string(char *src, const int delimiter)
{
src = srtchr(src, delimiter);
if (src && *(src + 1))
return src + 1;
return NULL;
}
int dm_event_set_timeout(const char *device_path, uint32_t timeout)
{
struct dm_event_daemon_message msg;
struct dm_event_daemon_message msg = { 0, 0, NULL };
if (!device_exists(device_path))
return -ENODEV;
@@ -710,13 +765,20 @@ int dm_event_set_timeout(const char *device_path, uint32_t timeout)
int dm_event_get_timeout(const char *device_path, uint32_t *timeout)
{
int ret;
struct dm_event_daemon_message msg;
struct dm_event_daemon_message msg = { 0, 0, NULL };
if (!device_exists(device_path))
return -ENODEV;
if (!(ret = _do_event(DM_EVENT_CMD_GET_TIMEOUT, &msg, NULL, device_path,
0, 0)))
*timeout = atoi(msg.data);
0, 0))) {
char *p = _skip_string(msg.data, ' ');
if (!p) {
log_error("malformed reply from dmeventd '%s'\n",
msg.data);
return -EIO;
}
*timeout = atoi(p);
}
if (msg.data)
dm_free(msg.data);
return ret;

View File

@@ -56,10 +56,14 @@ devices {
# filter = [ "a|^/dev/hda8$|", "r/.*/" ]
# The results of the filtering are cached on disk to avoid
# rescanning dud devices (which can take a very long time). By
# default this cache file is hidden in the /etc/lvm directory.
# It is safe to delete this file: the tools regenerate it.
cache = "/etc/lvm/.cache"
# rescanning dud devices (which can take a very long time).
# By default this cache is stored in the /etc/lvm/cache directory
# in a file called '.cache'.
# It is safe to delete the contents: the tools regenerate it.
# (The old setting 'cache' is still respected if neither of
# these new ones is present.)
cache_dir = "/etc/lvm/cache"
cache_file_prefix = ""
# You can turn off writing this cache file by setting this to 0.
write_cache_state = 1
@@ -188,6 +192,9 @@ global {
# command. Defaults to off.
test = 0
# Default value for --units argument
units = "h"
# Whether or not to communicate with the kernel device-mapper.
# Set to 0 if you want to use the tools to manipulate LVM metadata
# without activating any logical volumes.

View File

@@ -168,6 +168,10 @@ int lvs_in_vg_activated(struct volume_group *vg)
{
return 0;
}
int lvs_in_vg_activated_by_uuid_only(struct volume_group *vg);
{
return 0;
}
int lvs_in_vg_opened(struct volume_group *vg)
{
return 0;
@@ -421,21 +425,23 @@ int target_present(const char *target_name, int use_modprobe)
* Returns 1 if info structure populated, else 0 on failure.
*/
static int _lv_info(struct cmd_context *cmd, const struct logical_volume *lv, int with_mknodes,
struct lvinfo *info, int with_open_count)
struct lvinfo *info, int with_open_count, unsigned by_uuid_only)
{
struct dm_info dminfo;
char *name;
char *name = NULL;
if (!activation())
return 0;
if (!(name = build_dm_name(cmd->mem, lv->vg->name, lv->name, NULL)))
if (!by_uuid_only &&
!(name = build_dm_name(cmd->mem, lv->vg->name, lv->name, NULL)))
return_0;
log_debug("Getting device info for %s", name);
if (!dev_manager_info(lv->vg->cmd->mem, name, lv, with_mknodes,
with_open_count, &dminfo)) {
dm_pool_free(cmd->mem, name);
if (name)
dm_pool_free(cmd->mem, name);
return_0;
}
@@ -448,14 +454,16 @@ static int _lv_info(struct cmd_context *cmd, const struct logical_volume *lv, in
info->live_table = dminfo.live_table;
info->inactive_table = dminfo.inactive_table;
dm_pool_free(cmd->mem, name);
if (name)
dm_pool_free(cmd->mem, name);
return 1;
}
int lv_info(struct cmd_context *cmd, const struct logical_volume *lv, struct lvinfo *info,
int with_open_count)
{
return _lv_info(cmd, lv, 0, info, with_open_count);
return _lv_info(cmd, lv, 0, info, with_open_count, 0);
}
int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s,
@@ -466,7 +474,7 @@ int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s,
if (!(lv = lv_from_lvid(cmd, lvid_s, 0)))
return 0;
return _lv_info(cmd, lv, 0, info, with_open_count);
return _lv_info(cmd, lv, 0, info, with_open_count, 0);
}
/*
@@ -519,11 +527,12 @@ int lv_mirror_percent(struct cmd_context *cmd, struct logical_volume *lv,
return r;
}
static int _lv_active(struct cmd_context *cmd, struct logical_volume *lv)
static int _lv_active(struct cmd_context *cmd, struct logical_volume *lv,
unsigned by_uuid_only)
{
struct lvinfo info;
if (!lv_info(cmd, lv, &info, 0)) {
if (!_lv_info(cmd, lv, 0, &info, 0, by_uuid_only)) {
stack;
return -1;
}
@@ -607,7 +616,7 @@ static int _lv_suspend_lv(struct logical_volume *lv, int lockfs)
* These two functions return the number of visible LVs in the state,
* or -1 on error.
*/
int lvs_in_vg_activated(struct volume_group *vg)
static int _lvs_in_vg_activated(struct volume_group *vg, unsigned by_uuid_only)
{
struct lv_list *lvl;
int count = 0;
@@ -617,12 +626,22 @@ int lvs_in_vg_activated(struct volume_group *vg)
list_iterate_items(lvl, &vg->lvs) {
if (lvl->lv->status & VISIBLE_LV)
count += (_lv_active(vg->cmd, lvl->lv) == 1);
count += (_lv_active(vg->cmd, lvl->lv, by_uuid_only) == 1);
}
return count;
}
int lvs_in_vg_activated_by_uuid_only(struct volume_group *vg)
{
return _lvs_in_vg_activated(vg, 1);
}
int lvs_in_vg_activated(struct volume_group *vg)
{
return _lvs_in_vg_activated(vg, 0);
}
int lvs_in_vg_opened(struct volume_group *vg)
{
struct lv_list *lvl;
@@ -973,7 +992,7 @@ int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv)
return r;
}
if (!_lv_info(cmd, lv, 1, &info, 0))
if (!_lv_info(cmd, lv, 1, &info, 0, 0))
return_0;
if (info.exists)

View File

@@ -83,6 +83,7 @@ int lv_mirror_percent(struct cmd_context *cmd, struct logical_volume *lv,
* Return number of LVs in the VG that are active.
*/
int lvs_in_vg_activated(struct volume_group *vg);
int lvs_in_vg_activated_by_uuid_only(struct volume_group *vg);
int lvs_in_vg_opened(struct volume_group *vg);

View File

@@ -118,12 +118,10 @@ static struct dm_task *_setup_task(const char *name, const char *uuid,
}
static int _info_run(const char *name, const char *dlid, struct dm_info *info,
int mknodes, int with_open_count, struct dm_pool *mem,
char **uuid_out)
int mknodes, int with_open_count)
{
int r = 0;
struct dm_task *dmt;
const char *u;
int dmtask;
dmtask = mknodes ? DM_DEVICE_MKNODES : DM_DEVICE_INFO;
@@ -143,11 +141,6 @@ static int _info_run(const char *name, const char *dlid, struct dm_info *info,
if (!dm_task_get_info(dmt, info))
goto_out;
if (info->exists && uuid_out) {
if (!(u = dm_task_get_uuid(dmt)))
goto_out;
*uuid_out = dm_pool_strdup(mem, u);
}
r = 1;
out:
@@ -208,23 +201,20 @@ int device_is_usable(dev_t dev)
}
static int _info(const char *name, const char *dlid, int mknodes,
int with_open_count, struct dm_info *info,
struct dm_pool *mem, char **uuid_out)
int with_open_count, struct dm_info *info)
{
if (!mknodes && dlid && *dlid) {
if (_info_run(NULL, dlid, info, 0, with_open_count, mem,
uuid_out) &&
if (_info_run(NULL, dlid, info, 0, with_open_count) &&
info->exists)
return 1;
else if (_info_run(NULL, dlid + sizeof(UUID_PREFIX) - 1, info,
0, with_open_count, mem, uuid_out) &&
0, with_open_count) &&
info->exists)
return 1;
}
if (name)
return _info_run(name, NULL, info, mknodes, with_open_count,
mem, uuid_out);
return _info_run(name, NULL, info, mknodes, with_open_count);
return 0;
}
@@ -240,8 +230,7 @@ int dev_manager_info(struct dm_pool *mem, const char *name,
return 0;
}
return _info(name, dlid, with_mknodes, with_open_count, info,
NULL, NULL);
return _info(name, dlid, with_mknodes, with_open_count, info);
}
/* FIXME Interface must cope with multiple targets */
@@ -646,7 +635,7 @@ static int _add_dev_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
return_0;
log_debug("Getting device info for %s [%s]", name, dlid);
if (!_info(name, dlid, 0, 1, &info, dm->mem, NULL)) {
if (!_info(name, dlid, 0, 1, &info)) {
log_error("Failed to get info for %s [%s].", name, dlid);
return 0;
}

View File

@@ -575,7 +575,7 @@ static struct dev_filter *_init_filter_components(struct cmd_context *cmd)
static int _init_filters(struct cmd_context *cmd, unsigned load_persistent_cache)
{
const char *dev_cache;
const char *dev_cache = NULL, *cache_dir, *cache_file_prefix;
struct dev_filter *f3, *f4;
struct stat st;
char cache_file[PATH_MAX];
@@ -585,19 +585,35 @@ static int _init_filters(struct cmd_context *cmd, unsigned load_persistent_cache
if (!(f3 = _init_filter_components(cmd)))
return 0;
if (dm_snprintf(cache_file, sizeof(cache_file),
"%s/.cache", cmd->sys_dir) < 0) {
log_error("Persistent cache filename too long ('%s/.cache').",
cmd->sys_dir);
return 0;
}
init_ignore_suspended_devices(find_config_tree_int(cmd,
"devices/ignore_suspended_devices", DEFAULT_IGNORE_SUSPENDED_DEVICES));
dev_cache = find_config_tree_str(cmd, "devices/cache",
cache_file);
if (!(f4 = persistent_filter_create(f3, dev_cache))) {
/*
* If 'cache_dir' or 'cache_file_prefix' is set, ignore 'cache'.
*/
cache_dir = find_config_tree_str(cmd, "devices/cache_dir", NULL);
cache_file_prefix = find_config_tree_str(cmd, "devices/cache_file_prefix", NULL);
if (cache_dir || cache_file_prefix) {
if (dm_snprintf(cache_file, sizeof(cache_file),
"%s%s%s/%s.cache",
cache_dir ? "" : cmd->sys_dir,
cache_dir ? "" : "/",
cache_dir ? : DEFAULT_CACHE_SUBDIR,
cache_file_prefix ? : DEFAULT_CACHE_FILE_PREFIX) < 0) {
log_error("Persistent cache filename too long.");
return 0;
}
} else if (!(dev_cache = find_config_tree_str(cmd, "devices/cache", NULL)) &&
(dm_snprintf(cache_file, sizeof(cache_file),
"%s/%s/%s.cache",
cmd->sys_dir, DEFAULT_CACHE_SUBDIR,
DEFAULT_CACHE_FILE_PREFIX) < 0)) {
log_error("Persistent cache filename too long.");
return 0;
}
if (!(f4 = persistent_filter_create(f3, dev_cache ? : cache_file))) {
log_error("Failed to create persistent device filter");
return 0;
}
@@ -754,7 +770,6 @@ static int _init_segtypes(struct cmd_context *cmd)
struct config_value *cv;
struct segment_type *(*init_segtype_fn) (struct cmd_context *);
void *lib;
struct list *sgtl, *tmp;
struct segment_type *segtype2;
for (cv = cn->v; cv; cv = cv->next) {
@@ -781,18 +796,16 @@ static int _init_segtypes(struct cmd_context *cmd)
segtype->library = lib;
list_add(&cmd->segtypes, &segtype->list);
list_iterate_safe(sgtl, tmp, &cmd->segtypes) {
segtype2 = list_item(sgtl, struct segment_type);
if (!strcmp(segtype2->name, segtype->name)) {
log_error("Duplicate segment type %s: "
"unloading shared library %s",
segtype->name, cv->v.str);
list_del(&segtype->list);
segtype->ops->destroy(segtype);
dlclose(lib);
break;
}
list_iterate_items(segtype2, &cmd->segtypes) {
if ((segtype == segtype2) ||
strcmp(segtype2->name, segtype->name))
continue;
log_error("Duplicate segment type %s: "
"unloading shared library %s",
segtype->name, cv->v.str);
list_del(&segtype->list);
segtype->ops->destroy(segtype);
dlclose(lib);
}
}
}

View File

@@ -878,7 +878,7 @@ static int _find_config_int(const struct config_node *cn1,
{
const struct config_node *n = _find_first_config_node(cn1, cn2, path);
if (n && n->v->type == CFG_INT) {
if (n && n->v && n->v->type == CFG_INT) {
log_very_verbose("Setting %s to %d", path, n->v->v.i);
return n->v->v.i;
}
@@ -899,7 +899,7 @@ static float _find_config_float(const struct config_node *cn1,
{
const struct config_node *n = _find_first_config_node(cn1, cn2, path);
if (n && n->v->type == CFG_FLOAT) {
if (n && n->v && n->v->type == CFG_FLOAT) {
log_very_verbose("Setting %s to %f", path, n->v->v.r);
return n->v->v.r;
}

View File

@@ -21,6 +21,8 @@
#define DEFAULT_ARCHIVE_SUBDIR "archive"
#define DEFAULT_BACKUP_SUBDIR "backup"
#define DEFAULT_CACHE_SUBDIR "cache"
#define DEFAULT_CACHE_FILE_PREFIX ""
#define DEFAULT_ARCHIVE_DAYS 30
#define DEFAULT_ARCHIVE_NUMBER 10

View File

@@ -53,8 +53,10 @@ int dev_is_md(struct device *dev, uint64_t *sb)
sb_offset = MD_NEW_SIZE_SECTORS(size) << SECTOR_SHIFT;
/* Check if it is an md component device. */
/* Version 1 is little endian; version 0.90.0 is machine endian */
if (dev_read(dev, sb_offset, sizeof(uint32_t), &md_magic) &&
(md_magic == xlate32(MD_SB_MAGIC))) {
((md_magic == xlate32(MD_SB_MAGIC)) ||
(md_magic == MD_SB_MAGIC))) {
if (sb)
*sb = sb_offset;
ret = 1;

View File

@@ -203,6 +203,19 @@ static int _check_maps_are_complete(struct dm_hash_table *maps)
return 1;
}
static uint32_t _area_length(struct lv_map *lvm, uint32_t le)
{
uint32_t len = 0;
do
len++;
while ((lvm->map[le + len].pv == lvm->map[le].pv) &&
(lvm->map[le].pv &&
lvm->map[le + len].pe == lvm->map[le].pe + len));
return len;
}
static int _read_linear(struct cmd_context *cmd, struct lv_map *lvm)
{
uint32_t le = 0, len;
@@ -215,13 +228,7 @@ static int _read_linear(struct cmd_context *cmd, struct lv_map *lvm)
}
while (le < lvm->lv->le_count) {
len = 0;
do
len++;
while ((lvm->map[le + len].pv == lvm->map[le].pv) &&
(lvm->map[le].pv &&
lvm->map[le + len].pe == lvm->map[le].pe + len));
len = _area_length(lvm, le);
if (!(seg = alloc_lv_segment(cmd->mem, segtype, lvm->lv, le,
len, 0, 0, NULL, 1, len, 0, 0, 0))) {
@@ -230,10 +237,8 @@ static int _read_linear(struct cmd_context *cmd, struct lv_map *lvm)
}
if (!set_lv_segment_area_pv(seg, 0, lvm->map[le].pv,
lvm->map[le].pe)) {
stack;
return 0;
}
lvm->map[le].pe))
return_0;
list_add(&lvm->lv->segments, &seg->list);
@@ -244,7 +249,8 @@ static int _read_linear(struct cmd_context *cmd, struct lv_map *lvm)
}
static int _check_stripe(struct lv_map *lvm, uint32_t area_count,
uint32_t seg_len, uint32_t base_le, uint32_t len)
uint32_t area_len, uint32_t base_le,
uint32_t total_area_len)
{
uint32_t st;
@@ -252,11 +258,11 @@ static int _check_stripe(struct lv_map *lvm, uint32_t area_count,
* Is the next physical extent in every stripe adjacent to the last?
*/
for (st = 0; st < area_count; st++)
if ((lvm->map[base_le + st * len + seg_len].pv !=
lvm->map[base_le + st * len].pv) ||
(lvm->map[base_le + st * len].pv &&
lvm->map[base_le + st * len + seg_len].pe !=
lvm->map[base_le + st * len].pe + seg_len))
if ((lvm->map[base_le + st * total_area_len + area_len].pv !=
lvm->map[base_le + st * total_area_len].pv) ||
(lvm->map[base_le + st * total_area_len].pv &&
lvm->map[base_le + st * total_area_len + area_len].pe !=
lvm->map[base_le + st * total_area_len].pe + area_len))
return 0;
return 1;
@@ -264,7 +270,7 @@ static int _check_stripe(struct lv_map *lvm, uint32_t area_count,
static int _read_stripes(struct cmd_context *cmd, struct lv_map *lvm)
{
uint32_t st, le = 0, len;
uint32_t st, first_area_le = 0, total_area_len;
uint32_t area_len;
struct lv_segment *seg;
struct segment_type *segtype;
@@ -277,26 +283,25 @@ static int _read_stripes(struct cmd_context *cmd, struct lv_map *lvm)
"with logical extent count (%u) for %s",
lvm->stripes, lvm->lv->le_count, lvm->lv->name);
}
len = lvm->lv->le_count / lvm->stripes;
if (!(segtype = get_segtype_from_string(cmd, "striped"))) {
stack;
return 0;
}
total_area_len = lvm->lv->le_count / lvm->stripes;
while (le < len) {
if (!(segtype = get_segtype_from_string(cmd, "striped")))
return_0;
while (first_area_le < total_area_len) {
area_len = 1;
/*
* Find how many blocks are contiguous in all stripes
* Find how many extents are contiguous in all stripes
* and so can form part of this segment
*/
while (_check_stripe(lvm, lvm->stripes,
area_len * lvm->stripes, le, len))
area_len, first_area_le, total_area_len))
area_len++;
if (!(seg = alloc_lv_segment(cmd->mem, segtype, lvm->lv,
lvm->stripes * le,
lvm->stripes * first_area_le,
lvm->stripes * area_len,
0, lvm->stripe_size, NULL,
lvm->stripes,
@@ -310,15 +315,13 @@ static int _read_stripes(struct cmd_context *cmd, struct lv_map *lvm)
*/
for (st = 0; st < seg->area_count; st++)
if (!set_lv_segment_area_pv(seg, st,
lvm->map[le + st * len].pv,
lvm->map[le + st * len].pe)) {
stack;
return 0;
}
lvm->map[first_area_le + st * total_area_len].pv,
lvm->map[first_area_le + st * total_area_len].pe))
return_0;
list_add(&lvm->lv->segments, &seg->list);
le += seg->len;
first_area_le += area_len;
}
return 1;

View File

@@ -81,7 +81,7 @@ int init_no_locking(struct locking_type *locking, struct cmd_context *cmd)
locking->lock_resource = _no_lock_resource;
locking->reset_locking = _no_reset_locking;
locking->fin_locking = _no_fin_locking;
locking->flags = 0;
locking->flags = LCK_CLUSTERED;
return 1;
}

View File

@@ -963,6 +963,30 @@ static struct volume_group *_vg_read_orphans(struct cmd_context *cmd)
return vg;
}
static int _update_pv_list(struct list *all_pvs, struct volume_group *vg)
{
struct pv_list *pvl, *pvl2;
list_iterate_items(pvl, &vg->pvs) {
list_iterate_items(pvl2, all_pvs) {
if (pvl->pv->dev == pvl2->pv->dev)
goto next_pv;
}
/* PV is not on list so add it. Note that we don't copy it. */
if (!(pvl2 = dm_pool_zalloc(vg->cmd->mem, sizeof(*pvl2)))) {
log_error("pv_list allocation for '%s' failed",
dev_name(pvl->pv->dev));
return 0;
}
pvl2->pv = pvl->pv;
list_add(all_pvs, &pvl2->list);
next_pv:
;
}
return 1;
}
/* Caller sets consistent to 1 if it's safe for vg_read to correct
* inconsistent metadata on disk (i.e. the VG write lock is held).
* This guarantees only consistent metadata is returned unless PARTIAL_VG.
@@ -982,9 +1006,12 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
struct volume_group *vg, *correct_vg = NULL;
struct metadata_area *mda;
int inconsistent = 0;
int inconsistent_vgid = 0;
int use_precommitted = precommitted;
struct list *pvids;
struct pv_list *pvl;
struct pv_list *pvl, *pvl2;
struct list all_pvs;
char uuid[64] __attribute((aligned(8)));
if (!*vgname) {
if (use_precommitted) {
@@ -1069,6 +1096,8 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
}
}
list_init(&all_pvs);
/* Failed to find VG where we expected it - full scan and retry */
if (!correct_vg) {
inconsistent = 0;
@@ -1104,13 +1133,25 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
}
if (!correct_vg) {
correct_vg = vg;
if (!_update_pv_list(&all_pvs, correct_vg))
return_NULL;
continue;
}
if (strncmp((char *)vg->id.uuid,
(char *)correct_vg->id.uuid, ID_LEN)) {
inconsistent = 1;
inconsistent_vgid = 1;
}
/* FIXME Also ensure contents same - checksums same? */
if (correct_vg->seqno != vg->seqno) {
inconsistent = 1;
if (vg->seqno > correct_vg->seqno)
if (vg->seqno > correct_vg->seqno) {
if (!_update_pv_list(&all_pvs, vg))
return_NULL;
correct_vg = vg;
}
}
}
@@ -1143,17 +1184,42 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
return correct_vg;
}
log_print("Inconsistent metadata copies found - updating "
"to use version %u", correct_vg->seqno);
/* Don't touch if vgids didn't match */
if (inconsistent_vgid) {
log_error("Inconsistent metadata UUIDs found for "
"volume group %s", vgname);
*consistent = 0;
return correct_vg;
}
log_print("Inconsistent metadata found for VG %s - updating "
"to use version %u", vgname, correct_vg->seqno);
if (!vg_write(correct_vg)) {
log_error("Automatic metadata correction failed");
return NULL;
}
if (!vg_commit(correct_vg)) {
log_error("Automatic metadata correction commit "
"failed");
return NULL;
}
list_iterate_items(pvl, &all_pvs) {
list_iterate_items(pvl2, &correct_vg->pvs) {
if (pvl->pv->dev == pvl2->pv->dev)
goto next_pv;
}
if (!id_write_format(&pvl->pv->id, uuid, sizeof(uuid)))
return_NULL;
log_error("Removing PV %s (%s) that no longer belongs to VG %s",
dev_name(pvl->pv->dev), uuid, correct_vg->name);
if (!pv_write_orphan(cmd, pvl->pv))
return_NULL;
next_pv:
;
}
}
if ((correct_vg->status & PVMOVE) && !pvmove_mode()) {
@@ -1433,3 +1499,25 @@ int pv_write(struct cmd_context *cmd __attribute((unused)), struct physical_volu
return 1;
}
int pv_write_orphan(struct cmd_context *cmd, struct physical_volume *pv)
{
const char *old_vg_name = pv->vg_name;
pv->vg_name = ORPHAN;
pv->status = ALLOCATABLE_PV;
if (!dev_get_size(pv->dev, &pv->size)) {
log_error("%s: Couldn't get size.", dev_name(pv->dev));
return 0;
}
if (!pv_write(cmd, pv, NULL, INT64_C(-1))) {
log_error("Failed to clear metadata from physical "
"volume \"%s\" after removal from \"%s\"",
dev_name(pv->dev), old_vg_name);
return 0;
}
return 1;
}

View File

@@ -423,6 +423,7 @@ struct list *get_vgids(struct cmd_context *cmd, int full_scan);
int pv_write(struct cmd_context *cmd, struct physical_volume *pv,
struct list *mdas, int64_t label_sector);
int pv_write_orphan(struct cmd_context *cmd, struct physical_volume *pv);
/* pe_start and pe_end relate to any existing data so that new metadata
* areas can avoid overlap */

View File

@@ -256,6 +256,8 @@ void sync_dir(const char *file)
int fcntl_lock_file(const char *file, short lock_type, int warn_if_read_only)
{
int lockfd;
char *dir;
char *c;
struct flock lock = {
.l_type = lock_type,
.l_whence = 0,
@@ -263,6 +265,17 @@ int fcntl_lock_file(const char *file, short lock_type, int warn_if_read_only)
.l_len = 0
};
if (!(dir = dm_strdup(file))) {
log_error("fcntl_lock_file failed in strdup.");
return -1;
}
if ((c = strrchr(dir, '/')))
*c = '\0';
if (!create_dir(dir))
return -1;
log_very_verbose("Locking %s (%s, %hd)", file,
(lock_type == F_WRLCK) ? "F_WRLCK" : "F_RDLCK",
lock_type);

View File

@@ -868,11 +868,11 @@ static const struct dm_report_object_type _report_types[] = {
#define STR DM_REPORT_FIELD_TYPE_STRING
#define NUM DM_REPORT_FIELD_TYPE_NUMBER
#define FIELD(type, strct, sorttype, head, field, width, func, id, desc) {type, id, (off_t)((void *)&_dummy._ ## strct.field - (void *)&_dummy._ ## strct), head, width, sorttype, &_ ## func ## _disp, desc},
#define FIELD(type, strct, sorttype, head, field, width, func, id, desc) {type, sorttype, (off_t)((void *)&_dummy._ ## strct.field - (void *)&_dummy._ ## strct), width, id, head, &_ ## func ## _disp, desc},
static struct dm_report_field_type _fields[] = {
#include "columns.h"
{0, "", 0, "", 0, 0, NULL, NULL},
{0, 0, 0, 0, "", "", NULL, NULL},
};
#undef STR

View File

@@ -657,11 +657,11 @@ struct dm_report_field;
struct dm_report;
struct dm_report_field_type {
uint32_t type; /* object type id */
const char id[32]; /* string used to specify the field */
unsigned int offset; /* byte offset in the object */
const char heading[32]; /* string printed in header */
int width; /* default width */
uint32_t flags; /* DM_REPORT_FIELD_* */
uint32_t offset; /* byte offset in the object */
int32_t width; /* default width */
const char id[32]; /* string used to specify the field */
const char heading[32]; /* string printed in header */
int (*report_fn)(struct dm_report *rh, struct dm_pool *mem,
struct dm_report_field *field, const void *data,
void *private);

View File

@@ -60,7 +60,7 @@ struct field_properties {
struct list list;
uint32_t field_num;
uint32_t sort_posn;
unsigned width;
int32_t width;
const struct dm_report_object_type *type;
uint32_t flags;
};
@@ -504,15 +504,20 @@ struct dm_report *dm_report_init(uint32_t *report_types,
if (!(rh->mem = dm_pool_create("report", 10 * 1024))) {
log_error("dm_report_init: allocation of memory pool failed");
dm_free(rh);
return NULL;
}
/* Generate list of fields for output based on format string & flags */
if (!_parse_options(rh, output_fields))
if (!_parse_options(rh, output_fields)) {
dm_report_free(rh);
return NULL;
}
if (!_parse_keys(rh, sort_keys))
if (!_parse_keys(rh, sort_keys)) {
dm_report_free(rh);
return NULL;
}
/* Return updated types value for further compatility check by caller */
if (report_types)
@@ -750,7 +755,7 @@ int dm_report_output(struct dm_report *rh)
struct dm_report_field *field;
const char *repstr;
char buf[4096];
unsigned width;
int32_t width;
uint32_t align;
if (list_empty(&rh->rows))

View File

@@ -3,6 +3,9 @@
dmsetup \- low level logical volume management
.SH SYNOPSIS
.ad l
.B dmsetup help
.I [-c|-C|--columns]
.br
.B dmsetup create
.I device_name [-u uuid] [--notable | --table <table> | table_file]
.br
@@ -33,21 +36,25 @@ dmsetup \- low level logical volume management
.B dmsetup message
.I device_name sector message
.br
.B dmsetup ls [--target target_type] [--exec command] [--tree [-o options]]
.B dmsetup ls
.I [--target target_type] [--exec command] [--tree [-o options]]
.br
.B dmsetup info
.I [device_name]
.br
.B dmsetup info -c|-C|--columns [--noheadings] [-o name]
.B dmsetup info -c|-C|--columns
.I [--noheadings] [--separator separator] [-o fields] [-O|--sort sort_fields]
.I [device_name]
.br
.B dmsetup deps
.I [device_name]
.br
.B dmsetup status [--target target_type]
.B dmsetup status
.I [--target target_type]
.I [device_name]
.br
.B dmsetup table [--target target_type]
.B dmsetup table
.I [--target target_type]
.I [device_name]
.br
.B dmsetup wait
@@ -103,7 +110,7 @@ Tell the kernel not to supply the open reference count for the device.
When creating a device, don't load any table.
.IP \fB-o|--options
.br
Specify which fields to display. Only \fB-o\ name\fP is supported.
Specify which fields to display.
.IP \fB-r|--readonly
.br
Set the table being loaded read-only.
@@ -136,6 +143,11 @@ See below for information on the table format.
.br
Outputs a list of (major, minor) pairs for devices referenced by the
live table for the specified device.
.IP \fBhelp
.I [-c|-C|--columns]
.br
Outputs a summary of the commands available, optionally including
the list of report fields.
.IP \fBinfo
.I [device_name]
.br
@@ -154,6 +166,17 @@ Outputs some brief information about the device in the form:
Number of targets in the live table
.br
UUID
.IP \fBinfo -c|-C|--columns
.I [--noheadings] [--separator separator] [-o fields] [-O|--sort sort_fields]
.I [device_name]
.br
Output you can customise.
Fields are comma-separated and chosen from the following list:
name, major, minor, attr, open, segments, events, uuid.
Attributes are: (L)ive, (I)nactive, (s)uspended, (r)ead-only, read-(w)rite.
Precede the list with '+' to append
to the default selection of columns instead of replacing it.
Precede any sort_field with - for a reverse sort on that column.
.IP \fBls
.I [--target target_type]
.I [--exec command]

View File

@@ -12,7 +12,7 @@ lvchange \- change attributes of a logical volume
[\-\-ignorelockingfailure]
[\-\-monitor {y|n}]
[\-M/\-\-persistent y/n] [\-\-minor minor]
[\-P/\-\-partial y/n]
[\-P/\-\-partial]
[\-p/\-\-permission r/w] [\-r/\-\-readahead ReadAheadSectors]
[\-\-refresh]
[\-t/\-\-test]

View File

@@ -95,8 +95,8 @@ pattern it is rejected; otherwise it is accepted.
As an example, to ignore /dev/cdrom you could use:
\fBdevices { filter=["r|cdrom|"] }\fP
.IP
\fBcache\fP \(em Persistent filter cache file.
Defaults to "/etc/lvm/.cache".
\fBcache_dir\fP \(em Persistent filter cache file directory.
Defaults to "/etc/lvm/cache".
.IP
\fBwrite_cache_state\fP \(em Set to 0 to disable the writing out of the
persistent filter cache file when \fBlvm\fP exits.
@@ -364,9 +364,9 @@ understand how things work: to make changes you should always use
the tools as normal, or else vgcfgbackup, edit backup, vgcfgrestore.
.SH FILES
.I /etc/lvm/lvm.conf
.I /etc/lvm/.cache
.I /etc/lvm/archive
.I /etc/lvm/backup
.I /etc/lvm/cache/.cache
.I /var/lock/lvm
.SH SEE ALSO
.BR lvm (8),

View File

@@ -5,7 +5,7 @@ pvmove \- move physical extents
.B pvmove
[\-\-abort]
[\-\-alloc AllocationPolicy]
[\-\-background]
[\-b/\-\-background]
[\-d/\-\-debug] [\-h/\-\-help] [\-i/\-\-interval Seconds] [\-v/\-\-verbose]
[\-n/\-\-name LogicalVolume]
[SourcePhysicalVolume[:PE[-PE]...] [DestinationPhysicalVolume[:PE[-PE]...]...]]
@@ -73,7 +73,7 @@ type of on-disk metadata. Metadata can be converted using \fBvgconvert\fP(8).
.I \-\-abort
Abort any moves in progress.
.TP
.I \-\-background
.I \-b, \-\-background
Run the daemon in the background.
.TP
.I \-i, \-\-interval Seconds

View File

@@ -43,16 +43,10 @@ start()
then
for vg in $LVM_VGS
do
if ! action "Activating VG $vg:" $VGCHANGE -ayl $vg
then
rtrn=$?
fi
action "Activating VG $vg:" $VGCHANGE -ayl $vg || rtrn=$?
done
else
if ! action "Activating VGs:" $VGCHANGE -ayl
then
rtrn=$?
fi
action "Activating VGs:" $VGCHANGE -ayl || rtrn=$?
fi
done
@@ -67,19 +61,13 @@ stop()
then
for vg in $LVM_VGS
do
if ! action "Deactivating VG $vg:" $VGCHANGE -anl $vg
then
rtrn=$?
fi
action "Deactivating VG $vg:" $VGCHANGE -anl $vg || rtrn=$?
done
else
# Hack to only deactivate clustered volumes
clustervgs=`$VGDISPLAY 2> /dev/null | awk 'BEGIN {RS="VG Name"} {if (/Clustered/) print $1;}'`
for vg in $clustervgs; do
if ! action "Deactivating VG $vg:" $VGCHANGE -anl $vg
then
rtrn=$?
fi
action "Deactivating VG $vg:" $VGCHANGE -anl $vg || rtrn=$?
done
fi

View File

@@ -25,65 +25,67 @@
. /etc/init.d/functions
VGCHANGE="/usr/sbin/vgchange"
WARN=1
start()
{
for ret in 0
do
ret=0
# TODO do we want to separate out already active groups only?
VGS=`vgs --noheadings -o name`
for vg in $VGS
do
if ! action "Starting monitoring for VG $vg:" $VGCHANGE --monitor y $vg
then
ret=$?
fi
action "Starting monitoring for VG $vg:" $VGCHANGE --monitor y $vg || ret=$?
done
done
return $ret
return $ret
}
stop()
{
for ret in 0
do
ret=0
# TODO do we want to separate out already active groups only?
if test "$WARN" = "1"; then
echo "Not stopping monitoring, this is a dangerous operation. Please use force-stop to override."
return 1
fi
VGS=`vgs --noheadings -o name`
for vg in $VGS
do
if ! action "Starting monitoring for VG $vg:" $VGCHANGE --monitor n $vg
then
ret=$?
fi
action "Stopping monitoring for VG $vg:" $VGCHANGE --monitor n $vg || ret=$?
done
done
return $ret
}
ret=1
result=1
# See how we were called.
case "$1" in
start)
start
ret=$?
result=$?
;;
force-stop)
WARN=0
stop
result=$?
;;
stop)
test "$runlevel" = "0" && WARN=0
test "$runlevel" = "6" && WARN=0
stop
ret=$?
result=$?
;;
restart)
WARN=0
if stop
then
start
fi
ret=$?
result=$?
;;
status)
@@ -91,8 +93,8 @@ case "$1" in
;;
*)
echo $"Usage: $0 {start|stop|restart|status}"
echo $"Usage: $0 {start|stop|restart|status|force-stop}"
;;
esac
exit $ret
exit $result

View File

@@ -1561,20 +1561,20 @@ static const struct dm_report_object_type _report_types[] = {
#define OFFSET_OF(strct, field) ((unsigned int) &((struct strct *)NULL)->field)
#define STR (DM_REPORT_FIELD_TYPE_STRING)
#define NUM (DM_REPORT_FIELD_TYPE_NUMBER)
#define FIELD_O(type, strct, sorttype, head, field, width, func, id, desc) {DR_ ## type, id, OFFSET_OF(strct, field), head, width, sorttype, &_ ## func ## _disp, desc},
#define FIELD_F(type, sorttype, head, width, func, id, desc) {DR_ ## type, id, 0, head, width, sorttype, &_ ## func ## _disp, desc},
#define FIELD_O(type, strct, sorttype, head, field, width, func, id, desc) {DR_ ## type, sorttype, OFFSET_OF(strct, field), width, id, head, &_ ## func ## _disp, desc},
#define FIELD_F(type, sorttype, head, width, func, id, desc) {DR_ ## type, sorttype, 0, width, id, head, &_ ## func ## _disp, desc},
static const struct dm_report_field_type _report_fields[] = {
/* *INDENT-OFF* */
FIELD_F(TASK, STR, "Name", 16, dm_name, "name", "Name of mapped device.")
FIELD_F(TASK, STR, "UUID", 32, dm_uuid, "uuid", "Unique identifier for mapped device (optional).")
FIELD_F(INFO, STR, "Stat", 4, dm_info_status, "status", "Attributes.")
FIELD_O(INFO, dm_info, NUM, "Maj", major, 3, int32, "major", "Major number.")
FIELD_O(INFO, dm_info, NUM, "Min", minor, 3, int32, "minor", "Minor number.")
FIELD_O(INFO, dm_info, NUM, "Open", open_count, 4, int32, "open_count", "Number of references to open device, if requested.")
FIELD_O(INFO, dm_info, NUM, "Targ", target_count, 4, int32, "target_count", "Number of segments in live table, if present.")
FIELD_O(INFO, dm_info, NUM, "Event", event_nr, 6, uint32, "event_nr", "Current event number.")
{0, "", 0, "", 0, 0, NULL, NULL},
FIELD_F(TASK, STR, "UUID", 32, dm_uuid, "uuid", "Unique (optional) identifier for mapped device.")
FIELD_F(INFO, STR, "Stat", 4, dm_info_status, "attr", "(L)ive, (I)nactive, (s)uspended, (r)ead-only, read-(w)rite.")
FIELD_O(INFO, dm_info, NUM, "Maj", major, 3, int32, "major", "Block device major number.")
FIELD_O(INFO, dm_info, NUM, "Min", minor, 3, int32, "minor", "Block device minor number.")
FIELD_O(INFO, dm_info, NUM, "Open", open_count, 4, int32, "open", "Number of references to open device, if requested.")
FIELD_O(INFO, dm_info, NUM, "Targ", target_count, 4, int32, "segments", "Number of segments in live table, if present.")
FIELD_O(INFO, dm_info, NUM, "Event", event_nr, 6, uint32, "events", "Number of most recent event.")
{0, 0, 0, 0, "", "", NULL, NULL},
/* *INDENT-ON* */
};
@@ -1583,7 +1583,7 @@ FIELD_O(INFO, dm_info, NUM, "Event", event_nr, 6, uint32, "event_nr", "Current e
#undef FIELD_O
#undef FIELD_F
static const char *default_report_options = "name,major,minor,status,open_count,target_count,event_nr,uuid";
static const char *default_report_options = "name,major,minor,attr,open,segments,events,uuid";
static int _report_init(struct command *c)
{
@@ -1625,7 +1625,7 @@ static int _report_init(struct command *c)
if (_switches[SORT_ARG] && _string_args[SORT_ARG]) {
keys = _string_args[SORT_ARG];
buffered = 1;
if (!strcmp(c->name, "status") || !strcmp(c->name, "table")) {
if (c && (!strcmp(c->name, "status") || !strcmp(c->name, "table"))) {
err("--sort is not yet supported with status and table");
goto out;
}
@@ -1673,10 +1673,13 @@ static int _ls(int argc, char **argv, void *data)
return _process_all(argc, argv, 0, _display_name);
}
static int _help(int argc, char **argv, void *data);
/*
* Dispatch table
*/
static struct command _commands[] = {
{"help", "[-c|-C|--columns]", 0, 0, _help},
{"create", "<dev_name> [-j|--major <major> -m|--minor <minor>]\n"
"\t [-U|--uid <uid>] [-G|--gid <gid>] [-M|--mode <octal_mode>]\n"
"\t [-u|uuid <uuid>]\n"
@@ -1710,14 +1713,18 @@ static void _usage(FILE *out)
fprintf(out, "Usage:\n\n");
fprintf(out, "dmsetup [--version] [-v|--verbose [-v|--verbose ...]]\n"
" [-r|--readonly] [--noopencount] [--nolockfs]\n\n");
" [-r|--readonly] [--noopencount] [--nolockfs]\n"
" [-c|-C|--columns] [-o <fields>] [-O|--sort <sort_fields>]\n"
" [--noheadings] [--separator <separator>]\n\n");
for (i = 0; _commands[i].name; i++)
fprintf(out, "\t%s %s\n", _commands[i].name, _commands[i].help);
fprintf(out, "\n<device> may be device name or -u <uuid> or "
"-j <major> -m <minor>\n");
fprintf(out, "<fields> are comma-separated. Use 'help -c' for list.\n");
fprintf(out, "Table_file contents may be supplied on stdin.\n");
fprintf(out, "Tree options are: ascii, utf, vt100; compact, inverted, notrunc;\n"
" [no]device, active, open, rw and uuid.\n\n");
" [no]device, active, open, rw and uuid.\n");
fprintf(out, "\n");
return;
}
@@ -1728,6 +1735,23 @@ static void _losetup_usage(FILE *out)
"[-o offset] [-f|loop_device] [file]\n\n");
}
static int _help(int argc __attribute((unused)),
char **argv __attribute((unused)),
void *data __attribute((unused)))
{
_usage(stderr);
if (_switches[COLS_ARG]) {
_switches[OPTIONS_ARG] = 1;
_string_args[OPTIONS_ARG] = (char *) "help";
_switches[SORT_ARG] = 0;
(void) _report_init(NULL);
}
return 1;
}
static struct command *_find_command(const char *name)
{
int i;
@@ -1995,6 +2019,7 @@ static int _process_losetup_switches(const char *base, int *argc, char ***argv)
if (*argc != 2) {
fprintf(stderr, "%s: Too few arguments\n", base);
_losetup_usage(stderr);
dm_free(device_name);
return 0;
}
@@ -2003,6 +2028,7 @@ static int _process_losetup_switches(const char *base, int *argc, char ***argv)
fprintf(stderr, "%s: Could not parse loop file name %s\n",
base, (*argv)[1]);
_losetup_usage(stderr);
dm_free(device_name);
return 0;
}
@@ -2010,6 +2036,7 @@ static int _process_losetup_switches(const char *base, int *argc, char ***argv)
_table = dm_malloc(LOOP_TABLE_SIZE);
if (!_loop_table(_table, LOOP_TABLE_SIZE, loop_file, device_name, offset)) {
fprintf(stderr, "Could not build device-mapper table for %s\n", (*argv)[0]);
dm_free(device_name);
return 0;
}
_switches[TABLE_ARG]++;
@@ -2096,7 +2123,7 @@ static int _process_switches(int *argc, char ***argv)
return 1;
}
if(!strcmp(base, "losetup") || !strcmp(base, "dmlosetup")){
if (!strcmp(base, "losetup") || !strcmp(base, "dmlosetup")){
r = _process_losetup_switches(base, argc, argv);
free(namebase);
return r;

View File

@@ -95,7 +95,7 @@ static int _lvcreate_name_params(struct lvcreate_params *lp,
}
} else {
vg_name = skip_dev_dir(cmd, argv[0]);
vg_name = skip_dev_dir(cmd, argv[0], NULL);
if (strrchr(vg_name, '/')) {
log_error("Volume group name expected "
"(no slash)");

View File

@@ -19,3 +19,8 @@ int main(int argc, char **argv)
{
return lvm2_main(argc, argv, 1);
}
int lvm_shell(struct cmd_context *cmd, struct cmdline_context *cmdline)
{
return 0;
}

View File

@@ -13,9 +13,233 @@
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "tools.h"
#include "lvm2cmdline.h"
int main(int argc, char **argv)
{
return lvm2_main(argc, argv, 0);
}
#ifdef READLINE_SUPPORT
# include <readline/readline.h>
# include <readline/history.h>
# ifndef HAVE_RL_COMPLETION_MATCHES
# define rl_completion_matches(a, b) completion_matches((char *)a, b)
# endif
static struct cmdline_context *_cmdline;
/* List matching commands */
static char *_list_cmds(const char *text, int state)
{
static int i = 0;
static size_t len = 0;
/* Initialise if this is a new completion attempt */
if (!state) {
i = 0;
len = strlen(text);
}
while (i < _cmdline->num_commands)
if (!strncmp(text, _cmdline->commands[i++].name, len))
return strdup(_cmdline->commands[i - 1].name);
return NULL;
}
/* List matching arguments */
static char *_list_args(const char *text, int state)
{
static int match_no = 0;
static size_t len = 0;
static struct command *com;
/* Initialise if this is a new completion attempt */
if (!state) {
char *s = rl_line_buffer;
int j = 0;
match_no = 0;
com = NULL;
len = strlen(text);
/* Find start of first word in line buffer */
while (isspace(*s))
s++;
/* Look for word in list of commands */
for (j = 0; j < _cmdline->num_commands; j++) {
const char *p;
char *q = s;
p = _cmdline->commands[j].name;
while (*p == *q) {
p++;
q++;
}
if ((!*p) && *q == ' ') {
com = _cmdline->commands + j;
break;
}
}
if (!com)
return NULL;
}
/* Short form arguments */
if (len < 3) {
while (match_no < com->num_args) {
char s[3];
char c;
if (!(c = (_cmdline->the_args +
com->valid_args[match_no++])->short_arg))
continue;
sprintf(s, "-%c", c);
if (!strncmp(text, s, len))
return strdup(s);
}
}
/* Long form arguments */
if (match_no < com->num_args)
match_no = com->num_args;
while (match_no - com->num_args < com->num_args) {
const char *l;
l = (_cmdline->the_args +
com->valid_args[match_no++ - com->num_args])->long_arg;
if (*(l + 2) && !strncmp(text, l, len))
return strdup(l);
}
return NULL;
}
/* Custom completion function */
static char **_completion(const char *text, int start_pos, int end_pos)
{
char **match_list = NULL;
int p = 0;
while (isspace((int) *(rl_line_buffer + p)))
p++;
/* First word should be one of our commands */
if (start_pos == p)
match_list = rl_completion_matches(text, _list_cmds);
else if (*text == '-')
match_list = rl_completion_matches(text, _list_args);
/* else other args */
/* No further completion */
rl_attempted_completion_over = 1;
return match_list;
}
static int _hist_file(char *buffer, size_t size)
{
char *e = getenv("HOME");
if (dm_snprintf(buffer, size, "%s/.lvm_history", e) < 0) {
log_error("$HOME/.lvm_history: path too long");
return 0;
}
return 1;
}
static void _read_history(struct cmd_context *cmd)
{
char hist_file[PATH_MAX];
if (!_hist_file(hist_file, sizeof(hist_file)))
return;
if (read_history(hist_file))
log_very_verbose("Couldn't read history from %s.", hist_file);
stifle_history(find_config_tree_int(cmd, "shell/history_size",
DEFAULT_MAX_HISTORY));
}
static void _write_history(void)
{
char hist_file[PATH_MAX];
if (!_hist_file(hist_file, sizeof(hist_file)))
return;
if (write_history(hist_file))
log_very_verbose("Couldn't write history to %s.", hist_file);
}
int lvm_shell(struct cmd_context *cmd, struct cmdline_context *cmdline)
{
int argc, ret;
char *input = NULL, *args[MAX_ARGS], **argv;
rl_readline_name = "lvm";
rl_attempted_completion_function = (CPPFunction *) _completion;
_read_history(cmd);
_cmdline = cmdline;
_cmdline->interactive = 1;
while (1) {
free(input);
input = readline("lvm> ");
/* EOF */
if (!input) {
printf("\n");
break;
}
/* empty line */
if (!*input)
continue;
add_history(input);
argv = args;
if (lvm_split(input, &argc, argv, MAX_ARGS) == MAX_ARGS) {
log_error("Too many arguments, sorry.");
continue;
}
if (!strcmp(argv[0], "lvm")) {
argv++;
argc--;
}
if (!argc)
continue;
if (!strcmp(argv[0], "quit") || !strcmp(argv[0], "exit")) {
remove_history(history_length - 1);
log_error("Exiting.");
break;
}
ret = lvm_run_command(cmd, argc, argv);
if (ret == ENO_SUCH_CMD)
log_error("No such command '%s'. Try 'help'.",
argv[0]);
_write_history();
}
free(input);
return 0;
}
#endif /* READLINE_SUPPORT */

View File

@@ -18,6 +18,14 @@
struct cmd_context;
struct cmdline_context {
struct arg *the_args;
struct command *commands;
int num_commands;
int commands_size;
int interactive;
};
int lvm2_main(int argc, char **argv, unsigned is_static);
void *cmdlib_lvm2_init(unsigned is_static);
@@ -27,5 +35,6 @@ struct cmd_context *init_lvm(unsigned is_static);
void lvm_register_commands(void);
int lvm_split(char *str, int *argc, char **argv, int max);
int lvm_run_command(struct cmd_context *cmd, int argc, char **argv);
int lvm_shell(struct cmd_context *cmd, struct cmdline_context *cmdline);
#endif

View File

@@ -41,30 +41,16 @@ extern char *optarg;
# define OPTIND_INIT 1
#endif
#ifdef READLINE_SUPPORT
# include <readline/readline.h>
# include <readline/history.h>
# ifndef HAVE_RL_COMPLETION_MATCHES
# define rl_completion_matches(a, b) completion_matches((char *)a, b)
# endif
#endif
/*
* Exported table of valid switches
* Table of valid switches
*/
struct arg the_args[ARG_COUNT + 1] = {
static struct arg _the_args[ARG_COUNT + 1] = {
#define arg(a, b, c, d) {b, "", "--" c, d, 0, NULL, 0, 0, INT64_C(0), UINT64_C(0), SIGN_NONE, PERCENT_NONE, NULL},
#include "args.h"
#undef arg
};
static int _array_size;
static int _num_commands;
static struct command *_commands;
static int _interactive;
static struct cmdline_context _cmdline;
int yes_no_arg(struct cmd_context *cmd __attribute((unused)), struct arg *a)
{
@@ -412,21 +398,21 @@ char yes_no_prompt(const char *prompt, ...)
static void __alloc(int size)
{
if (!(_commands = dm_realloc(_commands, sizeof(*_commands) * size))) {
if (!(_cmdline.commands = dm_realloc(_cmdline.commands, sizeof(*_cmdline.commands) * size))) {
log_fatal("Couldn't allocate memory.");
exit(ECMD_FAILED);
}
_array_size = size;
_cmdline.commands_size = size;
}
static void _alloc_command(void)
{
if (!_array_size)
if (!_cmdline.commands_size)
__alloc(32);
if (_array_size <= _num_commands)
__alloc(2 * _array_size);
if (_cmdline.commands_size <= _cmdline.num_commands)
__alloc(2 * _cmdline.commands_size);
}
static void _create_new_command(const char *name, command_fn command,
@@ -437,7 +423,7 @@ static void _create_new_command(const char *name, command_fn command,
_alloc_command();
nc = _commands + _num_commands++;
nc = _cmdline.commands + _cmdline.num_commands++;
nc->name = name;
nc->desc = desc;
@@ -495,17 +481,17 @@ static struct command *_find_command(const char *name)
namebase = strdup(name);
base = basename(namebase);
for (i = 0; i < _num_commands; i++) {
if (!strcmp(base, _commands[i].name))
for (i = 0; i < _cmdline.num_commands; i++) {
if (!strcmp(base, _cmdline.commands[i].name))
break;
}
free(namebase);
if (i >= _num_commands)
if (i >= _cmdline.num_commands)
return 0;
return _commands + i;
return _cmdline.commands + i;
}
static void _usage(const char *name)
@@ -527,7 +513,7 @@ static void _usage(const char *name)
*/
static void _add_getopt_arg(int arg, char **ptr, struct option **o)
{
struct arg *a = the_args + arg;
struct arg *a = _cmdline.the_args + arg;
if (a->short_arg) {
*(*ptr)++ = a->short_arg;
@@ -556,12 +542,12 @@ static struct arg *_find_arg(struct command *com, int opt)
for (i = 0; i < com->num_args; i++) {
arg = com->valid_args[i];
a = the_args + arg;
a = _cmdline.the_args + arg;
/*
* opt should equal either the
* short arg, or the index into
* 'the_args'.
* the_args.
*/
if ((a->short_arg && (opt == a->short_arg)) ||
(!a->short_arg && (opt == arg)))
@@ -580,7 +566,7 @@ static int _process_command_line(struct cmd_context *cmd, int *argc,
struct arg *a;
for (i = 0; i < ARG_COUNT; i++) {
a = the_args + i;
a = _cmdline.the_args + i;
/* zero the count and arg */
a->count = 0;
@@ -651,15 +637,15 @@ static int _merge_synonym(struct cmd_context *cmd, int oldarg, int newarg)
if (arg_count(cmd, oldarg) && arg_count(cmd, newarg)) {
log_error("%s and %s are synonyms. Please only supply one.",
the_args[oldarg].long_arg, the_args[newarg].long_arg);
_cmdline.the_args[oldarg].long_arg, _cmdline.the_args[newarg].long_arg);
return 0;
}
if (!arg_count(cmd, oldarg))
return 1;
old = the_args + oldarg;
new = the_args + newarg;
old = _cmdline.the_args + oldarg;
new = _cmdline.the_args + newarg;
new->count = old->count;
new->value = old->value;
@@ -782,8 +768,8 @@ static void _display_help(void)
log_error("Use 'lvm help <command>' for more information");
log_error(" ");
for (i = 0; i < _num_commands; i++) {
struct command *com = _commands + i;
for (i = 0; i < _cmdline.num_commands; i++) {
struct command *com = _cmdline.commands + i;
log_error("%-16.16s%s", com->name, com->desc);
}
@@ -959,7 +945,7 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
*/
dm_pool_empty(cmd->mem);
if (ret == EINVALID_CMD_LINE && !_interactive)
if (ret == EINVALID_CMD_LINE && !_cmdline.interactive)
_usage(cmd->command->name);
log_debug("Completed: %s", cmd->cmd_line);
@@ -1030,7 +1016,9 @@ struct cmd_context *init_lvm(unsigned is_static)
{
struct cmd_context *cmd;
if (!(cmd = create_toolcontext(&the_args[0], is_static, 0))) {
_cmdline.the_args = &_the_args[0];
if (!(cmd = create_toolcontext(_cmdline.the_args, is_static, 0))) {
stack;
return NULL;
}
@@ -1046,10 +1034,10 @@ static void _fin_commands(void)
{
int i;
for (i = 0; i < _num_commands; i++)
dm_free(_commands[i].valid_args);
for (i = 0; i < _cmdline.num_commands; i++)
dm_free(_cmdline.commands[i].valid_args);
dm_free(_commands);
dm_free(_cmdline.commands);
}
void lvm_fin(struct cmd_context *cmd)
@@ -1106,218 +1094,6 @@ static int _run_script(struct cmd_context *cmd, int argc, char **argv)
return ret;
}
#ifdef READLINE_SUPPORT
/* List matching commands */
static char *_list_cmds(const char *text, int state)
{
static int i = 0;
static size_t len = 0;
/* Initialise if this is a new completion attempt */
if (!state) {
i = 0;
len = strlen(text);
}
while (i < _num_commands)
if (!strncmp(text, _commands[i++].name, len))
return strdup(_commands[i - 1].name);
return NULL;
}
/* List matching arguments */
static char *_list_args(const char *text, int state)
{
static int match_no = 0;
static size_t len = 0;
static struct command *com;
/* Initialise if this is a new completion attempt */
if (!state) {
char *s = rl_line_buffer;
int j = 0;
match_no = 0;
com = NULL;
len = strlen(text);
/* Find start of first word in line buffer */
while (isspace(*s))
s++;
/* Look for word in list of commands */
for (j = 0; j < _num_commands; j++) {
const char *p;
char *q = s;
p = _commands[j].name;
while (*p == *q) {
p++;
q++;
}
if ((!*p) && *q == ' ') {
com = _commands + j;
break;
}
}
if (!com)
return NULL;
}
/* Short form arguments */
if (len < 3) {
while (match_no < com->num_args) {
char s[3];
char c;
if (!(c = (the_args +
com->valid_args[match_no++])->short_arg))
continue;
sprintf(s, "-%c", c);
if (!strncmp(text, s, len))
return strdup(s);
}
}
/* Long form arguments */
if (match_no < com->num_args)
match_no = com->num_args;
while (match_no - com->num_args < com->num_args) {
const char *l;
l = (the_args +
com->valid_args[match_no++ - com->num_args])->long_arg;
if (*(l + 2) && !strncmp(text, l, len))
return strdup(l);
}
return NULL;
}
/* Custom completion function */
static char **_completion(const char *text, int start_pos, int end_pos)
{
char **match_list = NULL;
int p = 0;
while (isspace((int) *(rl_line_buffer + p)))
p++;
/* First word should be one of our commands */
if (start_pos == p)
match_list = rl_completion_matches(text, _list_cmds);
else if (*text == '-')
match_list = rl_completion_matches(text, _list_args);
/* else other args */
/* No further completion */
rl_attempted_completion_over = 1;
return match_list;
}
static int _hist_file(char *buffer, size_t size)
{
char *e = getenv("HOME");
if (dm_snprintf(buffer, size, "%s/.lvm_history", e) < 0) {
log_error("$HOME/.lvm_history: path too long");
return 0;
}
return 1;
}
static void _read_history(struct cmd_context *cmd)
{
char hist_file[PATH_MAX];
if (!_hist_file(hist_file, sizeof(hist_file)))
return;
if (read_history(hist_file))
log_very_verbose("Couldn't read history from %s.", hist_file);
stifle_history(find_config_tree_int(cmd, "shell/history_size",
DEFAULT_MAX_HISTORY));
}
static void _write_history(void)
{
char hist_file[PATH_MAX];
if (!_hist_file(hist_file, sizeof(hist_file)))
return;
if (write_history(hist_file))
log_very_verbose("Couldn't write history to %s.", hist_file);
}
static int _shell(struct cmd_context *cmd)
{
int argc, ret;
char *input = NULL, *args[MAX_ARGS], **argv;
rl_readline_name = "lvm";
rl_attempted_completion_function = (CPPFunction *) _completion;
_read_history(cmd);
_interactive = 1;
while (1) {
free(input);
input = readline("lvm> ");
/* EOF */
if (!input) {
printf("\n");
break;
}
/* empty line */
if (!*input)
continue;
add_history(input);
argv = args;
if (lvm_split(input, &argc, argv, MAX_ARGS) == MAX_ARGS) {
log_error("Too many arguments, sorry.");
continue;
}
if (!strcmp(argv[0], "lvm")) {
argv++;
argc--;
}
if (!argc)
continue;
if (!strcmp(argv[0], "quit") || !strcmp(argv[0], "exit")) {
remove_history(history_length - 1);
log_error("Exiting.");
break;
}
ret = lvm_run_command(cmd, argc, argv);
if (ret == ENO_SUCH_CMD)
log_error("No such command '%s'. Try 'help'.",
argv[0]);
_write_history();
}
free(input);
return 0;
}
#endif
/*
* Determine whether we should fall back and exec the equivalent LVM1 tool
*/
@@ -1403,7 +1179,7 @@ int lvm2_main(int argc, char **argv, unsigned is_static)
}
#ifdef READLINE_SUPPORT
if (!alias && argc == 1) {
ret = _shell(cmd);
ret = lvm_shell(cmd, &_cmdline);
goto out;
}
#endif

View File

@@ -29,7 +29,7 @@ int lvrename(struct cmd_context *cmd, int argc, char **argv)
struct lv_list *lvl;
if (argc == 3) {
vg_name = skip_dev_dir(cmd, argv[0]);
vg_name = skip_dev_dir(cmd, argv[0], NULL);
lv_name_old = argv[1];
lv_name_new = argv[2];
if (strchr(lv_name_old, '/') &&

View File

@@ -27,7 +27,7 @@ static const char *_extract_lvname(struct cmd_context *cmd, const char *vgname,
if (!strchr(arg, '/'))
return arg;
lvname = skip_dev_dir(cmd, arg);
lvname = skip_dev_dir(cmd, arg, NULL);
while (*lvname == '/')
lvname++;
if (!strchr(lvname, '/')) {

View File

@@ -138,6 +138,30 @@ out:
return ret;
}
static int _pvs_in_vg(struct cmd_context *cmd, const char *vg_name,
struct volume_group *vg, int consistent,
void *handle)
{
if (!vg) {
log_error("Volume group %s not found", vg_name);
return ECMD_FAILED;
}
return process_each_pv_in_vg(cmd, vg, NULL, handle, &_pvs_single);
}
static int _pvsegs_in_vg(struct cmd_context *cmd, const char *vg_name,
struct volume_group *vg, int consistent,
void *handle)
{
if (!vg) {
log_error("Volume group %s not found", vg_name);
return ECMD_FAILED;
}
return process_each_pv_in_vg(cmd, vg, NULL, handle, &_pvsegs_single);
}
static int _report(struct cmd_context *cmd, int argc, char **argv,
report_type_t report_type)
{
@@ -146,8 +170,8 @@ static int _report(struct cmd_context *cmd, int argc, char **argv,
char *str;
const char *keys = NULL, *options = NULL, *separator;
int r = ECMD_PROCESSED;
int aligned, buffered, headings;
unsigned args_are_pvs;
aligned = find_config_tree_int(cmd, "report/aligned",
DEFAULT_REP_ALIGNED);
@@ -158,6 +182,8 @@ static int _report(struct cmd_context *cmd, int argc, char **argv,
separator = find_config_tree_str(cmd, "report/separator",
DEFAULT_REP_SEPARATOR);
args_are_pvs = (report_type == PVS || report_type == PVSEGS) ? 1 : 0;
switch (report_type) {
case LVS:
keys = find_config_tree_str(cmd, "report/lvs_sort",
@@ -260,7 +286,7 @@ static int _report(struct cmd_context *cmd, int argc, char **argv,
if (!(report_handle = report_init(cmd, options, keys, &report_type,
separator, aligned, buffered,
headings)))
return 0;
return_0;
/* Ensure options selected are compatible */
if (report_type & SEGS)
@@ -269,6 +295,7 @@ static int _report(struct cmd_context *cmd, int argc, char **argv,
report_type |= PVS;
if ((report_type & LVS) && (report_type & PVS)) {
log_error("Can't report LV and PV fields at the same time");
dm_report_free(report_handle);
return 0;
}
@@ -292,16 +319,24 @@ static int _report(struct cmd_context *cmd, int argc, char **argv,
report_handle, &_vgs_single);
break;
case PVS:
r = process_each_pv(cmd, argc, argv, NULL, report_handle,
&_pvs_single);
if (args_are_pvs)
r = process_each_pv(cmd, argc, argv, NULL,
report_handle, &_pvs_single);
else
r = process_each_vg(cmd, argc, argv, LCK_VG_READ, 0,
report_handle, &_pvs_in_vg);
break;
case SEGS:
r = process_each_lv(cmd, argc, argv, LCK_VG_READ, report_handle,
&_lvsegs_single);
break;
case PVSEGS:
r = process_each_pv(cmd, argc, argv, NULL, report_handle,
&_pvsegs_single);
if (args_are_pvs)
r = process_each_pv(cmd, argc, argv, NULL,
report_handle, &_pvsegs_single);
else
r = process_each_vg(cmd, argc, argv, LCK_VG_READ, 0,
report_handle, &_pvsegs_in_vg);
break;
}

View File

@@ -88,21 +88,53 @@ const char *command_name(struct cmd_context *cmd)
/*
* Strip dev_dir if present
*/
char *skip_dev_dir(struct cmd_context *cmd, const char *vg_name)
char *skip_dev_dir(struct cmd_context *cmd, const char *vg_name,
unsigned *dev_dir_found)
{
/* FIXME Do this properly */
const char *dmdir = dm_dir();
size_t dmdir_len = strlen(dmdir), vglv_sz;
char *vgname, *lvname, *layer, *vglv;
/* FIXME Do this properly */
if (*vg_name == '/') {
while (*vg_name == '/')
vg_name++;
vg_name--;
}
/* Reformat string if /dev/mapper found */
if (!strncmp(vg_name, dmdir, dmdir_len) && vg_name[dmdir_len] == '/') {
if (dev_dir_found)
*dev_dir_found = 1;
vg_name += dmdir_len;
while (*vg_name == '/')
vg_name++;
if (!dm_split_lvm_name(cmd->mem, vg_name, &vgname, &lvname, &layer) ||
*layer) {
log_error("skip_dev_dir: Couldn't split up device name %s",
vg_name);
return (char *) vg_name;
}
vglv_sz = strlen(vgname) + strlen(lvname) + 2;
if (!(vglv = dm_pool_alloc(cmd->mem, vglv_sz)) ||
dm_snprintf(vglv, vglv_sz, "%s%s%s", vgname,
*lvname ? "/" : "",
lvname) < 0) {
log_error("vg/lv string alloc failed");
return (char *) vg_name;
}
return vglv;
}
if (!strncmp(vg_name, cmd->dev_dir, strlen(cmd->dev_dir))) {
if (dev_dir_found)
*dev_dir_found = 1;
vg_name += strlen(cmd->dev_dir);
while (*vg_name == '/')
vg_name++;
}
} else if (dev_dir_found)
*dev_dir_found = 0;
return (char *) vg_name;
}
@@ -222,7 +254,7 @@ int process_each_lv(struct cmd_context *cmd, int argc, char **argv,
for (; opt < argc; opt++) {
const char *lv_name = argv[opt];
char *vgname_def;
int dev_dir_found = 0;
unsigned dev_dir_found = 0;
/* Do we have a tag or vgname or lvname? */
vgname = lv_name;
@@ -243,18 +275,8 @@ int process_each_lv(struct cmd_context *cmd, int argc, char **argv,
}
/* FIXME Jumbled parsing */
if (*vgname == '/') {
while (*vgname == '/')
vgname++;
vgname--;
}
if (!strncmp(vgname, cmd->dev_dir,
strlen(cmd->dev_dir))) {
vgname += strlen(cmd->dev_dir);
dev_dir_found = 1;
while (*vgname == '/')
vgname++;
}
vgname = skip_dev_dir(cmd, vgname, &dev_dir_found);
if (*vgname == '/') {
log_error("\"%s\": Invalid path for Logical "
"Volume", argv[opt]);
@@ -528,7 +550,7 @@ int process_each_vg(struct cmd_context *cmd, int argc, char **argv,
continue;
}
vg_name = skip_dev_dir(cmd, vg_name);
vg_name = skip_dev_dir(cmd, vg_name, NULL);
if (strchr(vg_name, '/')) {
log_error("Invalid volume group name: %s",
vg_name);
@@ -830,7 +852,7 @@ char *default_vgname(struct cmd_context *cmd)
if (!vg_path)
return 0;
vg_path = skip_dev_dir(cmd, vg_path);
vg_path = skip_dev_dir(cmd, vg_path, NULL);
if (strchr(vg_path, '/')) {
log_error("Environment Volume Group in LVM_VG_NAME invalid: "

View File

@@ -76,7 +76,8 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
char *default_vgname(struct cmd_context *cmd);
const char *extract_vgname(struct cmd_context *cmd, const char *lv_name);
char *skip_dev_dir(struct cmd_context *cmd, const char *vg_name);
char *skip_dev_dir(struct cmd_context *cmd, const char *vg_name,
unsigned *dev_dir_found);
/*
* Builds a list of pv's from the names in argv. Used in

View File

@@ -24,7 +24,7 @@ int vgcfgrestore(struct cmd_context *cmd, int argc, char **argv)
return ECMD_FAILED;
}
vg_name = skip_dev_dir(cmd, argv[0]);
vg_name = skip_dev_dir(cmd, argv[0], NULL);
if (!validate_name(vg_name)) {
log_error("Volume group name \"%s\" is invalid", vg_name);

View File

@@ -38,7 +38,7 @@ int vgcreate(struct cmd_context *cmd, int argc, char **argv)
return EINVALID_CMD_LINE;
}
vg_name = skip_dev_dir(cmd, argv[0]);
vg_name = skip_dev_dir(cmd, argv[0], NULL);
max_lv = arg_uint_value(cmd, maxlogicalvolumes_ARG, 0);
max_pv = arg_uint_value(cmd, maxphysicalvolumes_ARG, 0);
alloc = arg_uint_value(cmd, alloc_ARG, ALLOC_NORMAL);

View File

@@ -32,7 +32,7 @@ int vgextend(struct cmd_context *cmd, int argc, char **argv)
return EINVALID_CMD_LINE;
}
vg_name = skip_dev_dir(cmd, argv[0]);
vg_name = skip_dev_dir(cmd, argv[0], NULL);
argc--;
argv++;
@@ -41,6 +41,12 @@ int vgextend(struct cmd_context *cmd, int argc, char **argv)
return ECMD_FAILED;
}
if (!validate_name(vg_name)) {
log_error("Volume group name \"%s\" is invalid",
vg_name);
return ECMD_FAILED;
}
log_verbose("Checking for volume group \"%s\"", vg_name);
if (!lock_vol(cmd, vg_name, LCK_VG_WRITE | LCK_NONBLOCK)) {
unlock_vg(cmd, ORPHAN);

View File

@@ -253,12 +253,12 @@ int vgmerge(struct cmd_context *cmd, int argc, char **argv)
return EINVALID_CMD_LINE;
}
vg_name_to = skip_dev_dir(cmd, argv[0]);
vg_name_to = skip_dev_dir(cmd, argv[0], NULL);
argc--;
argv++;
for (; opt < argc; opt++) {
vg_name_from = skip_dev_dir(cmd, argv[opt]);
vg_name_from = skip_dev_dir(cmd, argv[opt], NULL);
ret = _vgmerge_single(cmd, vg_name_to, vg_name_from);
if (ret > ret_max)

View File

@@ -427,13 +427,13 @@ int vgreduce(struct cmd_context *cmd, int argc, char **argv)
int ret = 1;
int consistent = 1;
if (!argc & !arg_count(cmd, removemissing_ARG)) {
if (!argc && !arg_count(cmd, removemissing_ARG)) {
log_error("Please give volume group name and "
"physical volume paths");
return EINVALID_CMD_LINE;
}
if (!argc & arg_count(cmd, removemissing_ARG)) {
if (!argc && arg_count(cmd, removemissing_ARG)) {
log_error("Please give volume group name");
return EINVALID_CMD_LINE;
}
@@ -461,10 +461,16 @@ int vgreduce(struct cmd_context *cmd, int argc, char **argv)
return EINVALID_CMD_LINE;
}
vg_name = skip_dev_dir(cmd, argv[0]);
vg_name = skip_dev_dir(cmd, argv[0], NULL);
argv++;
argc--;
if (!validate_name(vg_name)) {
log_error("Volume group name \"%s\" is invalid",
vg_name);
return ECMD_FAILED;
}
log_verbose("Finding volume group \"%s\"", vg_name);
if (!lock_vol(cmd, vg_name, LCK_VG_WRITE)) {
log_error("Can't get lock for %s", vg_name);

View File

@@ -87,6 +87,11 @@ int vgremove(struct cmd_context *cmd, int argc, char **argv)
{
int ret;
if (!argc) {
log_error("Please enter one or more volume group paths");
return EINVALID_CMD_LINE;
}
if (!lock_vol(cmd, ORPHAN, LCK_VG_WRITE)) {
log_error("Can't get lock for orphan PVs");
return ECMD_FAILED;

View File

@@ -35,8 +35,8 @@ int vgrename(struct cmd_context *cmd, int argc, char **argv)
return EINVALID_CMD_LINE;
}
vg_name_old = skip_dev_dir(cmd, argv[0]);
vg_name_new = skip_dev_dir(cmd, argv[1]);
vg_name_old = skip_dev_dir(cmd, argv[0], NULL);
vg_name_new = skip_dev_dir(cmd, argv[1], NULL);
dev_dir = cmd->dev_dir;
length = strlen(dev_dir);
@@ -118,7 +118,7 @@ int vgrename(struct cmd_context *cmd, int argc, char **argv)
return ECMD_FAILED;
}
if (lvs_in_vg_activated(vg_old)) {
if (lvs_in_vg_activated_by_uuid_only(vg_old)) {
unlock_vg(cmd, vg_name_old);
log_error("Volume group \"%s\" still has active LVs",
vg_name_old);

View File

@@ -72,6 +72,9 @@ static int _move_lvs(struct volume_group *vg_from, struct volume_group *vg_to)
if ((lv->status & SNAPSHOT))
continue;
if ((lv->status & MIRRORED))
continue;
/* Ensure all the PVs used by this LV remain in the same */
/* VG as each other */
vg_with = NULL;
@@ -161,6 +164,48 @@ static int _move_snapshots(struct volume_group *vg_from,
return 1;
}
static int _move_mirrors(struct volume_group *vg_from,
struct volume_group *vg_to)
{
struct list *lvh, *lvht;
struct logical_volume *lv;
struct lv_segment *seg;
int i, seg_in, log_in;
list_iterate_safe(lvh, lvht, &vg_from->lvs) {
lv = list_item(lvh, struct lv_list)->lv;
if (!(lv->status & MIRRORED))
continue;
seg = first_seg(lv);
seg_in = 0;
for (i = 0; i < seg->area_count; i++)
if (_lv_is_in_vg(vg_to, seg_lv(seg, i)))
seg_in++;
log_in = (!seg->log_lv || _lv_is_in_vg(vg_to, seg->log_lv));
if ((seg_in && seg_in < seg->area_count) ||
(seg_in && seg->log_lv && !log_in) ||
(!seg_in && seg->log_lv && log_in)) {
log_error("Mirror %s split", lv->name);
return 0;
}
if (seg_in == seg->area_count && log_in) {
list_del(lvh);
list_add(&vg_to->lvs, lvh);
vg_from->lv_count--;
vg_to->lv_count++;
}
}
return 1;
}
int vgsplit(struct cmd_context *cmd, int argc, char **argv)
{
char *vg_name_from, *vg_name_to;
@@ -174,11 +219,17 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv)
return EINVALID_CMD_LINE;
}
vg_name_from = argv[0];
vg_name_to = argv[1];
vg_name_from = skip_dev_dir(cmd, argv[0], NULL);
vg_name_to = skip_dev_dir(cmd, argv[1], NULL);
argc -= 2;
argv += 2;
if (!validate_name(vg_name_from)) {
log_error("Volume group name \"%s\" is invalid",
vg_name_from);
return ECMD_FAILED;
}
if (!strcmp(vg_name_to, vg_name_from)) {
log_error("Duplicate volume group name \"%s\"", vg_name_from);
return ECMD_FAILED;
@@ -275,6 +326,10 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv)
if (!(_move_snapshots(vg_from, vg_to)))
goto error;
/* Move required mirrors across */
if (!(_move_mirrors(vg_from, vg_to)))
goto error;
/* FIXME Split mdas properly somehow too! */
/* Currently we cheat by sharing the format instance and relying on
* vg_write to ignore mdas outside the VG! Done this way, with text