mirror of
git://sourceware.org/git/lvm2.git
synced 2025-12-24 16:23:50 +03:00
Compare commits
76 Commits
dm_v1_02_1
...
old-dm_v1_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e366b68ad3 | ||
|
|
fb94fb980a | ||
|
|
b10cc18f53 | ||
|
|
a249de3b72 | ||
|
|
d04e972d65 | ||
|
|
b9f5a18a76 | ||
|
|
d3f157f08a | ||
|
|
2294fdb496 | ||
|
|
d7ba0e01a5 | ||
|
|
b6172b53fd | ||
|
|
477ec611d5 | ||
|
|
b6194edd67 | ||
|
|
dcdbbb3ecb | ||
|
|
7ef99ee4e6 | ||
|
|
1ac1418286 | ||
|
|
8fc854f38e | ||
|
|
1c2360b335 | ||
|
|
dd4477406b | ||
|
|
9d67bbb104 | ||
|
|
d6c8e1df61 | ||
|
|
5ec7c8fece | ||
|
|
86b21eaf83 | ||
|
|
228486a971 | ||
|
|
88c0caab26 | ||
|
|
5cd4679419 | ||
|
|
eeed5e0d19 | ||
|
|
369ab1e0b2 | ||
|
|
2e21519a10 | ||
|
|
ecc001ed08 | ||
|
|
cd96852696 | ||
|
|
b9f7f30158 | ||
|
|
ca5e423331 | ||
|
|
fa9407089c | ||
|
|
66f28e193a | ||
|
|
0d93f89f5c | ||
|
|
154e9a2c47 | ||
|
|
84574a1257 | ||
|
|
bf83527b64 | ||
|
|
12c53622a0 | ||
|
|
d8f54cf891 | ||
|
|
625a671189 | ||
|
|
6ebdad3102 | ||
|
|
9a8f21aa03 | ||
|
|
291dd8edc2 | ||
|
|
de4c1daf29 | ||
|
|
0b55d7d0d8 | ||
|
|
5d86fd8fdb | ||
|
|
1b76eb1f59 | ||
|
|
b05678d8bf | ||
|
|
781f4971c6 | ||
|
|
d02ac7b99a | ||
|
|
b1b6c97f7c | ||
|
|
baee28ab5c | ||
|
|
83edf68ff9 | ||
|
|
c7588f91dd | ||
|
|
30b432adc5 | ||
|
|
7c9733eb5d | ||
|
|
a223c3fea3 | ||
|
|
d5250f4901 | ||
|
|
25f29f4712 | ||
|
|
382af5563d | ||
|
|
8cf3d165d3 | ||
|
|
0fd6ce546f | ||
|
|
b881c372bc | ||
|
|
94c5e7deb0 | ||
|
|
c344766f3c | ||
|
|
67895de0bc | ||
|
|
ff00cb6990 | ||
|
|
2cc75c11ed | ||
|
|
cd79e58eda | ||
|
|
6fa801f3d8 | ||
|
|
684eecba1d | ||
|
|
da9cf7e5de | ||
|
|
f57e7445fd | ||
|
|
fba1388719 | ||
|
|
80ed029c17 |
66
WHATS_NEW
66
WHATS_NEW
@@ -1,3 +1,69 @@
|
||||
Version 2.02.25 - 27th April 2007
|
||||
=================================
|
||||
Fix get_config_uint64() to read a 64-bit value not a 32-bit one.
|
||||
Add -Wformat-security and change one fprintf() to fputs().
|
||||
Move regex functions into libdevmapper.
|
||||
Change some #include lines to search only standard system directories.
|
||||
Add devices/preferred_names config regex list for displayed device names.
|
||||
Free a temporary dir string in fcntl_lock_file() after use.
|
||||
Fix a dm_pool_destroy() in matcher_create().
|
||||
Introduce goto_bad macro.
|
||||
Fix warnings on x86_64 involving ptrdiff_t in log_error messages.
|
||||
Update pvck to include text metadata area and record detection.
|
||||
Add support functions for token counting in config file extracts.
|
||||
Update pvck to read labels on disk, with --labelsector parameter.
|
||||
Add count_chars and count_chars_len functions.
|
||||
Add /sys/block listings to lvm_dump.sh.
|
||||
Make lvm_dump.sh list /dev recursively.
|
||||
Fix thread race in clvmd.
|
||||
Add scan_sector param to label_read and _find_labeller.
|
||||
Make clvmd cope with quorum devices.
|
||||
Add extra internal error checking to clvmd.
|
||||
Add dev_read_circular.
|
||||
Add pvck command stub.
|
||||
Update lists of attribute characters in man pages.
|
||||
Change cling alloc policy attribute character from 'C' to l'.
|
||||
Fix creation and conversion of mirrors with tags.
|
||||
Fix vgsplit for lvm1 format (set and validate VG name in PVs metadata).
|
||||
Split metadata areas in vgsplit properly.
|
||||
|
||||
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.
|
||||
|
||||
23
WHATS_NEW_DM
23
WHATS_NEW_DM
@@ -1,3 +1,26 @@
|
||||
Version 1.02.19 - 27th April 2007
|
||||
=================================
|
||||
Standardise protective include file #defines.
|
||||
Add regex functions to library.
|
||||
Avoid trailing separator in reports when there are hidden sort fields.
|
||||
Fix segfault in 'dmsetup status' without --showkeys against crypt target.
|
||||
Deal with some more compiler warnings.
|
||||
Introduce _add_field() and _is_same_field() to libdm-report.c.
|
||||
Fix some libdevmapper-event and dmeventd memory leaks.
|
||||
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.
|
||||
|
||||
@@ -36,10 +36,10 @@
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <errno.h>
|
||||
#include <libdlm.h>
|
||||
|
||||
#include "clvmd-comms.h"
|
||||
#include "clvm.h"
|
||||
#include "libdlm.h"
|
||||
#include "log.h"
|
||||
#include "clvmd.h"
|
||||
#include "lvm-functions.h"
|
||||
@@ -121,7 +121,7 @@ static int _get_num_nodes()
|
||||
|
||||
/* return number of ACTIVE nodes */
|
||||
for (i=0; i<num_nodes; i++) {
|
||||
if (nodes[i].cn_member)
|
||||
if (nodes[i].cn_member && nodes[i].cn_nodeid)
|
||||
nnodes++;
|
||||
}
|
||||
return nnodes;
|
||||
@@ -159,7 +159,7 @@ static int _cluster_do_node_callback(struct local_client *client,
|
||||
int somedown = 0;
|
||||
|
||||
for (i = 0; i < _get_num_nodes(); i++) {
|
||||
if (nodes[i].cn_member) {
|
||||
if (nodes[i].cn_member && nodes[i].cn_nodeid) {
|
||||
callback(client, (char *)&nodes[i].cn_nodeid, node_updown[nodes[i].cn_nodeid]);
|
||||
if (!node_updown[nodes[i].cn_nodeid])
|
||||
somedown = -1;
|
||||
@@ -168,8 +168,7 @@ static int _cluster_do_node_callback(struct local_client *client,
|
||||
return somedown;
|
||||
}
|
||||
|
||||
/* Process OOB message from the cluster socket,
|
||||
this currently just means that a node has stopped listening on our port */
|
||||
/* Process OOB messages from the cluster socket */
|
||||
static void event_callback(cman_handle_t handle, void *private, int reason, int arg)
|
||||
{
|
||||
char namebuf[MAX_CLUSTER_MEMBER_NAME_LEN];
|
||||
|
||||
@@ -64,8 +64,9 @@
|
||||
#include <stddef.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <libdevmapper.h>
|
||||
#include <libdlm.h>
|
||||
|
||||
#include "libdevmapper.h"
|
||||
#include "list.h"
|
||||
#include "locking.h"
|
||||
#include "log.h"
|
||||
@@ -73,7 +74,6 @@
|
||||
#include "clvmd-comms.h"
|
||||
#include "clvm.h"
|
||||
#include "clvmd.h"
|
||||
#include "libdlm.h"
|
||||
|
||||
extern struct cluster_ops *clops;
|
||||
|
||||
|
||||
@@ -40,9 +40,10 @@
|
||||
#include <utmpx.h>
|
||||
#include <syslog.h>
|
||||
#include <assert.h>
|
||||
#include <libdevmapper.h>
|
||||
#include <ccs.h>
|
||||
#include <libgulm.h>
|
||||
|
||||
#include "libdevmapper.h"
|
||||
#include "ccs.h"
|
||||
#include "list.h"
|
||||
#include "locking.h"
|
||||
#include "log.h"
|
||||
@@ -51,7 +52,6 @@
|
||||
#include "lvm-functions.h"
|
||||
#include "clvmd.h"
|
||||
#include "clvmd-gulm.h"
|
||||
#include "libgulm.h"
|
||||
|
||||
/* Hash list of nodes in the cluster */
|
||||
static struct dm_hash_table *node_hash;
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include <getopt.h>
|
||||
#include <syslog.h>
|
||||
#include <errno.h>
|
||||
#include <libdlm.h>
|
||||
|
||||
#include "clvmd-comms.h"
|
||||
#include "lvm-functions.h"
|
||||
@@ -44,7 +45,6 @@
|
||||
#include "version.h"
|
||||
#include "clvmd.h"
|
||||
#include "refresh_clvmd.h"
|
||||
#include "libdlm.h"
|
||||
#include "system-lv.h"
|
||||
#include "list.h"
|
||||
#include "log.h"
|
||||
@@ -56,6 +56,8 @@
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#define MAX_RETRIES 4
|
||||
|
||||
/* The maximum size of a message that will fit into a packet. Anything bigger
|
||||
than this is sent via the system LV */
|
||||
#define MAX_INLINE_MESSAGE (max_cluster_message-sizeof(struct clvm_header))
|
||||
@@ -325,7 +327,7 @@ int main(int argc, char *argv[])
|
||||
/* This needs to be started after cluster initialisation
|
||||
as it may need to take out locks */
|
||||
DEBUGLOG("starting LVM thread\n");
|
||||
pthread_create(&lvm_thread, NULL, lvm_thread_fn,
|
||||
pthread_create(&lvm_thread, NULL, lvm_thread_fn,
|
||||
(void *)(long)using_gulm);
|
||||
|
||||
/* Tell the rest of the cluster our version number */
|
||||
@@ -375,6 +377,9 @@ static int local_rendezvous_callback(struct local_client *thisfd, char *buf,
|
||||
socklen_t sl = sizeof(socka);
|
||||
int client_fd = accept(thisfd->fd, (struct sockaddr *) &socka, &sl);
|
||||
|
||||
if (client_fd == -1 && errno == EINTR)
|
||||
return 1;
|
||||
|
||||
if (client_fd >= 0) {
|
||||
newfd = malloc(sizeof(struct local_client));
|
||||
if (!newfd) {
|
||||
@@ -412,6 +417,8 @@ static int local_pipe_callback(struct local_client *thisfd, char *buf,
|
||||
int status = -1; /* in error by default */
|
||||
|
||||
len = read(thisfd->fd, buffer, sizeof(int));
|
||||
if (len == -1 && errno == EINTR)
|
||||
return 1;
|
||||
|
||||
if (len == sizeof(int)) {
|
||||
memcpy(&status, buffer, sizeof(int));
|
||||
@@ -786,6 +793,8 @@ static int read_from_local_sock(struct local_client *thisfd)
|
||||
char buffer[PIPE_BUF];
|
||||
|
||||
len = read(thisfd->fd, buffer, sizeof(buffer));
|
||||
if (len == -1 && errno == EINTR)
|
||||
return 1;
|
||||
|
||||
DEBUGLOG("Read on local socket %d, len = %d\n", thisfd->fd, len);
|
||||
|
||||
@@ -901,8 +910,12 @@ static int read_from_local_sock(struct local_client *thisfd)
|
||||
len - strlen(inheader->node) - sizeof(struct clvm_header);
|
||||
missing_len = inheader->arglen - argslen;
|
||||
|
||||
if (missing_len < 0)
|
||||
missing_len = 0;
|
||||
|
||||
/* Save the message */
|
||||
thisfd->bits.localsock.cmd = malloc(len + missing_len);
|
||||
|
||||
if (!thisfd->bits.localsock.cmd) {
|
||||
struct clvm_header reply;
|
||||
reply.cmd = CLVMD_CMD_REPLY;
|
||||
@@ -927,9 +940,8 @@ static int read_from_local_sock(struct local_client *thisfd)
|
||||
DEBUGLOG
|
||||
("got %d bytes, need another %d (total %d)\n",
|
||||
argslen, missing_len, inheader->arglen);
|
||||
len =
|
||||
read(thisfd->fd, argptr + argslen,
|
||||
missing_len);
|
||||
len = read(thisfd->fd, argptr + argslen,
|
||||
missing_len);
|
||||
if (len >= 0) {
|
||||
missing_len -= len;
|
||||
argslen += len;
|
||||
@@ -1215,7 +1227,7 @@ static void process_remote_command(struct clvm_header *msg, int msglen, int fd,
|
||||
/* Version check is internal - don't bother exposing it in
|
||||
clvmd-command.c */
|
||||
if (msg->cmd == CLVMD_CMD_VERSION) {
|
||||
int version_nums[3];
|
||||
int version_nums[3];
|
||||
char node[256];
|
||||
|
||||
memcpy(version_nums, msg->args, sizeof(version_nums));
|
||||
@@ -1395,6 +1407,7 @@ static __attribute__ ((noreturn)) void *pre_and_post_thread(void *arg)
|
||||
{
|
||||
struct local_client *client = (struct local_client *) arg;
|
||||
int status;
|
||||
int write_status;
|
||||
sigset_t ss;
|
||||
int pipe_fd = client->bits.localsock.pipe;
|
||||
|
||||
@@ -1424,8 +1437,19 @@ static __attribute__ ((noreturn)) void *pre_and_post_thread(void *arg)
|
||||
client->bits.localsock.all_success = 0;
|
||||
|
||||
DEBUGLOG("Writing status %d down pipe %d\n", status, pipe_fd);
|
||||
|
||||
/* Tell the parent process we have finished this bit */
|
||||
write(pipe_fd, &status, sizeof(int));
|
||||
do {
|
||||
write_status = write(pipe_fd, &status, sizeof(int));
|
||||
if (write_status == sizeof(int))
|
||||
break;
|
||||
if (write_status < 0 &&
|
||||
(errno == EINTR || errno == EAGAIN))
|
||||
continue;
|
||||
log_error("Error sending to pipe: %m\n");
|
||||
break;
|
||||
} while(1);
|
||||
|
||||
if (status)
|
||||
continue; /* Wait for another PRE command */
|
||||
|
||||
@@ -1446,7 +1470,16 @@ static __attribute__ ((noreturn)) void *pre_and_post_thread(void *arg)
|
||||
status = 0;
|
||||
do_post_command(client);
|
||||
|
||||
write(pipe_fd, &status, sizeof(int));
|
||||
do {
|
||||
write_status = write(pipe_fd, &status, sizeof(int));
|
||||
if (write_status == sizeof(int))
|
||||
break;
|
||||
if (write_status < 0 &&
|
||||
(errno == EINTR || errno == EAGAIN))
|
||||
continue;
|
||||
log_error("Error sending to pipe: %m\n");
|
||||
break;
|
||||
} while(1);
|
||||
|
||||
DEBUGLOG("Waiting for next pre command\n");
|
||||
|
||||
@@ -1650,6 +1683,11 @@ static int send_message(void *buf, int msglen, char *csid, int fd,
|
||||
const char *errtext)
|
||||
{
|
||||
int len;
|
||||
int saved_errno = 0;
|
||||
struct timespec delay;
|
||||
struct timespec remtime;
|
||||
|
||||
int retry_cnt = 0;
|
||||
|
||||
/* Send remote messages down the cluster socket */
|
||||
if (csid == NULL || !ISLOCAL_CSID(csid)) {
|
||||
@@ -1660,14 +1698,38 @@ static int send_message(void *buf, int msglen, char *csid, int fd,
|
||||
|
||||
/* Make sure it all goes */
|
||||
do {
|
||||
if (retry_cnt > MAX_RETRIES)
|
||||
{
|
||||
errno = saved_errno;
|
||||
log_error(errtext);
|
||||
errno = saved_errno;
|
||||
break;
|
||||
}
|
||||
|
||||
len = write(fd, buf + ptr, msglen - ptr);
|
||||
|
||||
if (len <= 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
if (errno == EAGAIN ||
|
||||
errno == EIO ||
|
||||
errno == ENOSPC) {
|
||||
saved_errno = errno;
|
||||
retry_cnt++;
|
||||
|
||||
delay.tv_sec = 0;
|
||||
delay.tv_nsec = 100000;
|
||||
remtime.tv_sec = 0;
|
||||
remtime.tv_nsec = 0;
|
||||
(void) nanosleep (&delay, &remtime);
|
||||
|
||||
continue;
|
||||
}
|
||||
log_error(errtext);
|
||||
break;
|
||||
}
|
||||
ptr += len;
|
||||
} while (len < msglen);
|
||||
} while (ptr < msglen);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
@@ -30,11 +30,11 @@
|
||||
#include <errno.h>
|
||||
#include <syslog.h>
|
||||
#include <assert.h>
|
||||
#include <libdevmapper.h>
|
||||
#include <libdlm.h>
|
||||
|
||||
#include "libdevmapper.h"
|
||||
#include "list.h"
|
||||
#include "lvm-types.h"
|
||||
#include "libdlm.h"
|
||||
#include "clvm.h"
|
||||
#include "clvmd-comms.h"
|
||||
#include "clvmd.h"
|
||||
@@ -50,6 +50,7 @@
|
||||
static struct cmd_context *cmd = NULL;
|
||||
static struct dm_hash_table *lv_hash = NULL;
|
||||
static pthread_mutex_t lv_hash_lock;
|
||||
static pthread_mutex_t lvm_lock;
|
||||
static char last_error[1024];
|
||||
|
||||
struct lv_info {
|
||||
@@ -311,10 +312,12 @@ int do_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
|
||||
DEBUGLOG("do_lock_lv: resource '%s', cmd = 0x%x, flags = %x\n",
|
||||
resource, command, lock_flags);
|
||||
|
||||
pthread_mutex_lock(&lvm_lock);
|
||||
if (!cmd->config_valid || config_files_changed(cmd)) {
|
||||
/* Reinitialise various settings inc. logging, filters */
|
||||
if (!refresh_toolcontext(cmd)) {
|
||||
log_error("Updated config file invalid. Aborting.");
|
||||
pthread_mutex_unlock(&lvm_lock);
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
@@ -367,6 +370,7 @@ int do_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
|
||||
|
||||
/* clean the pool for another command */
|
||||
dm_pool_empty(cmd->mem);
|
||||
pthread_mutex_unlock(&lvm_lock);
|
||||
|
||||
DEBUGLOG("Command return is %d\n", status);
|
||||
return status;
|
||||
@@ -393,6 +397,8 @@ int pre_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
|
||||
int post_lock_lv(unsigned char command, unsigned char lock_flags,
|
||||
char *resource)
|
||||
{
|
||||
int status;
|
||||
|
||||
/* Opposite of above, done on resume after a metadata update */
|
||||
if (command == LCK_LV_RESUME) {
|
||||
int oldmode;
|
||||
@@ -406,7 +412,10 @@ int post_lock_lv(unsigned char command, unsigned char lock_flags,
|
||||
if (oldmode == LKM_PWMODE) {
|
||||
struct lvinfo lvi;
|
||||
|
||||
if (!lv_info_by_lvid(cmd, resource, &lvi, 0))
|
||||
pthread_mutex_lock(&lvm_lock);
|
||||
status = lv_info_by_lvid(cmd, resource, &lvi, 0);
|
||||
pthread_mutex_unlock(&lvm_lock);
|
||||
if (!status)
|
||||
return EIO;
|
||||
|
||||
if (lvi.exists) {
|
||||
@@ -533,7 +542,7 @@ static void lvm2_log_fn(int level, const char *file, int line,
|
||||
const char *message)
|
||||
{
|
||||
/*
|
||||
* Ignore non-error messages, but store the latest one for returning
|
||||
* Ignore non-error messages, but store the latest one for returning
|
||||
* to the user.
|
||||
*/
|
||||
if (level != _LOG_ERR && level != _LOG_FATAL)
|
||||
@@ -572,6 +581,7 @@ void init_lvhash()
|
||||
/* Create hash table for keeping LV locks & status */
|
||||
lv_hash = dm_hash_create(100);
|
||||
pthread_mutex_init(&lv_hash_lock, NULL);
|
||||
pthread_mutex_init(&lvm_lock, NULL);
|
||||
}
|
||||
|
||||
/* Called to initialise the LVM context of the daemon */
|
||||
|
||||
@@ -36,8 +36,11 @@
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <mntent.h>
|
||||
#include <libdlm.h>
|
||||
#ifdef HAVE_CCS
|
||||
#include <ccs.h>
|
||||
#endif
|
||||
|
||||
#include "libdlm.h"
|
||||
#include "log.h"
|
||||
#include "list.h"
|
||||
#include "locking.h"
|
||||
@@ -45,9 +48,6 @@
|
||||
#include "clvm.h"
|
||||
#include "clvmd-comms.h"
|
||||
#include "clvmd.h"
|
||||
#ifdef HAVE_CCS
|
||||
#include "ccs.h"
|
||||
#endif
|
||||
|
||||
#define SYSTEM_LV_FILESYSTEM "ext2"
|
||||
#define SYSTEM_LV_MOUNTPOINT "/tmp/.clvmd-XXXXXX"
|
||||
|
||||
@@ -34,8 +34,8 @@
|
||||
#include <syslog.h>
|
||||
#include <netdb.h>
|
||||
#include <assert.h>
|
||||
#include <libdevmapper.h>
|
||||
|
||||
#include "libdevmapper.h"
|
||||
#include "clvm.h"
|
||||
#include "clvmd-comms.h"
|
||||
#include "clvmd.h"
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -244,6 +245,8 @@ static struct thread_status *_alloc_thread_status(struct message_data *data,
|
||||
|
||||
static void _free_thread_status(struct thread_status *thread)
|
||||
{
|
||||
if (thread->current_task)
|
||||
dm_task_destroy(thread->current_task);
|
||||
dm_free(thread->device.uuid);
|
||||
dm_free(thread->device.name);
|
||||
dm_free(thread);
|
||||
@@ -257,8 +260,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 +323,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 +347,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, ' ')) {
|
||||
@@ -617,6 +623,8 @@ static int _event_wait(struct thread_status *thread, struct dm_task **task)
|
||||
} else if (thread->events & DM_EVENT_TIMEOUT && errno == EINTR) {
|
||||
thread->current_events |= DM_EVENT_TIMEOUT;
|
||||
ret = DM_WAIT_INTR;
|
||||
} else if (thread->status == DM_THREAD_SHUTDOWN && errno == EINTR) {
|
||||
ret = DM_WAIT_FATAL;
|
||||
} else {
|
||||
syslog(LOG_NOTICE, "dm_task_run failed, errno = %d, %s",
|
||||
errno, strerror(errno));
|
||||
@@ -807,11 +815,6 @@ static int _create_thread(struct thread_status *thread)
|
||||
|
||||
static int _terminate_thread(struct thread_status *thread)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if ((ret = pthread_cancel(thread->thread)))
|
||||
return ret;
|
||||
|
||||
return pthread_kill(thread->thread, SIGALRM);
|
||||
}
|
||||
|
||||
@@ -875,8 +878,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 +1059,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 +1070,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 +1184,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 +1380,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 = 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 +1425,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;
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -323,13 +359,24 @@ static int _daemon_talk(struct dm_event_fifos *fifos,
|
||||
*/
|
||||
if (!_daemon_write(fifos, msg)) {
|
||||
stack;
|
||||
dm_free(msg->data);
|
||||
msg->data = 0;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (!_daemon_read(fifos, msg)) {
|
||||
stack;
|
||||
return -EIO;
|
||||
}
|
||||
do {
|
||||
|
||||
if (msg->data)
|
||||
dm_free(msg->data);
|
||||
msg->data = 0;
|
||||
|
||||
if (!_daemon_read(fifos, msg)) {
|
||||
stack;
|
||||
return -EIO;
|
||||
}
|
||||
} while (!_check_message_id(msg));
|
||||
|
||||
_sequence_nr++;
|
||||
|
||||
return (int32_t) msg->cmd;
|
||||
}
|
||||
@@ -507,7 +554,14 @@ 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 (msg->data)
|
||||
dm_free(msg->data);
|
||||
msg->data = 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 +575,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 +605,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 +652,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 +680,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;
|
||||
@@ -667,6 +726,12 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
|
||||
|
||||
dm_event_handler_set_dso(dmevh, reply_dso);
|
||||
dm_event_handler_set_event_mask(dmevh, reply_mask);
|
||||
|
||||
if (reply_dso)
|
||||
dm_free(reply_dso);
|
||||
if (reply_uuid)
|
||||
dm_free(reply_uuid);
|
||||
|
||||
dmevh->dev_name = dm_strdup(dm_task_get_name(dmt));
|
||||
if (!dmevh->dev_name) {
|
||||
ret = -ENOMEM;
|
||||
@@ -689,6 +754,10 @@ int dm_event_get_registered_device(struct dm_event_handler *dmevh, int next)
|
||||
fail:
|
||||
if (msg.data)
|
||||
dm_free(msg.data);
|
||||
if (reply_dso)
|
||||
dm_free(reply_dso);
|
||||
if (reply_uuid)
|
||||
dm_free(reply_uuid);
|
||||
_dm_event_handler_clear_dev_info(dmevh);
|
||||
dm_task_destroy(dmt);
|
||||
return ret;
|
||||
@@ -696,9 +765,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 +787,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;
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "libdevmapper.h"
|
||||
#include "libdevmapper-event.h"
|
||||
#include "lvm2cmd.h"
|
||||
|
||||
#include <libdevmapper.h>
|
||||
#include <libdevmapper-event.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "libdevmapper.h"
|
||||
#include "libdevmapper-event.h"
|
||||
#include "lvm2cmd.h"
|
||||
|
||||
#include <libdevmapper.h>
|
||||
#include <libdevmapper-event.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -19,6 +19,14 @@ devices {
|
||||
# to use with LVM2.
|
||||
scan = [ "/dev" ]
|
||||
|
||||
# If several entries in the scanned directories correspond to the
|
||||
# same block device and the tools need to display a name for device,
|
||||
# all the pathnames are matched against each item in the following
|
||||
# list of regular expressions in turn and the first match is used.
|
||||
preferred_names = [ ]
|
||||
|
||||
# preferred_names = [ "^/dev/mpath/", "^/dev/[hs]d" ]
|
||||
|
||||
# A filter that tells LVM2 to only use a restricted set of devices.
|
||||
# The filter consists of an array of regular expressions. These
|
||||
# expressions can be delimited by a character of your choice, and
|
||||
@@ -56,10 +64,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 +200,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.
|
||||
|
||||
@@ -43,7 +43,6 @@
|
||||
../lib/misc/lvm-string.h
|
||||
../lib/misc/lvm-wrappers.h
|
||||
../lib/misc/sharedlib.h
|
||||
../lib/regex/matcher.h
|
||||
../lib/report/report.h
|
||||
../lib/uuid/uuid.h
|
||||
../po/pogen.h
|
||||
|
||||
@@ -81,9 +81,6 @@ SOURCES =\
|
||||
misc/lvm-wrappers.c \
|
||||
misc/timestamp.c \
|
||||
mm/memlock.c \
|
||||
regex/matcher.c \
|
||||
regex/parse_rx.c \
|
||||
regex/ttree.c \
|
||||
report/report.c \
|
||||
striped/striped.c \
|
||||
uuid/uuid.c \
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
|
||||
@@ -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 */
|
||||
@@ -446,10 +435,8 @@ struct dev_manager *dev_manager_create(struct cmd_context *cmd,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(dm = dm_pool_alloc(mem, sizeof(*dm)))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(dm = dm_pool_alloc(mem, sizeof(*dm))))
|
||||
goto_bad;
|
||||
|
||||
dm->cmd = cmd;
|
||||
dm->mem = mem;
|
||||
@@ -461,10 +448,8 @@ struct dev_manager *dev_manager_create(struct cmd_context *cmd,
|
||||
}
|
||||
dm->stripe_filler = stripe_filler;
|
||||
|
||||
if (!(dm->vg_name = dm_pool_strdup(dm->mem, vg_name))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(dm->vg_name = dm_pool_strdup(dm->mem, vg_name)))
|
||||
goto_bad;
|
||||
|
||||
dm->target_state = NULL;
|
||||
|
||||
@@ -646,7 +631,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;
|
||||
}
|
||||
|
||||
12
lib/cache/lvmcache.c
vendored
12
lib/cache/lvmcache.c
vendored
@@ -135,7 +135,7 @@ const struct format_type *fmt_from_vgname(const char *vgname, const char *vgid)
|
||||
|
||||
list_iterate_safe(devh, tmp, &devs) {
|
||||
devl = list_item(devh, struct device_list);
|
||||
label_read(devl->dev, &label);
|
||||
label_read(devl->dev, &label, UINT64_C(0));
|
||||
list_del(&devl->list);
|
||||
dm_free(devl);
|
||||
}
|
||||
@@ -205,7 +205,7 @@ static void _rescan_entry(struct lvmcache_info *info)
|
||||
struct label *label;
|
||||
|
||||
if (info->status & CACHE_INVALID)
|
||||
label_read(info->dev, &label);
|
||||
label_read(info->dev, &label, UINT64_C(0));
|
||||
}
|
||||
|
||||
static int _scan_invalid(void)
|
||||
@@ -247,7 +247,7 @@ int lvmcache_label_scan(struct cmd_context *cmd, int full_scan)
|
||||
}
|
||||
|
||||
while ((dev = dev_iter_get(iter)))
|
||||
label_read(dev, &label);
|
||||
label_read(dev, &label, UINT64_C(0));
|
||||
|
||||
dev_iter_destroy(iter);
|
||||
|
||||
@@ -346,7 +346,7 @@ struct device *device_from_pvid(struct cmd_context *cmd, struct id *pvid)
|
||||
|
||||
/* Already cached ? */
|
||||
if ((info = info_from_pvid((char *) pvid))) {
|
||||
if (label_read(info->dev, &label)) {
|
||||
if (label_read(info->dev, &label, UINT64_C(0))) {
|
||||
info = (struct lvmcache_info *) label->info;
|
||||
if (id_equal(pvid, (struct id *) &info->dev->pvid))
|
||||
return info->dev;
|
||||
@@ -357,7 +357,7 @@ struct device *device_from_pvid(struct cmd_context *cmd, struct id *pvid)
|
||||
|
||||
/* Try again */
|
||||
if ((info = info_from_pvid((char *) pvid))) {
|
||||
if (label_read(info->dev, &label)) {
|
||||
if (label_read(info->dev, &label, UINT64_C(0))) {
|
||||
info = (struct lvmcache_info *) label->info;
|
||||
if (id_equal(pvid, (struct id *) &info->dev->pvid))
|
||||
return info->dev;
|
||||
@@ -371,7 +371,7 @@ struct device *device_from_pvid(struct cmd_context *cmd, struct id *pvid)
|
||||
|
||||
/* Try again */
|
||||
if ((info = info_from_pvid((char *) pvid))) {
|
||||
if (label_read(info->dev, &label)) {
|
||||
if (label_read(info->dev, &label, UINT64_C(0))) {
|
||||
info = (struct lvmcache_info *) label->info;
|
||||
if (id_equal(pvid, (struct id *) &info->dev->pvid))
|
||||
return info->dev;
|
||||
|
||||
@@ -465,10 +465,8 @@ static int _init_dev_cache(struct cmd_context *cmd)
|
||||
const struct config_node *cn;
|
||||
struct config_value *cv;
|
||||
|
||||
if (!dev_cache_init()) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
if (!dev_cache_init(cmd))
|
||||
return_0;
|
||||
|
||||
if (!(cn = find_config_tree_node(cmd, "devices/scan"))) {
|
||||
if (!dev_cache_add_dir("/dev")) {
|
||||
@@ -575,7 +573,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 +583,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 +768,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 +794,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "device.h"
|
||||
#include "str_list.h"
|
||||
#include "toolcontext.h"
|
||||
#include "lvm-string.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
@@ -26,6 +27,9 @@
|
||||
#include <fcntl.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#define SECTION_B_CHAR '{'
|
||||
#define SECTION_E_CHAR '}'
|
||||
|
||||
enum {
|
||||
TOK_INT,
|
||||
TOK_FLOAT,
|
||||
@@ -79,7 +83,8 @@ static const int sep = '/';
|
||||
|
||||
#define match(t) do {\
|
||||
if (!_match_aux(p, (t))) {\
|
||||
log_error("Parse error at byte %d (line %d): unexpected token", p->tb - p->fb + 1, p->line); \
|
||||
log_error("Parse error at byte %" PRIptrdiff_t " (line %d): unexpected token", \
|
||||
p->tb - p->fb + 1, p->line); \
|
||||
return 0;\
|
||||
} \
|
||||
} while(0);
|
||||
@@ -210,18 +215,10 @@ int read_config_fd(struct config_tree *cft, struct device *dev,
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
if (!dev_read(dev, (uint64_t) offset, size, buf)) {
|
||||
log_error("Read from %s failed", dev_name(dev));
|
||||
if (!dev_read_circular(dev, (uint64_t) offset, size,
|
||||
(uint64_t) offset2, size2, buf)) {
|
||||
goto out;
|
||||
}
|
||||
if (size2) {
|
||||
if (!dev_read(dev, (uint64_t) offset2, size2,
|
||||
buf + size)) {
|
||||
log_error("Circular read from %s failed",
|
||||
dev_name(dev));
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
p->fb = buf;
|
||||
}
|
||||
|
||||
@@ -360,7 +357,7 @@ static void _write_value(FILE *fp, struct config_value *v)
|
||||
break;
|
||||
|
||||
case CFG_INT:
|
||||
fprintf(fp, "%d", v->v.i);
|
||||
fprintf(fp, "%" PRId64, v->v.i);
|
||||
break;
|
||||
|
||||
case CFG_EMPTY_ARRAY:
|
||||
@@ -482,7 +479,7 @@ static struct config_node *_file(struct parser *p)
|
||||
|
||||
static struct config_node *_section(struct parser *p)
|
||||
{
|
||||
/* IDENTIFIER '{' VALUE* '}' */
|
||||
/* IDENTIFIER SECTION_B_CHAR VALUE* SECTION_E_CHAR */
|
||||
struct config_node *root, *n, *l = NULL;
|
||||
if (!(root = _create_node(p))) {
|
||||
stack;
|
||||
@@ -571,7 +568,7 @@ static struct config_value *_type(struct parser *p)
|
||||
switch (p->t) {
|
||||
case TOK_INT:
|
||||
v->type = CFG_INT;
|
||||
v->v.i = strtol(p->tb, NULL, 0); /* FIXME: check error */
|
||||
v->v.i = strtoll(p->tb, NULL, 0); /* FIXME: check error */
|
||||
match(TOK_INT);
|
||||
break;
|
||||
|
||||
@@ -594,7 +591,8 @@ static struct config_value *_type(struct parser *p)
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error("Parse error at byte %d (line %d): expected a value", p->tb - p->fb + 1, p->line);
|
||||
log_error("Parse error at byte %" PRIptrdiff_t " (line %d): expected a value",
|
||||
p->tb - p->fb + 1, p->line);
|
||||
return 0;
|
||||
}
|
||||
return v;
|
||||
@@ -631,12 +629,12 @@ static void _get_token(struct parser *p, int tok_prev)
|
||||
p->t = TOK_INT; /* fudge so the fall through for
|
||||
floats works */
|
||||
switch (*p->te) {
|
||||
case '{':
|
||||
case SECTION_B_CHAR:
|
||||
p->t = TOK_SECTION_B;
|
||||
p->te++;
|
||||
break;
|
||||
|
||||
case '}':
|
||||
case SECTION_E_CHAR:
|
||||
p->t = TOK_SECTION_E;
|
||||
p->te++;
|
||||
break;
|
||||
@@ -716,8 +714,9 @@ static void _get_token(struct parser *p, int tok_prev)
|
||||
default:
|
||||
p->t = TOK_IDENTIFIER;
|
||||
while ((p->te != p->fe) && (*p->te) && !isspace(*p->te) &&
|
||||
(*p->te != '#') && (*p->te != '=') && (*p->te != '{') &&
|
||||
(*p->te != '}'))
|
||||
(*p->te != '#') && (*p->te != '=') &&
|
||||
(*p->te != SECTION_B_CHAR) &&
|
||||
(*p->te != SECTION_E_CHAR))
|
||||
p->te++;
|
||||
break;
|
||||
}
|
||||
@@ -872,25 +871,26 @@ const char *find_config_str(const struct config_node *cn,
|
||||
return _find_config_str(cn, NULL, path, fail);
|
||||
}
|
||||
|
||||
static int _find_config_int(const struct config_node *cn1,
|
||||
const struct config_node *cn2,
|
||||
const char *path, int fail)
|
||||
static int64_t _find_config_int64(const struct config_node *cn1,
|
||||
const struct config_node *cn2,
|
||||
const char *path, int64_t fail)
|
||||
{
|
||||
const struct config_node *n = _find_first_config_node(cn1, cn2, path);
|
||||
|
||||
if (n && n->v->type == CFG_INT) {
|
||||
log_very_verbose("Setting %s to %d", path, n->v->v.i);
|
||||
if (n && n->v && n->v->type == CFG_INT) {
|
||||
log_very_verbose("Setting %s to %" PRId64, path, n->v->v.i);
|
||||
return n->v->v.i;
|
||||
}
|
||||
|
||||
log_very_verbose("%s not found in config: defaulting to %d",
|
||||
log_very_verbose("%s not found in config: defaulting to %" PRId64,
|
||||
path, fail);
|
||||
return fail;
|
||||
}
|
||||
|
||||
int find_config_int(const struct config_node *cn, const char *path, int fail)
|
||||
{
|
||||
return _find_config_int(cn, NULL, path, fail);
|
||||
/* FIXME Add log_error message on overflow */
|
||||
return (int) _find_config_int64(cn, NULL, path, (int64_t) fail);
|
||||
}
|
||||
|
||||
static float _find_config_float(const struct config_node *cn1,
|
||||
@@ -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;
|
||||
}
|
||||
@@ -932,7 +932,8 @@ const char *find_config_tree_str(struct cmd_context *cmd,
|
||||
int find_config_tree_int(struct cmd_context *cmd, const char *path,
|
||||
int fail)
|
||||
{
|
||||
return _find_config_int(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path, fail);
|
||||
/* FIXME Add log_error message on overflow */
|
||||
return (int) _find_config_int64(cmd->cft_override ? cmd->cft_override->root : NULL, cmd->cft->root, path, (int64_t) fail);
|
||||
}
|
||||
|
||||
float find_config_tree_float(struct cmd_context *cmd, const char *path,
|
||||
@@ -1024,7 +1025,6 @@ int get_config_uint64(const struct config_node *cn, const char *path,
|
||||
if (!n || !n->v || n->v->type != CFG_INT)
|
||||
return 0;
|
||||
|
||||
/* FIXME Support 64-bit value! */
|
||||
*result = (uint64_t) n->v->v.i;
|
||||
return 1;
|
||||
}
|
||||
@@ -1154,3 +1154,61 @@ int merge_config_tree(struct cmd_context *cmd, struct config_tree *cft,
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a token type to the char it represents.
|
||||
*/
|
||||
static char _token_type_to_char(int type)
|
||||
{
|
||||
switch (type) {
|
||||
case TOK_SECTION_B:
|
||||
return SECTION_B_CHAR;
|
||||
case TOK_SECTION_E:
|
||||
return SECTION_E_CHAR;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns:
|
||||
* # of 'type' tokens in 'str'.
|
||||
*/
|
||||
static unsigned _count_tokens (const char *str, unsigned len, int type)
|
||||
{
|
||||
char c;
|
||||
|
||||
c = _token_type_to_char(type);
|
||||
|
||||
return(count_chars_len(str, len, c));
|
||||
}
|
||||
|
||||
/*
|
||||
* Heuristic function to make a quick guess as to whether a text
|
||||
* region probably contains a valid config "section". (Useful for
|
||||
* scanning areas of the disk for old metadata.)
|
||||
* Config sections contain various tokens, may contain other sections
|
||||
* and strings, and are delimited by begin (type 'TOK_SECTION_B') and
|
||||
* end (type 'TOK_SECTION_E') tokens. As a quick heuristic, we just
|
||||
* count the number of begin and end tokens, and see if they are
|
||||
* non-zero and the counts match.
|
||||
* Full validation of the section should be done with another function
|
||||
* (for example, read_config_fd).
|
||||
*
|
||||
* Returns:
|
||||
* 0 - probably is not a valid config section
|
||||
* 1 - probably _is_ a valid config section
|
||||
*/
|
||||
unsigned maybe_config_section(const char *str, unsigned len)
|
||||
{
|
||||
int begin_count;
|
||||
int end_count;
|
||||
|
||||
begin_count = _count_tokens(str, len, TOK_SECTION_B);
|
||||
end_count = _count_tokens(str, len, TOK_SECTION_E);
|
||||
|
||||
if (begin_count && end_count && (begin_count - end_count == 0))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ enum {
|
||||
struct config_value {
|
||||
int type;
|
||||
union {
|
||||
int i;
|
||||
int64_t i;
|
||||
float r;
|
||||
char *str;
|
||||
} v;
|
||||
@@ -108,4 +108,6 @@ int get_config_uint64(const struct config_node *cn, const char *path,
|
||||
int get_config_str(const struct config_node *cn, const char *path,
|
||||
char **result);
|
||||
|
||||
unsigned maybe_config_section(const char *str, unsigned len);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
/* Define some portable printing types */
|
||||
#define PRIsize_t "zu"
|
||||
#define PRIptrdiff_t "td"
|
||||
|
||||
struct str_list {
|
||||
struct list list;
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "btree.h"
|
||||
#include "filter.h"
|
||||
#include "filter-persistent.h"
|
||||
#include "toolcontext.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/param.h>
|
||||
@@ -38,6 +39,7 @@ static struct {
|
||||
struct dm_pool *mem;
|
||||
struct dm_hash_table *names;
|
||||
struct btree *devices;
|
||||
struct dm_regex *preferred_names_matcher;
|
||||
|
||||
int has_scanned;
|
||||
struct list dirs;
|
||||
@@ -129,15 +131,52 @@ static struct device *_dev_create(dev_t d)
|
||||
return dev;
|
||||
}
|
||||
|
||||
void dev_set_preferred_name(struct str_list *sl, struct device *dev)
|
||||
{
|
||||
/*
|
||||
* Don't interfere with ordering specified in config file.
|
||||
*/
|
||||
if (_cache.preferred_names_matcher)
|
||||
return;
|
||||
|
||||
log_debug("%s: New preferred name", sl->str);
|
||||
list_del(&sl->list);
|
||||
list_add_h(&dev->aliases, &sl->list);
|
||||
}
|
||||
|
||||
/* Return 1 if we prefer path1 else return 0 */
|
||||
static int _compare_paths(const char *path0, const char *path1)
|
||||
{
|
||||
int slash0 = 0, slash1 = 0;
|
||||
int m0, m1;
|
||||
const char *p;
|
||||
char p0[PATH_MAX], p1[PATH_MAX];
|
||||
char *s0, *s1;
|
||||
struct stat stat0, stat1;
|
||||
|
||||
/*
|
||||
* FIXME Better to compare patterns one-at-a-time against all names.
|
||||
*/
|
||||
if (_cache.preferred_names_matcher) {
|
||||
m0 = dm_regex_match(_cache.preferred_names_matcher, path0);
|
||||
m1 = dm_regex_match(_cache.preferred_names_matcher, path1);
|
||||
|
||||
if (m0 != m1) {
|
||||
if (m0 < 0)
|
||||
return 1;
|
||||
if (m1 < 0)
|
||||
return 0;
|
||||
if (m0 < m1)
|
||||
return 1;
|
||||
if (m1 < m0)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Built-in rules.
|
||||
*/
|
||||
|
||||
/* Return the path with fewer slashes */
|
||||
for (p = path0; p++; p = (const char *) strchr(p, '/'))
|
||||
slash0++;
|
||||
@@ -441,7 +480,65 @@ void dev_cache_scan(int do_scan)
|
||||
_full_scan(1);
|
||||
}
|
||||
|
||||
int dev_cache_init(void)
|
||||
static int _init_preferred_names(struct cmd_context *cmd)
|
||||
{
|
||||
const struct config_node *cn;
|
||||
struct config_value *v;
|
||||
struct dm_pool *scratch = NULL;
|
||||
char **regex;
|
||||
unsigned count = 0;
|
||||
int i, r = 0;
|
||||
|
||||
_cache.preferred_names_matcher = NULL;
|
||||
|
||||
if (!(cn = find_config_tree_node(cmd, "devices/preferred_names")) ||
|
||||
cn->v->type == CFG_EMPTY_ARRAY) {
|
||||
log_very_verbose("devices/preferred_names not found in config file: "
|
||||
"using built-in preferences");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (v = cn->v; v; v = v->next) {
|
||||
if (v->type != CFG_STRING) {
|
||||
log_error("preferred_names patterns must be enclosed in quotes");
|
||||
return 0;
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
if (!(scratch = dm_pool_create("preferred device name matcher", 1024)))
|
||||
return_0;
|
||||
|
||||
if (!(regex = dm_pool_alloc(scratch, sizeof(*regex) * count))) {
|
||||
log_error("Failed to allocate preferred device name "
|
||||
"pattern list.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (v = cn->v, i = count - 1; v; v = v->next, i--) {
|
||||
if (!(regex[i] = dm_pool_strdup(scratch, v->v.str))) {
|
||||
log_error("Failed to allocate a preferred device name "
|
||||
"pattern.");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(_cache.preferred_names_matcher =
|
||||
dm_regex_create(_cache.mem,(const char **) regex, count))) {
|
||||
log_error("Preferred device name pattern matcher creation failed.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
dm_pool_destroy(scratch);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int dev_cache_init(struct cmd_context *cmd)
|
||||
{
|
||||
_cache.names = NULL;
|
||||
_cache.has_scanned = 0;
|
||||
@@ -466,6 +563,9 @@ int dev_cache_init(void)
|
||||
list_init(&_cache.dirs);
|
||||
list_init(&_cache.files);
|
||||
|
||||
if (!_init_preferred_names(cmd))
|
||||
goto_bad;
|
||||
|
||||
return 1;
|
||||
|
||||
bad:
|
||||
@@ -489,6 +589,9 @@ void dev_cache_exit(void)
|
||||
if (_cache.names)
|
||||
_check_for_open_devices();
|
||||
|
||||
if (_cache.preferred_names_matcher)
|
||||
_cache.preferred_names_matcher = NULL;
|
||||
|
||||
if (_cache.mem) {
|
||||
dm_pool_destroy(_cache.mem);
|
||||
_cache.mem = NULL;
|
||||
|
||||
@@ -30,7 +30,8 @@ struct dev_filter {
|
||||
/*
|
||||
* The global device cache.
|
||||
*/
|
||||
int dev_cache_init(void);
|
||||
struct cmd_context;
|
||||
int dev_cache_init(struct cmd_context *cmd);
|
||||
void dev_cache_exit(void);
|
||||
|
||||
/* Trigger(1) or avoid(0) a scan */
|
||||
@@ -41,6 +42,8 @@ int dev_cache_add_dir(const char *path);
|
||||
int dev_cache_add_loopfile(const char *path);
|
||||
struct device *dev_cache_get(const char *name, struct dev_filter *f);
|
||||
|
||||
void dev_set_preferred_name(struct str_list *sl, struct device *dev);
|
||||
|
||||
/*
|
||||
* Object for iterating through the cache.
|
||||
*/
|
||||
|
||||
@@ -564,6 +564,35 @@ int dev_read(struct device *dev, uint64_t offset, size_t len, void *buffer)
|
||||
return _aligned_io(&where, buffer, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read from 'dev' into 'buf', possibly in 2 distinct regions, denoted
|
||||
* by (offset,len) and (offset2,len2). Thus, the total size of
|
||||
* 'buf' should be len+len2.
|
||||
*/
|
||||
int dev_read_circular(struct device *dev, uint64_t offset, size_t len,
|
||||
uint64_t offset2, size_t len2, void *buf)
|
||||
{
|
||||
if (!dev_read(dev, offset, len, buf)) {
|
||||
log_error("Read from %s failed", dev_name(dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The second region is optional, and allows for
|
||||
* a circular buffer on the device.
|
||||
*/
|
||||
if (!len2)
|
||||
return 1;
|
||||
|
||||
if (!dev_read(dev, offset2, len2, buf + len)) {
|
||||
log_error("Circular read from %s failed",
|
||||
dev_name(dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* FIXME If O_DIRECT can't extend file, dev_extend first; dev_truncate after.
|
||||
* But fails if concurrent processes writing
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -78,6 +78,8 @@ int dev_fd(struct device *dev);
|
||||
const char *dev_name(const struct device *dev);
|
||||
|
||||
int dev_read(struct device *dev, uint64_t offset, size_t len, void *buffer);
|
||||
int dev_read_circular(struct device *dev, uint64_t offset, size_t len,
|
||||
uint64_t offset2, size_t len2, void *buf);
|
||||
int dev_write(struct device *dev, uint64_t offset, size_t len, void *buffer);
|
||||
int dev_append(struct device *dev, size_t len, void *buffer);
|
||||
int dev_set(struct device *dev, uint64_t offset, size_t len, int value);
|
||||
|
||||
@@ -301,10 +301,9 @@ struct dev_filter *persistent_filter_create(struct dev_filter *real,
|
||||
}
|
||||
memset(pf, 0, sizeof(*pf));
|
||||
|
||||
if (!(pf->file = dm_malloc(strlen(file) + 1))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(pf->file = dm_malloc(strlen(file) + 1)))
|
||||
goto_bad;
|
||||
|
||||
strcpy(pf->file, file);
|
||||
pf->real = real;
|
||||
|
||||
@@ -313,10 +312,8 @@ struct dev_filter *persistent_filter_create(struct dev_filter *real,
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!(f = dm_malloc(sizeof(*f)))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(f = dm_malloc(sizeof(*f))))
|
||||
goto_bad;
|
||||
|
||||
f->passes_filter = _lookup_p;
|
||||
f->destroy = _persistent_destroy;
|
||||
|
||||
@@ -15,13 +15,12 @@
|
||||
|
||||
#include "lib.h"
|
||||
#include "filter-regex.h"
|
||||
#include "matcher.h"
|
||||
#include "device.h"
|
||||
|
||||
struct rfilter {
|
||||
struct dm_pool *mem;
|
||||
dm_bitset_t accept;
|
||||
struct matcher *engine;
|
||||
struct dm_regex *engine;
|
||||
};
|
||||
|
||||
static int _extract_pattern(struct dm_pool *mem, const char *pat,
|
||||
@@ -98,18 +97,15 @@ static int _build_matcher(struct rfilter *rf, struct config_value *val)
|
||||
unsigned count = 0;
|
||||
int i, r = 0;
|
||||
|
||||
if (!(scratch = dm_pool_create("filter matcher", 1024))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
if (!(scratch = dm_pool_create("filter dm_regex", 1024)))
|
||||
return_0;
|
||||
|
||||
/*
|
||||
* count how many patterns we have.
|
||||
*/
|
||||
for (v = val; v; v = v->next) {
|
||||
|
||||
if (v->type != CFG_STRING) {
|
||||
log_info("filter patterns must be enclosed in quotes");
|
||||
log_error("filter patterns must be enclosed in quotes");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -119,10 +115,8 @@ static int _build_matcher(struct rfilter *rf, struct config_value *val)
|
||||
/*
|
||||
* allocate space for them
|
||||
*/
|
||||
if (!(regex = dm_pool_alloc(scratch, sizeof(*regex) * count))) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
if (!(regex = dm_pool_alloc(scratch, sizeof(*regex) * count)))
|
||||
goto_out;
|
||||
|
||||
/*
|
||||
* create the accept/reject bitset
|
||||
@@ -136,15 +130,15 @@ static int _build_matcher(struct rfilter *rf, struct config_value *val)
|
||||
*/
|
||||
for (v = val, i = count - 1; v; v = v->next, i--)
|
||||
if (!_extract_pattern(scratch, v->v.str, regex, rf->accept, i)) {
|
||||
log_info("invalid filter pattern");
|
||||
log_error("invalid filter pattern");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* build the matcher.
|
||||
*/
|
||||
if (!(rf->engine = matcher_create(rf->mem, (const char **) regex,
|
||||
count)))
|
||||
if (!(rf->engine = dm_regex_create(rf->mem, (const char **) regex,
|
||||
count)))
|
||||
stack;
|
||||
r = 1;
|
||||
|
||||
@@ -160,17 +154,12 @@ static int _accept_p(struct dev_filter *f, struct device *dev)
|
||||
struct str_list *sl;
|
||||
|
||||
list_iterate_items(sl, &dev->aliases) {
|
||||
m = matcher_run(rf->engine, sl->str);
|
||||
m = dm_regex_match(rf->engine, sl->str);
|
||||
|
||||
if (m >= 0) {
|
||||
if (dm_bit(rf->accept, m)) {
|
||||
|
||||
if (!first) {
|
||||
log_debug("%s: New preferred name",
|
||||
sl->str);
|
||||
list_del(&sl->list);
|
||||
list_add_h(&dev->aliases, &sl->list);
|
||||
}
|
||||
if (!first)
|
||||
dev_set_preferred_name(sl, dev);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -208,22 +197,16 @@ struct dev_filter *regex_filter_create(struct config_value *patterns)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(rf = dm_pool_alloc(mem, sizeof(*rf)))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(rf = dm_pool_alloc(mem, sizeof(*rf))))
|
||||
goto_bad;
|
||||
|
||||
rf->mem = mem;
|
||||
|
||||
if (!_build_matcher(rf, patterns)) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!_build_matcher(rf, patterns))
|
||||
goto_bad;
|
||||
|
||||
if (!(f = dm_pool_zalloc(mem, sizeof(*f)))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(f = dm_pool_zalloc(mem, sizeof(*f))))
|
||||
goto_bad;
|
||||
|
||||
f->passes_filter = _accept_p;
|
||||
f->destroy = _regex_destroy;
|
||||
|
||||
@@ -284,10 +284,8 @@ struct dev_filter *sysfs_filter_create(const char *proc)
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!(f = dm_pool_zalloc(mem, sizeof(*f)))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(f = dm_pool_zalloc(mem, sizeof(*f))))
|
||||
goto_bad;
|
||||
|
||||
f->passes_filter = _accept_p;
|
||||
f->destroy = _destroy;
|
||||
|
||||
@@ -357,10 +357,8 @@ static struct disk_list *__read_disk(const struct format_type *fmt,
|
||||
list_init(&dl->uuids);
|
||||
list_init(&dl->lvds);
|
||||
|
||||
if (!_read_pvd(dev, &dl->pvd)) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!_read_pvd(dev, &dl->pvd))
|
||||
goto_bad;
|
||||
|
||||
/*
|
||||
* is it an orphan ?
|
||||
|
||||
@@ -131,10 +131,10 @@ static struct volume_group *_build_vg(struct format_instance *fid,
|
||||
int partial;
|
||||
|
||||
if (!vg)
|
||||
goto bad;
|
||||
goto_bad;
|
||||
|
||||
if (list_empty(pvs))
|
||||
goto bad;
|
||||
goto_bad;
|
||||
|
||||
memset(vg, 0, sizeof(*vg));
|
||||
|
||||
@@ -146,24 +146,24 @@ static struct volume_group *_build_vg(struct format_instance *fid,
|
||||
list_init(&vg->tags);
|
||||
|
||||
if (!_check_vgs(pvs, &partial))
|
||||
goto bad;
|
||||
goto_bad;
|
||||
|
||||
dl = list_item(pvs->n, struct disk_list);
|
||||
|
||||
if (!import_vg(mem, vg, dl, partial))
|
||||
goto bad;
|
||||
goto_bad;
|
||||
|
||||
if (!import_pvs(fid->fmt, mem, vg, pvs, &vg->pvs, &vg->pv_count))
|
||||
goto bad;
|
||||
goto_bad;
|
||||
|
||||
if (!import_lvs(mem, vg, pvs))
|
||||
goto bad;
|
||||
goto_bad;
|
||||
|
||||
if (!import_extents(fid->fmt->cmd, vg, pvs))
|
||||
goto bad;
|
||||
goto_bad;
|
||||
|
||||
if (!import_snapshots(mem, vg, pvs))
|
||||
goto bad;
|
||||
goto_bad;
|
||||
|
||||
return vg;
|
||||
|
||||
@@ -191,15 +191,11 @@ static struct volume_group *_format1_vg_read(struct format_instance *fid,
|
||||
vg_name = strip_dir(vg_name, fid->fmt->cmd->dev_dir);
|
||||
|
||||
if (!read_pvs_in_vg
|
||||
(fid->fmt, vg_name, fid->fmt->cmd->filter, mem, &pvs)) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
(fid->fmt, vg_name, fid->fmt->cmd->filter, mem, &pvs))
|
||||
goto_bad;
|
||||
|
||||
if (!(vg = _build_vg(fid, &pvs))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(vg = _build_vg(fid, &pvs)))
|
||||
goto_bad;
|
||||
|
||||
bad:
|
||||
dm_pool_destroy(mem);
|
||||
@@ -415,17 +411,14 @@ static int _format1_pv_write(const struct format_type *fmt, struct physical_volu
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(dl = dm_pool_alloc(mem, sizeof(*dl)))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(dl = dm_pool_alloc(mem, sizeof(*dl))))
|
||||
goto_bad;
|
||||
|
||||
dl->mem = mem;
|
||||
dl->dev = pv->dev;
|
||||
|
||||
if (!export_pv(fmt->cmd, mem, NULL, &dl->pvd, pv)) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!export_pv(fmt->cmd, mem, NULL, &dl->pvd, pv))
|
||||
goto_bad;
|
||||
|
||||
/* must be set to be able to zero gap after PV structure in
|
||||
dev_write in order to make other disk tools happy */
|
||||
@@ -434,10 +427,8 @@ static int _format1_pv_write(const struct format_type *fmt, struct physical_volu
|
||||
dl->pvd.pe_on_disk.base = LVM1_PE_ALIGN << SECTOR_SHIFT;
|
||||
|
||||
list_add(&pvs, &dl->list);
|
||||
if (!write_disks(fmt, &pvs)) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!write_disks(fmt, &pvs))
|
||||
goto_bad;
|
||||
|
||||
dm_pool_destroy(mem);
|
||||
return 1;
|
||||
|
||||
@@ -59,22 +59,16 @@ static struct dm_hash_table *_create_lv_maps(struct dm_pool *mem,
|
||||
if (ll->lv->status & SNAPSHOT)
|
||||
continue;
|
||||
|
||||
if (!(lvm = dm_pool_alloc(mem, sizeof(*lvm)))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(lvm = dm_pool_alloc(mem, sizeof(*lvm))))
|
||||
goto_bad;
|
||||
|
||||
lvm->lv = ll->lv;
|
||||
if (!(lvm->map = dm_pool_zalloc(mem, sizeof(*lvm->map)
|
||||
* ll->lv->le_count))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
* ll->lv->le_count)))
|
||||
goto_bad;
|
||||
|
||||
if (!dm_hash_insert(maps, ll->lv->name, lvm)) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!dm_hash_insert(maps, ll->lv->name, lvm))
|
||||
goto_bad;
|
||||
}
|
||||
|
||||
return maps;
|
||||
@@ -203,6 +197,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 +222,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 +231,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 +243,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 +252,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 +264,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 +277,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 +309,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;
|
||||
|
||||
@@ -160,7 +160,7 @@ static int _out_with_comment_file(struct formatter *f, const char *comment,
|
||||
for (i = 0; i < f->indent; i++)
|
||||
white_space[i] = '\t';
|
||||
white_space[i] = '\0';
|
||||
fprintf(f->data.fp, white_space);
|
||||
fputs(white_space, f->data.fp);
|
||||
i = vfprintf(f->data.fp, fmt, ap);
|
||||
|
||||
if (comment) {
|
||||
@@ -176,7 +176,7 @@ static int _out_with_comment_file(struct formatter *f, const char *comment,
|
||||
|
||||
while (++i < COMMENT_TAB);
|
||||
|
||||
fprintf(f->data.fp, comment);
|
||||
fputs(comment, f->data.fp);
|
||||
}
|
||||
fputc('\n', f->data.fp);
|
||||
|
||||
|
||||
@@ -39,6 +39,9 @@
|
||||
#define FMT_TEXT_NAME "lvm2"
|
||||
#define FMT_TEXT_ALIAS "text"
|
||||
|
||||
static struct mda_header *_raw_read_mda_header(const struct format_type *fmt,
|
||||
struct device_area *dev_area);
|
||||
|
||||
static struct format_instance *_text_create_text_instance(const struct format_type
|
||||
*fmt, const char *vgname,
|
||||
const char *vgid,
|
||||
@@ -80,6 +83,164 @@ static int _text_vg_setup(struct format_instance *fid __attribute((unused)),
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if metadata area belongs to vg
|
||||
*/
|
||||
static int _mda_in_vg_raw(struct format_instance *fid __attribute((unused)),
|
||||
struct volume_group *vg, struct metadata_area *mda)
|
||||
{
|
||||
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
|
||||
struct pv_list *pvl;
|
||||
|
||||
list_iterate_items(pvl, &vg->pvs)
|
||||
if (pvl->pv->dev == mdac->area.dev)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* For circular region between region_start and region_start + region_size,
|
||||
* back up one SECTOR_SIZE from 'region_ptr' and return the value.
|
||||
* This allows reverse traversal through text metadata area to find old
|
||||
* metadata.
|
||||
*
|
||||
* Parameters:
|
||||
* region_start: start of the region (bytes)
|
||||
* region_size: size of the region (bytes)
|
||||
* region_ptr: pointer within the region (bytes)
|
||||
* NOTE: region_start <= region_ptr <= region_start + region_size
|
||||
*/
|
||||
static uint64_t _get_prev_sector_circular(uint64_t region_start,
|
||||
uint64_t region_size,
|
||||
uint64_t region_ptr)
|
||||
{
|
||||
if (region_ptr >= region_start + SECTOR_SIZE)
|
||||
return region_ptr - SECTOR_SIZE;
|
||||
else
|
||||
return (region_start + region_size - SECTOR_SIZE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Analyze a metadata area for old metadata records in the circular buffer.
|
||||
* This function just looks through and makes a first pass at the data in
|
||||
* the sectors for particular things.
|
||||
* FIXME: do something with each metadata area (try to extract vg, write
|
||||
* raw data to file, etc)
|
||||
*/
|
||||
static int _pv_analyze_mda_raw (const struct format_type * fmt,
|
||||
struct metadata_area *mda)
|
||||
{
|
||||
struct mda_header *mdah;
|
||||
struct raw_locn *rlocn;
|
||||
uint64_t area_start;
|
||||
uint64_t area_size;
|
||||
uint64_t prev_sector;
|
||||
uint64_t latest_mrec_offset;
|
||||
int i;
|
||||
uint64_t offset;
|
||||
uint64_t offset2;
|
||||
uint64_t size;
|
||||
uint64_t size2;
|
||||
char *buf=NULL;
|
||||
struct device_area *area;
|
||||
struct mda_context *mdac;
|
||||
int r=0;
|
||||
|
||||
mdac = (struct mda_context *) mda->metadata_locn;
|
||||
|
||||
log_print("Found text metadata area, offset=%"PRIu64", size=%"PRIu64,
|
||||
mdac->area.start,
|
||||
mdac->area.size);
|
||||
area = &mdac->area;
|
||||
|
||||
if (!dev_open(area->dev))
|
||||
return_0;
|
||||
|
||||
if (!(mdah = _raw_read_mda_header(fmt, area)))
|
||||
goto_out;
|
||||
|
||||
rlocn = mdah->raw_locns;
|
||||
|
||||
/*
|
||||
* The device area includes the metadata header as well as the
|
||||
* records, so remove the metadata header from the start and size
|
||||
*/
|
||||
area_start = area->start + MDA_HEADER_SIZE;
|
||||
area_size = area->size - MDA_HEADER_SIZE;
|
||||
latest_mrec_offset = rlocn->offset + area->start;
|
||||
|
||||
/*
|
||||
* Start searching at rlocn (point of live metadata) and go
|
||||
* backwards.
|
||||
*/
|
||||
prev_sector = _get_prev_sector_circular(area_start, area_size,
|
||||
latest_mrec_offset);
|
||||
offset = prev_sector;
|
||||
size = SECTOR_SIZE;
|
||||
offset2 = size2 = 0;
|
||||
i = 0;
|
||||
while (prev_sector != latest_mrec_offset) {
|
||||
prev_sector = _get_prev_sector_circular(area_start, area_size,
|
||||
prev_sector);
|
||||
/*
|
||||
* FIXME: for some reason, the whole metadata region from
|
||||
* area->start to area->start+area->size is not used.
|
||||
* Only ~32KB seems to contain valid metadata records
|
||||
* (LVM2 format - format_text). As a result, I end up with
|
||||
* "maybe_config_section" returning true when there's no valid
|
||||
* metadata in a sector (sectors with all nulls).
|
||||
*/
|
||||
if (!(buf = dm_pool_alloc(fmt->cmd->mem, size + size2)))
|
||||
goto_out;
|
||||
|
||||
if (!dev_read_circular(area->dev, offset, size,
|
||||
offset2, size2, buf))
|
||||
goto_out;
|
||||
|
||||
/*
|
||||
* FIXME: We could add more sophisticated metadata detection
|
||||
*/
|
||||
if (maybe_config_section(buf, size+size2)) {
|
||||
/* FIXME: Validate region, pull out timestamp?, etc */
|
||||
/* FIXME: Do something with this region */
|
||||
log_verbose ("Found LVM2 metadata record at "
|
||||
"offset=%"PRIu64", size=%"PRIu64", "
|
||||
"offset2=%"PRIu64" size2=%"PRIu64,
|
||||
offset, size, offset2, size2);
|
||||
offset = prev_sector;
|
||||
size = SECTOR_SIZE;
|
||||
offset2 = size2 = 0;
|
||||
} else {
|
||||
/*
|
||||
* Not a complete metadata record, assume we have
|
||||
* metadata and just increase the size and offset.
|
||||
* Start the second region if the previous sector is
|
||||
* wrapping around towards the end of the disk.
|
||||
*/
|
||||
if (prev_sector > offset) {
|
||||
offset2 = prev_sector;
|
||||
size2 += SECTOR_SIZE;
|
||||
} else {
|
||||
offset = prev_sector;
|
||||
size += SECTOR_SIZE;
|
||||
}
|
||||
}
|
||||
dm_pool_free(fmt->cmd->mem, buf);
|
||||
buf = NULL;
|
||||
}
|
||||
|
||||
r = 1;
|
||||
out:
|
||||
if (buf)
|
||||
dm_pool_free(fmt->cmd->mem, buf);
|
||||
if (!dev_close(area->dev))
|
||||
stack;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int _text_lv_setup(struct format_instance *fid __attribute((unused)),
|
||||
struct logical_volume *lv)
|
||||
{
|
||||
@@ -1271,7 +1432,7 @@ static int _text_pv_read(const struct format_type *fmt, const char *pv_name,
|
||||
}
|
||||
|
||||
/* FIXME Optimise out repeated reading when cache lock held */
|
||||
if (!(label_read(dev, &label))) {
|
||||
if (!(label_read(dev, &label, UINT64_C(0)))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -1395,7 +1556,9 @@ static struct metadata_area_ops _metadata_text_raw_ops = {
|
||||
.vg_remove = _vg_remove_raw,
|
||||
.vg_precommit = _vg_precommit_raw,
|
||||
.vg_commit = _vg_commit_raw,
|
||||
.vg_revert = _vg_revert_raw
|
||||
.vg_revert = _vg_revert_raw,
|
||||
.mda_in_vg = _mda_in_vg_raw,
|
||||
.pv_analyze_mda = _pv_analyze_mda_raw,
|
||||
};
|
||||
|
||||
/* pvmetadatasize in sectors */
|
||||
|
||||
@@ -660,15 +660,11 @@ static struct volume_group *_read_vg(struct format_instance *fid,
|
||||
/* eg Set to instance of fmt1 here if reading a format1 backup? */
|
||||
vg->fid = fid;
|
||||
|
||||
if (!(vg->name = dm_pool_strdup(mem, vgn->key))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(vg->name = dm_pool_strdup(mem, vgn->key)))
|
||||
goto_bad;
|
||||
|
||||
if (!(vg->system_id = dm_pool_zalloc(mem, NAME_LEN))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(vg->system_id = dm_pool_zalloc(mem, NAME_LEN)))
|
||||
goto_bad;
|
||||
|
||||
vgn = vgn->child;
|
||||
|
||||
|
||||
@@ -107,7 +107,8 @@ struct labeller *label_get_handler(const char *name)
|
||||
}
|
||||
|
||||
static struct labeller *_find_labeller(struct device *dev, char *buf,
|
||||
uint64_t *label_sector)
|
||||
uint64_t *label_sector,
|
||||
uint64_t scan_sector)
|
||||
{
|
||||
struct labeller_i *li;
|
||||
struct labeller *r = NULL;
|
||||
@@ -117,12 +118,13 @@ static struct labeller *_find_labeller(struct device *dev, char *buf,
|
||||
int found = 0;
|
||||
char readbuf[LABEL_SCAN_SIZE] __attribute((aligned(8)));
|
||||
|
||||
if (!dev_read(dev, UINT64_C(0), LABEL_SCAN_SIZE, readbuf)) {
|
||||
if (!dev_read(dev, scan_sector << SECTOR_SHIFT,
|
||||
LABEL_SCAN_SIZE, readbuf)) {
|
||||
log_debug("%s: Failed to read label area", dev_name(dev));
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Scan first few sectors for a valid label */
|
||||
/* Scan a few sectors for a valid label */
|
||||
for (sector = 0; sector < LABEL_SCAN_SECTORS;
|
||||
sector += LABEL_SIZE >> SECTOR_SHIFT) {
|
||||
lh = (struct label_header *) (readbuf +
|
||||
@@ -132,13 +134,14 @@ static struct labeller *_find_labeller(struct device *dev, char *buf,
|
||||
if (found) {
|
||||
log_error("Ignoring additional label on %s at "
|
||||
"sector %" PRIu64, dev_name(dev),
|
||||
sector);
|
||||
sector + scan_sector);
|
||||
}
|
||||
if (xlate64(lh->sector_xl) != sector) {
|
||||
if (xlate64(lh->sector_xl) != sector + scan_sector) {
|
||||
log_info("%s: Label for sector %" PRIu64
|
||||
" found at sector %" PRIu64
|
||||
" - ignoring", dev_name(dev),
|
||||
xlate64(lh->sector_xl), sector);
|
||||
xlate64(lh->sector_xl),
|
||||
sector + scan_sector);
|
||||
continue;
|
||||
}
|
||||
if (calc_crc(INITIAL_CRC, &lh->offset_xl, LABEL_SIZE -
|
||||
@@ -153,19 +156,21 @@ static struct labeller *_find_labeller(struct device *dev, char *buf,
|
||||
}
|
||||
|
||||
list_iterate_items(li, &_labellers) {
|
||||
if (li->l->ops->can_handle(li->l, (char *) lh, sector)) {
|
||||
if (li->l->ops->can_handle(li->l, (char *) lh,
|
||||
sector + scan_sector)) {
|
||||
log_very_verbose("%s: %s label detected",
|
||||
dev_name(dev), li->name);
|
||||
if (found) {
|
||||
log_error("Ignoring additional label "
|
||||
"on %s at sector %" PRIu64,
|
||||
dev_name(dev), sector);
|
||||
dev_name(dev),
|
||||
sector + scan_sector);
|
||||
continue;
|
||||
}
|
||||
r = li->l;
|
||||
memcpy(buf, lh, LABEL_SIZE);
|
||||
if (label_sector)
|
||||
*label_sector = sector;
|
||||
*label_sector = sector + scan_sector;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
@@ -256,7 +261,8 @@ int label_remove(struct device *dev)
|
||||
}
|
||||
|
||||
/* FIXME Avoid repeated re-reading if cache lock held */
|
||||
int label_read(struct device *dev, struct label **result)
|
||||
int label_read(struct device *dev, struct label **result,
|
||||
uint64_t scan_sector)
|
||||
{
|
||||
char buf[LABEL_SIZE] __attribute((aligned(8)));
|
||||
struct labeller *l;
|
||||
@@ -274,7 +280,7 @@ int label_read(struct device *dev, struct label **result)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (!(l = _find_labeller(dev, buf, §or)))
|
||||
if (!(l = _find_labeller(dev, buf, §or, scan_sector)))
|
||||
goto_out;
|
||||
|
||||
if ((r = (l->ops->read)(l, dev, buf, result)) && result && *result)
|
||||
@@ -354,7 +360,7 @@ int label_verify(struct device *dev)
|
||||
return_0;
|
||||
}
|
||||
|
||||
if (!(l = _find_labeller(dev, buf, §or)))
|
||||
if (!(l = _find_labeller(dev, buf, §or, UINT64_C(0))))
|
||||
goto_out;
|
||||
|
||||
r = l->ops->verify ? l->ops->verify(l, buf, sector) : 1;
|
||||
|
||||
@@ -96,7 +96,8 @@ int label_register_handler(const char *name, struct labeller *handler);
|
||||
struct labeller *label_get_handler(const char *name);
|
||||
|
||||
int label_remove(struct device *dev);
|
||||
int label_read(struct device *dev, struct label **result);
|
||||
int label_read(struct device *dev, struct label **result,
|
||||
uint64_t scan_sector);
|
||||
int label_write(struct device *dev, struct label *label);
|
||||
int label_verify(struct device *dev);
|
||||
struct label *label_create(struct labeller *labeller);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -138,5 +138,6 @@ void print_log(int level, const char *file, int line, const char *format, ...)
|
||||
#define return_0 do { stack; return 0; } while (0)
|
||||
#define return_NULL do { stack; return NULL; } while (0)
|
||||
#define goto_out do { stack; goto out; } while (0)
|
||||
#define goto_bad do { stack; goto bad; } while (0)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -280,10 +280,9 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name,
|
||||
vg->seqno = 0;
|
||||
|
||||
vg->status = (RESIZEABLE_VG | LVM_READ | LVM_WRITE);
|
||||
if (!(vg->system_id = dm_pool_alloc(mem, NAME_LEN))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(vg->system_id = dm_pool_alloc(mem, NAME_LEN)))
|
||||
goto_bad;
|
||||
|
||||
*vg->system_id = '\0';
|
||||
|
||||
vg->extent_size = extent_size;
|
||||
@@ -320,7 +319,7 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name,
|
||||
|
||||
/* attach the pv's */
|
||||
if (!vg_extend(vg->fid, vg, pv_count, pv_names))
|
||||
goto bad;
|
||||
goto_bad;
|
||||
|
||||
return vg;
|
||||
|
||||
@@ -505,6 +504,34 @@ int vg_change_pesize(struct cmd_context *cmd, struct volume_group *vg,
|
||||
return 1;
|
||||
}
|
||||
|
||||
int vg_split_mdas(struct cmd_context *cmd, struct volume_group *vg_from,
|
||||
struct volume_group *vg_to)
|
||||
{
|
||||
struct metadata_area *mda, *mda2;
|
||||
struct list *mdas_from, *mdas_to;
|
||||
int common_mda = 0;
|
||||
|
||||
mdas_from = &vg_from->fid->metadata_areas;
|
||||
mdas_to = &vg_to->fid->metadata_areas;
|
||||
|
||||
list_iterate_items_safe(mda, mda2, mdas_from) {
|
||||
if (!mda->ops->mda_in_vg) {
|
||||
common_mda = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!mda->ops->mda_in_vg(vg_from->fid, vg_from, mda)) {
|
||||
list_del(&mda->list);
|
||||
list_add(mdas_to, &mda->list);
|
||||
}
|
||||
}
|
||||
|
||||
if (list_empty(mdas_from) || list_empty(mdas_to))
|
||||
return common_mda;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Sizes in sectors */
|
||||
struct physical_volume *pv_create(const struct format_type *fmt,
|
||||
struct device *dev,
|
||||
@@ -533,10 +560,8 @@ struct physical_volume *pv_create(const struct format_type *fmt,
|
||||
|
||||
pv->dev = dev;
|
||||
|
||||
if (!(pv->vg_name = dm_pool_zalloc(mem, NAME_LEN))) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!(pv->vg_name = dm_pool_zalloc(mem, NAME_LEN)))
|
||||
goto_bad;
|
||||
|
||||
pv->status = ALLOCATABLE_PV;
|
||||
|
||||
@@ -759,6 +784,12 @@ int vg_validate(struct volume_group *vg)
|
||||
r = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp(pvl->pv->vg_name, vg->name)) {
|
||||
log_error("Internal error: VG name for PV %s is corrupted",
|
||||
dev_name(pvl->pv->dev));
|
||||
r = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!check_pv_segments(vg)) {
|
||||
@@ -963,6 +994,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 +1037,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 +1127,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 +1164,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 +1215,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()) {
|
||||
@@ -1303,7 +1400,7 @@ struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(label_read(dev, &label))) {
|
||||
if (!(label_read(dev, &label, UINT64_C(0)))) {
|
||||
if (warnings)
|
||||
log_error("No physical volume label read from %s",
|
||||
pv_name);
|
||||
@@ -1433,3 +1530,66 @@ 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;
|
||||
}
|
||||
/*
|
||||
* Returns:
|
||||
* 0 - fail
|
||||
* 1 - success
|
||||
*/
|
||||
int pv_analyze(struct cmd_context *cmd, const char *pv_name,
|
||||
int64_t label_sector)
|
||||
{
|
||||
struct label *label;
|
||||
struct device *dev;
|
||||
struct metadata_area *mda;
|
||||
struct lvmcache_info *info;
|
||||
|
||||
dev = dev_cache_get(pv_name, cmd->filter);
|
||||
if (!dev) {
|
||||
log_error("Device %s not found (or ignored by filtering).",
|
||||
pv_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* First, scan for LVM labels.
|
||||
*/
|
||||
if (!label_read(dev, &label, label_sector)) {
|
||||
log_error("Could not find LVM label on %s",
|
||||
pv_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_print("Found label on %s, sector %"PRIu64", type=%s",
|
||||
pv_name, label->sector, label->type);
|
||||
|
||||
/*
|
||||
* Next, loop through metadata areas
|
||||
*/
|
||||
info = label->info;
|
||||
list_iterate_items(mda, &info->mdas)
|
||||
mda->ops->pv_analyze_mda(info->fmt, mda);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -178,6 +178,17 @@ struct metadata_area_ops {
|
||||
struct volume_group * vg, struct metadata_area * mda);
|
||||
int (*vg_remove) (struct format_instance * fi, struct volume_group * vg,
|
||||
struct metadata_area * mda);
|
||||
/*
|
||||
* Check if metadata area belongs to vg
|
||||
*/
|
||||
int (*mda_in_vg) (struct format_instance * fi,
|
||||
struct volume_group * vg, struct metadata_area *mda);
|
||||
/*
|
||||
* Analyze a metadata area on a PV.
|
||||
*/
|
||||
int (*pv_analyze_mda) (const struct format_type * fmt,
|
||||
struct metadata_area *mda);
|
||||
|
||||
};
|
||||
|
||||
struct metadata_area {
|
||||
@@ -423,6 +434,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 */
|
||||
@@ -437,6 +449,8 @@ struct physical_volume *pv_create(const struct format_type *fmt,
|
||||
uint64_t pvmetadatasize, struct list *mdas);
|
||||
int pv_resize(struct physical_volume *pv, struct volume_group *vg,
|
||||
uint32_t new_pe_count);
|
||||
int pv_analyze(struct cmd_context *cmd, const char *pv_name,
|
||||
int64_t label_sector);
|
||||
|
||||
struct volume_group *vg_create(struct cmd_context *cmd, const char *name,
|
||||
uint32_t extent_size, uint32_t max_pv,
|
||||
@@ -449,6 +463,8 @@ int vg_extend(struct format_instance *fi, struct volume_group *vg,
|
||||
int pv_count, char **pv_names);
|
||||
int vg_change_pesize(struct cmd_context *cmd, struct volume_group *vg,
|
||||
uint32_t new_extent_size);
|
||||
int vg_split_mdas(struct cmd_context *cmd, struct volume_group *vg_from,
|
||||
struct volume_group *vg_to);
|
||||
|
||||
/* Manipulate LVs */
|
||||
struct logical_volume *lv_create_empty(struct format_instance *fi,
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "activate.h"
|
||||
#include "lv_alloc.h"
|
||||
#include "lvm-string.h"
|
||||
#include "str_list.h"
|
||||
#include "locking.h" /* FIXME Should not be used in this file */
|
||||
|
||||
#include "defaults.h" /* FIXME: should this be defaults.h? */
|
||||
@@ -77,6 +78,42 @@ static void _move_lv_segments(struct logical_volume *lv_to, struct logical_volum
|
||||
lv_from->size = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Delete independent/orphan LV, it must acquire lock.
|
||||
*/
|
||||
static int _delete_lv(struct lv_segment *mirrored_seg, struct logical_volume *lv)
|
||||
{
|
||||
struct cmd_context *cmd = mirrored_seg->lv->vg->cmd;
|
||||
struct str_list *sl;
|
||||
|
||||
/* Inherit tags - maybe needed for activation */
|
||||
if (!str_list_match_list(&mirrored_seg->lv->tags, &lv->tags)) {
|
||||
list_iterate_items(sl, &mirrored_seg->lv->tags)
|
||||
if (!str_list_add(cmd->mem, &lv->tags, sl->str)) {
|
||||
log_error("Aborting. Unable to tag.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!vg_write(mirrored_seg->lv->vg) ||
|
||||
!vg_commit(mirrored_seg->lv->vg)) {
|
||||
log_error("Intermediate VG commit for orphan volume failed.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!activate_lv(cmd, lv))
|
||||
return_0;
|
||||
|
||||
if (!deactivate_lv(cmd, lv))
|
||||
return_0;
|
||||
|
||||
if (!lv_remove(lv))
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reduce mirrored_seg to num_mirrors images.
|
||||
*/
|
||||
@@ -205,57 +242,15 @@ int remove_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors,
|
||||
}
|
||||
|
||||
/* Delete the 'orphan' LVs */
|
||||
for (m = num_mirrors; m < old_area_count; m++) {
|
||||
/* LV is now independent of the mirror so must acquire lock. */
|
||||
if (!activate_lv(mirrored_seg->lv->vg->cmd, seg_lv(mirrored_seg, m))) {
|
||||
stack;
|
||||
for (m = num_mirrors; m < old_area_count; m++)
|
||||
if (!_delete_lv(mirrored_seg, seg_lv(mirrored_seg, m)))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!deactivate_lv(mirrored_seg->lv->vg->cmd, seg_lv(mirrored_seg, m))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
if (lv1 && !_delete_lv(mirrored_seg, lv1))
|
||||
return 0;
|
||||
|
||||
if (!lv_remove(seg_lv(mirrored_seg, m))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (lv1) {
|
||||
if (!activate_lv(mirrored_seg->lv->vg->cmd, lv1)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!deactivate_lv(mirrored_seg->lv->vg->cmd, lv1)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lv_remove(lv1)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (log_lv) {
|
||||
if (!activate_lv(mirrored_seg->lv->vg->cmd, log_lv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!deactivate_lv(mirrored_seg->lv->vg->cmd, log_lv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lv_remove(log_lv)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (log_lv && !_delete_lv(mirrored_seg, log_lv))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#ifndef _LVM_LIB_H
|
||||
#define _LVM_LIB_H
|
||||
|
||||
#include <configure.h>
|
||||
#include "configure.h"
|
||||
|
||||
#define _REENTRANT
|
||||
#define _GNU_SOURCE
|
||||
|
||||
@@ -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,21 @@ 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)) {
|
||||
dm_free(dir);
|
||||
return -1;
|
||||
}
|
||||
|
||||
dm_free(dir);
|
||||
|
||||
log_very_verbose("Locking %s (%s, %hd)", file,
|
||||
(lock_type == F_WRLCK) ? "F_WRLCK" : "F_RDLCK",
|
||||
lock_type);
|
||||
|
||||
@@ -36,18 +36,38 @@ int emit_to_buffer(char **buffer, size_t *size, const char *fmt, ...)
|
||||
}
|
||||
|
||||
/*
|
||||
* Device layer names are all of the form <vg>-<lv>-<layer>, any
|
||||
* other hyphens that appear in these names are quoted with yet
|
||||
* another hyphen. The top layer of any device has no layer
|
||||
* name. eg, vg0-lvol0.
|
||||
* Count occurences of 'c' in 'str' until we reach a null char.
|
||||
*
|
||||
* Returns:
|
||||
* len - incremented for each char we encounter, whether 'c' or not.
|
||||
* count - number of occurences of 'c'
|
||||
*/
|
||||
static void _count_hyphens(const char *str, size_t *len, int *hyphens)
|
||||
void count_chars(const char *str, size_t *len, int *count,
|
||||
const char c)
|
||||
{
|
||||
const char *ptr;
|
||||
|
||||
for (ptr = str; *ptr; ptr++, (*len)++)
|
||||
if (*ptr == '-')
|
||||
(*hyphens)++;
|
||||
if (*ptr == c)
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Count occurences of 'c' in 'str' of length 'size'.
|
||||
*
|
||||
* Returns:
|
||||
* # of occurences of 'c'
|
||||
*/
|
||||
unsigned count_chars_len(const char *str, size_t size, const char c)
|
||||
{
|
||||
int i;
|
||||
unsigned count=0;
|
||||
|
||||
for (i=0; i < size; i++)
|
||||
if (str[i] == c)
|
||||
count++;
|
||||
return count;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -73,11 +93,11 @@ char *build_dm_name(struct dm_pool *mem, const char *vgname,
|
||||
int hyphens = 1;
|
||||
char *r, *out;
|
||||
|
||||
_count_hyphens(vgname, &len, &hyphens);
|
||||
_count_hyphens(lvname, &len, &hyphens);
|
||||
count_chars(vgname, &len, &hyphens, '-');
|
||||
count_chars(lvname, &len, &hyphens, '-');
|
||||
|
||||
if (layer && *layer) {
|
||||
_count_hyphens(layer, &len, &hyphens);
|
||||
count_chars(layer, &len, &hyphens, '-');
|
||||
hyphens++;
|
||||
}
|
||||
|
||||
@@ -105,6 +125,12 @@ char *build_dm_name(struct dm_pool *mem, const char *vgname,
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Device layer names are all of the form <vg>-<lv>-<layer>, any
|
||||
* other hyphens that appear in these names are quoted with yet
|
||||
* another hyphen. The top layer of any device has no layer
|
||||
* name. eg, vg0-lvol0.
|
||||
*/
|
||||
int validate_name(const char *n)
|
||||
{
|
||||
register char c;
|
||||
|
||||
@@ -30,4 +30,8 @@ char *build_dm_name(struct dm_pool *mem, const char *vg,
|
||||
|
||||
int validate_name(const char *n);
|
||||
|
||||
void count_chars(const char *str, size_t *len, int *count,
|
||||
char c);
|
||||
unsigned count_chars_len(const char *str, size_t size, char c);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU General Public License v.2.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _LVM_MATCHER_H
|
||||
#define _LVM_MATCHER_H
|
||||
|
||||
struct matcher;
|
||||
struct matcher *matcher_create(struct dm_pool *mem, const char **patterns,
|
||||
unsigned num);
|
||||
|
||||
int matcher_run(struct matcher *m, const char *begin);
|
||||
|
||||
#endif
|
||||
@@ -49,7 +49,7 @@ static char _alloc_policy_char(alloc_policy_t alloc)
|
||||
case ALLOC_CONTIGUOUS:
|
||||
return 'c';
|
||||
case ALLOC_CLING:
|
||||
return 'C';
|
||||
return 'l';
|
||||
case ALLOC_NORMAL:
|
||||
return 'n';
|
||||
case ALLOC_ANYWHERE:
|
||||
@@ -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
|
||||
|
||||
@@ -127,3 +127,5 @@ dm_report_field_int32
|
||||
dm_report_field_uint32
|
||||
dm_report_field_uint64
|
||||
dm_report_field_set_value
|
||||
dm_regex_create
|
||||
dm_regex_match
|
||||
|
||||
@@ -27,6 +27,9 @@ SOURCES =\
|
||||
libdm-report.c \
|
||||
mm/dbg_malloc.c \
|
||||
mm/pool.c \
|
||||
regex/matcher.c \
|
||||
regex/parse_rx.c \
|
||||
regex/ttree.c \
|
||||
$(interface)/libdm-iface.c
|
||||
|
||||
INCLUDES = -I$(interface)
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _LVM_BITSET_H
|
||||
#define _LVM_BITSET_H
|
||||
#ifndef _DM_BITSET_H
|
||||
#define _DM_BITSET_H
|
||||
|
||||
#include "pool.h"
|
||||
|
||||
|
||||
@@ -68,14 +68,14 @@ static struct dm_hash_node *_create_node(const char *str, unsigned len)
|
||||
return n;
|
||||
}
|
||||
|
||||
static unsigned long _hash(const unsigned char *str, unsigned len)
|
||||
static unsigned long _hash(const char *str, unsigned len)
|
||||
{
|
||||
unsigned long h = 0, g;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
h <<= 4;
|
||||
h += _nums[*str++];
|
||||
h += _nums[(unsigned char) *str++];
|
||||
g = h & ((unsigned long) 0xf << 16u);
|
||||
if (g) {
|
||||
h ^= g >> 16u;
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _LVM_HASH_H
|
||||
#define _LVM_HASH_H
|
||||
#ifndef _DM_HASH_H
|
||||
#define _DM_HASH_H
|
||||
|
||||
struct hash_table;
|
||||
struct hash_node;
|
||||
|
||||
@@ -433,12 +433,12 @@ static int _dm_task_get_info_v1(struct dm_task *dmt, struct dm_info *info)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const char *_dm_task_get_name_v1(struct dm_task *dmt)
|
||||
static const char *_dm_task_get_name_v1(const struct dm_task *dmt)
|
||||
{
|
||||
return (dmt->dmi.v1->name);
|
||||
}
|
||||
|
||||
static const char *_dm_task_get_uuid_v1(struct dm_task *dmt)
|
||||
static const char *_dm_task_get_uuid_v1(const struct dm_task *dmt)
|
||||
{
|
||||
return (dmt->dmi.v1->uuid);
|
||||
}
|
||||
@@ -924,7 +924,7 @@ int dm_task_get_info(struct dm_task *dmt, struct dm_info *info)
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *dm_task_get_name(struct dm_task *dmt)
|
||||
const char *dm_task_get_name(const struct dm_task *dmt)
|
||||
{
|
||||
#ifdef DM_COMPAT
|
||||
if (_dm_version == 1)
|
||||
@@ -934,7 +934,7 @@ const char *dm_task_get_name(struct dm_task *dmt)
|
||||
return (dmt->dmi.v4->name);
|
||||
}
|
||||
|
||||
const char *dm_task_get_uuid(struct dm_task *dmt)
|
||||
const char *dm_task_get_uuid(const struct dm_task *dmt)
|
||||
{
|
||||
#ifdef DM_COMPAT
|
||||
if (_dm_version == 1)
|
||||
@@ -1555,7 +1555,7 @@ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
|
||||
dmi->flags |= DM_SKIP_BDGET_FLAG;
|
||||
|
||||
log_debug("dm %s %s %s%s%s %s%.0d%s%.0d%s"
|
||||
"%s%c%c%s %.0llu %s [%u]",
|
||||
"%s%c%c%s %.0" PRIu64 " %s [%u]",
|
||||
_cmd_data_v4[dmt->type].name,
|
||||
dmi->name, dmi->uuid, dmt->newname ? " " : "",
|
||||
dmt->newname ? dmt->newname : "",
|
||||
|
||||
@@ -133,8 +133,8 @@ struct dm_versions {
|
||||
int dm_get_library_version(char *version, size_t size);
|
||||
int dm_task_get_driver_version(struct dm_task *dmt, char *version, size_t size);
|
||||
int dm_task_get_info(struct dm_task *dmt, struct dm_info *dmi);
|
||||
const char *dm_task_get_name(struct dm_task *dmt);
|
||||
const char *dm_task_get_uuid(struct dm_task *dmt);
|
||||
const char *dm_task_get_name(const struct dm_task *dmt);
|
||||
const char *dm_task_get_uuid(const struct dm_task *dmt);
|
||||
|
||||
struct dm_deps *dm_task_get_deps(struct dm_task *dmt);
|
||||
struct dm_names *dm_task_get_names(struct dm_task *dmt);
|
||||
@@ -630,6 +630,25 @@ char *dm_basename(const char *path);
|
||||
*/
|
||||
int dm_asprintf(char **buf, const char *format, ...);
|
||||
|
||||
/*********************
|
||||
* regular expressions
|
||||
*********************/
|
||||
struct dm_regex;
|
||||
|
||||
/*
|
||||
* Initialise an array of num patterns for matching.
|
||||
* Uses memory from mem.
|
||||
*/
|
||||
struct dm_regex *dm_regex_create(struct dm_pool *mem, const char **patterns,
|
||||
unsigned num_patterns);
|
||||
|
||||
/*
|
||||
* Match string s against the patterns.
|
||||
* Returns the index of the highest pattern in the array that matches,
|
||||
* or -1 if none match.
|
||||
*/
|
||||
int dm_regex_match(struct dm_regex *regex, const char *s);
|
||||
|
||||
/*********************
|
||||
* reporting functions
|
||||
*********************/
|
||||
@@ -657,11 +676,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);
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
@@ -296,35 +296,74 @@ static int _copy_field(struct dm_report *rh, struct field_properties *dest,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct field_properties * _add_field(struct dm_report *rh,
|
||||
uint32_t field_num, uint32_t flags)
|
||||
{
|
||||
struct field_properties *fp;
|
||||
|
||||
rh->report_types |= rh->fields[field_num].type;
|
||||
|
||||
if (!(fp = dm_pool_zalloc(rh->mem, sizeof(struct field_properties)))) {
|
||||
log_error("dm_report: struct field_properties allocation "
|
||||
"failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!_copy_field(rh, fp, field_num)) {
|
||||
stack;
|
||||
dm_pool_free(rh->mem, fp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fp->flags |= flags;
|
||||
|
||||
/*
|
||||
* Place hidden fields at the front so list_end() will
|
||||
* tell us when we've reached the last visible field.
|
||||
*/
|
||||
if (fp->flags & FLD_HIDDEN)
|
||||
list_add_h(&rh->field_props, &fp->list);
|
||||
else
|
||||
list_add(&rh->field_props, &fp->list);
|
||||
|
||||
return fp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare name1 against name2 or prefix plus name2
|
||||
* name2 is not necessarily null-terminated.
|
||||
* len2 is the length of name2.
|
||||
*/
|
||||
static int _is_same_field(const char *name1, const char *name2,
|
||||
size_t len2, const char *prefix)
|
||||
{
|
||||
size_t prefix_len;
|
||||
|
||||
/* Exact match? */
|
||||
if (!strncasecmp(name1, name2, len2) && strlen(name1) == len2)
|
||||
return 1;
|
||||
|
||||
/* Match including prefix? */
|
||||
prefix_len = strlen(prefix);
|
||||
if (!strncasecmp(prefix, name1, prefix_len) &&
|
||||
!strncasecmp(name1 + prefix_len, name2, len2) &&
|
||||
strlen(name1) == prefix_len + len2)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _field_match(struct dm_report *rh, const char *field, size_t flen)
|
||||
{
|
||||
uint32_t f, l;
|
||||
struct field_properties *fp;
|
||||
uint32_t f;
|
||||
|
||||
if (!flen)
|
||||
return 0;
|
||||
|
||||
for (f = 0; rh->fields[f].report_fn; f++) {
|
||||
if ((!strncasecmp(rh->fields[f].id, field, flen) &&
|
||||
strlen(rh->fields[f].id) == flen) ||
|
||||
(l = strlen(rh->field_prefix),
|
||||
!strncasecmp(rh->field_prefix, rh->fields[f].id, l) &&
|
||||
!strncasecmp(rh->fields[f].id + l, field, flen) &&
|
||||
strlen(rh->fields[f].id) == l + flen)) {
|
||||
rh->report_types |= rh->fields[f].type;
|
||||
if (!(fp = dm_pool_zalloc(rh->mem, sizeof(*fp)))) {
|
||||
log_error("dm_report: "
|
||||
"struct field_properties allocation "
|
||||
"failed");
|
||||
return 0;
|
||||
}
|
||||
if (!_copy_field(rh, fp, f))
|
||||
return 0;
|
||||
|
||||
list_add(&rh->field_props, &fp->list);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
for (f = 0; rh->fields[f].report_fn; f++)
|
||||
if (_is_same_field(rh->fields[f].id, field, flen,
|
||||
rh->field_prefix))
|
||||
return _add_field(rh, f, 0) ? 1 : 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -341,21 +380,8 @@ static int _add_sort_key(struct dm_report *rh, uint32_t field_num,
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
rh->report_types |= rh->fields[field_num].type;
|
||||
if (!(found = dm_pool_zalloc(rh->mem, sizeof(*found)))) {
|
||||
log_error("dm_report: "
|
||||
"struct field_properties allocation failed");
|
||||
return 0;
|
||||
}
|
||||
if (!_copy_field(rh, found, field_num))
|
||||
return 0;
|
||||
|
||||
/* Add as a non-display field */
|
||||
found->flags |= FLD_HIDDEN;
|
||||
|
||||
list_add(&rh->field_props, &found->list);
|
||||
}
|
||||
if (!found && !(found = _add_field(rh, field_num, FLD_HIDDEN)))
|
||||
return_0;
|
||||
|
||||
if (found->flags & FLD_SORT_KEY) {
|
||||
log_error("dm_report: Ignoring duplicate sort field: %s",
|
||||
@@ -372,7 +398,7 @@ static int _add_sort_key(struct dm_report *rh, uint32_t field_num,
|
||||
|
||||
static int _key_match(struct dm_report *rh, const char *key, size_t len)
|
||||
{
|
||||
uint32_t f, l;
|
||||
uint32_t f;
|
||||
uint32_t flags;
|
||||
|
||||
if (!len)
|
||||
@@ -394,16 +420,10 @@ static int _key_match(struct dm_report *rh, const char *key, size_t len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (f = 0; rh->fields[f].report_fn; f++) {
|
||||
if ((!strncasecmp(rh->fields[f].id, key, len) &&
|
||||
strlen(rh->fields[f].id) == len) ||
|
||||
(l = strlen(rh->field_prefix),
|
||||
!strncasecmp(rh->field_prefix, rh->fields[f].id, l) &&
|
||||
!strncasecmp(rh->fields[f].id + l, key, len) &&
|
||||
strlen(rh->fields[f].id) == l + len)) {
|
||||
for (f = 0; rh->fields[f].report_fn; f++)
|
||||
if (_is_same_field(rh->fields[f].id, key, len,
|
||||
rh->field_prefix))
|
||||
return _add_sort_key(rh, f, flags);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -504,15 +524,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 +775,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))
|
||||
|
||||
@@ -117,7 +117,7 @@ int dm_snprintf(char *buf, size_t bufsize, const char *format, ...)
|
||||
n = vsnprintf(buf, bufsize, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (n < 0 || (n > bufsize - 1))
|
||||
if (n < 0 || ((unsigned) n + 1 > bufsize))
|
||||
return -1;
|
||||
|
||||
return n;
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _LVM_DBG_MALLOC_H
|
||||
#define _LVM_DBG_MALLOC_H
|
||||
#ifndef _DM_DBG_MALLOC_H
|
||||
#define _DM_DBG_MALLOC_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _LVM_POOL_H
|
||||
#define _LVM_POOL_H
|
||||
#ifndef _DM_POOL_H
|
||||
#define _DM_POOL_H
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
* This file is part of the device-mapper userspace tools.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
@@ -14,9 +14,9 @@
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "matcher.h"
|
||||
#include "parse_rx.h"
|
||||
#include "ttree.h"
|
||||
#include "assert.h"
|
||||
|
||||
struct dfa_state {
|
||||
int final;
|
||||
@@ -29,7 +29,7 @@ struct state_queue {
|
||||
struct state_queue *next;
|
||||
};
|
||||
|
||||
struct matcher { /* Instance variables for the lexer */
|
||||
struct dm_regex { /* Instance variables for the lexer */
|
||||
struct dfa_state *start;
|
||||
unsigned num_nodes;
|
||||
int nodes_entered;
|
||||
@@ -52,7 +52,7 @@ static int _count_nodes(struct rx_node *rx)
|
||||
return r;
|
||||
}
|
||||
|
||||
static void _fill_table(struct matcher *m, struct rx_node *rx)
|
||||
static void _fill_table(struct dm_regex *m, struct rx_node *rx)
|
||||
{
|
||||
assert((rx->type != OR) || (rx->left && rx->right));
|
||||
|
||||
@@ -65,7 +65,7 @@ static void _fill_table(struct matcher *m, struct rx_node *rx)
|
||||
m->nodes[m->nodes_entered++] = rx;
|
||||
}
|
||||
|
||||
static void _create_bitsets(struct matcher *m)
|
||||
static void _create_bitsets(struct dm_regex *m)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -77,7 +77,7 @@ static void _create_bitsets(struct matcher *m)
|
||||
}
|
||||
}
|
||||
|
||||
static void _calc_functions(struct matcher *m)
|
||||
static void _calc_functions(struct dm_regex *m)
|
||||
{
|
||||
int i, j, final = 1;
|
||||
struct rx_node *rx, *c1, *c2;
|
||||
@@ -189,7 +189,7 @@ static struct state_queue *_create_state_queue(struct dm_pool *mem,
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _calc_states(struct matcher *m, struct rx_node *rx)
|
||||
static int _calc_states(struct dm_regex *m, struct rx_node *rx)
|
||||
{
|
||||
unsigned iwidth = (m->num_nodes / DM_BITS_PER_INT) + 1;
|
||||
struct ttree *tt = ttree_create(m->scratch, iwidth);
|
||||
@@ -263,43 +263,38 @@ static int _calc_states(struct matcher *m, struct rx_node *rx)
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct matcher *matcher_create(struct dm_pool *mem, const char **patterns,
|
||||
unsigned num)
|
||||
struct dm_regex *dm_regex_create(struct dm_pool *mem, const char **patterns,
|
||||
unsigned num_patterns)
|
||||
{
|
||||
char *all, *ptr;
|
||||
int i;
|
||||
size_t len = 0;
|
||||
struct rx_node *rx;
|
||||
struct dm_pool *scratch = dm_pool_create("regex matcher", 10 * 1024);
|
||||
struct matcher *m;
|
||||
struct dm_regex *m;
|
||||
|
||||
if (!scratch) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
if (!scratch)
|
||||
return_NULL;
|
||||
|
||||
if (!(m = dm_pool_alloc(mem, sizeof(*m)))) {
|
||||
stack;
|
||||
dm_pool_destroy(scratch);
|
||||
return NULL;
|
||||
return_NULL;
|
||||
}
|
||||
|
||||
memset(m, 0, sizeof(*m));
|
||||
|
||||
/* join the regexps together, delimiting with zero */
|
||||
for (i = 0; i < num; i++)
|
||||
for (i = 0; i < num_patterns; i++)
|
||||
len += strlen(patterns[i]) + 8;
|
||||
|
||||
ptr = all = dm_pool_alloc(scratch, len + 1);
|
||||
|
||||
if (!all) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!all)
|
||||
goto_bad;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
for (i = 0; i < num_patterns; i++) {
|
||||
ptr += sprintf(ptr, "(.*(%s)%c)", patterns[i], TARGET_TRANS);
|
||||
if (i < (num - 1))
|
||||
if (i < (num_patterns - 1))
|
||||
*ptr++ = '|';
|
||||
}
|
||||
|
||||
@@ -314,10 +309,8 @@ struct matcher *matcher_create(struct dm_pool *mem, const char **patterns,
|
||||
m->num_nodes = _count_nodes(rx);
|
||||
m->nodes = dm_pool_alloc(scratch, sizeof(*m->nodes) * m->num_nodes);
|
||||
|
||||
if (!m->nodes) {
|
||||
stack;
|
||||
goto bad;
|
||||
}
|
||||
if (!m->nodes)
|
||||
goto_bad;
|
||||
|
||||
_fill_table(m, rx);
|
||||
_create_bitsets(m);
|
||||
@@ -330,7 +323,7 @@ struct matcher *matcher_create(struct dm_pool *mem, const char **patterns,
|
||||
|
||||
bad:
|
||||
dm_pool_destroy(scratch);
|
||||
dm_pool_destroy(mem);
|
||||
dm_pool_free(mem, m);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -345,16 +338,16 @@ static struct dfa_state *_step_matcher(int c, struct dfa_state *cs, int *r)
|
||||
return cs;
|
||||
}
|
||||
|
||||
int matcher_run(struct matcher *m, const char *b)
|
||||
int dm_regex_match(struct dm_regex *regex, const char *s)
|
||||
{
|
||||
struct dfa_state *cs = m->start;
|
||||
struct dfa_state *cs = regex->start;
|
||||
int r = 0;
|
||||
|
||||
if (!(cs = _step_matcher(HAT_CHAR, cs, &r)))
|
||||
goto out;
|
||||
|
||||
for (; *b; b++)
|
||||
if (!(cs = _step_matcher(*b, cs, &r)))
|
||||
for (; *s; s++)
|
||||
if (!(cs = _step_matcher(*s, cs, &r)))
|
||||
goto out;
|
||||
|
||||
_step_matcher(DOLLAR_CHAR, cs, &r);
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
* This file is part of the device-mapper userspace tools.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
* This file is part of the device-mapper userspace tools.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
@@ -13,8 +13,8 @@
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _LVM_PARSE_REGEX_H
|
||||
#define _LVM_PARSE_REGEX_H
|
||||
#ifndef _DM_PARSE_REGEX_H
|
||||
#define _DM_PARSE_REGEX_H
|
||||
|
||||
enum {
|
||||
CAT,
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
* This file is part of the device-mapper userspace tools.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
* This file is part of the device-mapper userspace tools.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
@@ -13,8 +13,8 @@
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _LVM_TTREE_H
|
||||
#define _LVM_TTREE_H
|
||||
#ifndef _DM_TTREE_H
|
||||
#define _DM_TTREE_H
|
||||
|
||||
struct ttree;
|
||||
|
||||
@@ -56,7 +56,7 @@ endif
|
||||
|
||||
.SUFFIXES: .c .d .o .so .a .po .pot .mo .dylib
|
||||
|
||||
CFLAGS += -fPIC -Wall -Wundef -Wshadow -Wcast-align -Wwrite-strings -Wmissing-prototypes -Wmissing-declarations -Wnested-externs -Winline -Wmissing-noreturn
|
||||
CFLAGS += -fPIC -Wall -Wundef -Wshadow -Wcast-align -Wwrite-strings -Wmissing-prototypes -Wmissing-declarations -Wnested-externs -Winline -Wmissing-noreturn -Wformat-security
|
||||
|
||||
#CFLAGS += -W -Wconversion -Wpointer-arith -Wredundant-decls -Wbad-function-cast -Wcast-qual
|
||||
#CFLAGS += -pedantic -std=gnu99
|
||||
@@ -94,7 +94,7 @@ STRIP=
|
||||
LIB_VERSION := $(shell cat $(top_srcdir)/VERSION | \
|
||||
awk -F '.' '{printf "%s.%s",$$1,$$2}')
|
||||
|
||||
INCLUDES += -I. -I$(top_srcdir)/include
|
||||
INCLUDES += -I$(top_srcdir)/include
|
||||
|
||||
ifneq ("@DMDIR@", "")
|
||||
INCLUDES += -I@DMDIR@/include
|
||||
|
||||
@@ -20,7 +20,7 @@ MAN5=lvm.conf.5
|
||||
MAN8=lvchange.8 lvconvert.8 lvcreate.8 lvdisplay.8 lvextend.8 lvm.8 \
|
||||
lvmchange.8 lvmdiskscan.8 lvmdump.8 \
|
||||
lvreduce.8 lvremove.8 lvrename.8 lvresize.8 lvs.8 \
|
||||
lvscan.8 pvchange.8 pvcreate.8 pvdisplay.8 pvmove.8 pvremove.8 \
|
||||
lvscan.8 pvchange.8 pvck.8 pvcreate.8 pvdisplay.8 pvmove.8 pvremove.8 \
|
||||
pvresize.8 pvs.8 pvscan.8 vgcfgbackup.8 vgcfgrestore.8 vgchange.8 \
|
||||
vgck.8 vgcreate.8 vgconvert.8 vgdisplay.8 vgexport.8 vgextend.8 \
|
||||
vgimport.8 vgmerge.8 vgmknodes.8 vgreduce.8 vgremove.8 vgrename.8 \
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -194,6 +194,7 @@ All tools return a status code of zero on success or non-zero on failure.
|
||||
.BR lvs (8),
|
||||
.BR lvscan (8),
|
||||
.BR pvchange (8),
|
||||
.BR pvck (8),
|
||||
.BR pvcreate (8),
|
||||
.BR pvdisplay (8),
|
||||
.BR pvmove (8),
|
||||
|
||||
@@ -81,6 +81,11 @@ LVM physical volumes.
|
||||
Devices in directories outside this hierarchy will be ignored.
|
||||
Defaults to "/dev".
|
||||
.IP
|
||||
\fBpreferred_names\fP \(em List of patterns compared in turn against
|
||||
all the pathnames referencing the same device in in the scanned directories.
|
||||
The pathname that matches the earliest pattern in the list is the
|
||||
one used in any output.
|
||||
.IP
|
||||
\fBfilter\fP \(em List of patterns to apply to devices found by a scan.
|
||||
Patterns are regular expressions delimited by any character and preceded
|
||||
by \fBa\fP (for accept) or \fBr\fP (for reject). The list is traversed
|
||||
@@ -95,8 +100,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 +369,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),
|
||||
|
||||
@@ -51,7 +51,7 @@ invalid (S)napshot, (v)irtual
|
||||
.IP 2 3
|
||||
Permissions: (w)riteable, (r)ead-only
|
||||
.IP 3 3
|
||||
Allocation policy: (c)ontiguous, (n)ormal, (a)nywhere, (i)nherited
|
||||
Allocation policy: (c)ontiguous, c(l)ing, (n)ormal, (a)nywhere, (i)nherited
|
||||
This is capitalised if the volume is currently locked against allocation
|
||||
changes, for example during \fBpvmove\fP (8).
|
||||
.IP 4 3
|
||||
|
||||
33
man/pvck.8
Normal file
33
man/pvck.8
Normal file
@@ -0,0 +1,33 @@
|
||||
.TH PVCK 8 "LVM TOOLS" "Sistina Software UK" \" -*- nroff -*-
|
||||
.SH NAME
|
||||
pvck \- check physical volume metadata
|
||||
.SH SYNOPSIS
|
||||
.B pvck
|
||||
.RB [ \-d | \-\-debug ]
|
||||
.RB [ \-h | \-\-help ]
|
||||
.RB [ \-v | \-\-verbose ]
|
||||
.RB [ \-\-labelsector ]
|
||||
.IR PhysicalVolume " [" PhysicalVolume ...]
|
||||
.SH DESCRIPTION
|
||||
pvck checks physical volume LVM metadata for consistency.
|
||||
.SH OPTIONS
|
||||
See \fBlvm\fP for common options.
|
||||
.TP
|
||||
.BR \-\-labelsector " sector"
|
||||
By default, 4 sectors of \fBPhysicalVolume\fP are scanned for an LVM label,
|
||||
starting at sector 0. This parameter allows you to specify a different
|
||||
starting sector for the scan and is useful for recovery situations. For
|
||||
example, suppose the partition table is corrupted or lost on /dev/sda,
|
||||
but you suspect there was an LVM partition at approximately 100 MB. This
|
||||
area of the disk may be scanned by using the \fB--labelsector\fP parameter
|
||||
with a value of 204800 (100 * 1024 * 1024 / 512 = 204800):
|
||||
.sp
|
||||
.BI "pvck --labelsector 204800 /dev/sda"
|
||||
.sp
|
||||
Note that a script can be used with \fB--labelsector\fP to automate the
|
||||
process of finding LVM labels.
|
||||
.SH SEE ALSO
|
||||
.BR lvm (8),
|
||||
.BR pvcreate (8),
|
||||
.BR pvscan (8)
|
||||
.BR vgck (8)
|
||||
@@ -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
|
||||
|
||||
19
man/vgs.8
19
man/vgs.8
@@ -36,9 +36,24 @@ vg_free_count, max_lv, max_pv, pv_count, lv_count, snap_count, vg_seqno,
|
||||
vg_tags.
|
||||
Any "vg_" prefixes are optional. Columns mentioned in either \fBpvs (8)\fP
|
||||
or \fBlvs (8)\fP can also be chosen, but columns cannot be taken from both
|
||||
at the same time. The vg_attr bits are: (w)riteable, (r)eadonly,
|
||||
resi(z)eable, e(x)ported, (p)artial and (c)lustered.
|
||||
at the same time.
|
||||
Use \fb-o help\fP to view the full list of fields available.
|
||||
.IP
|
||||
The vg_attr bits are:
|
||||
.RS
|
||||
.IP 1 3
|
||||
Permissions: (w)riteable, (r)ead-only
|
||||
.IP 2 3
|
||||
Resi(z)eable
|
||||
.IP 3 3
|
||||
E(x)ported
|
||||
.IP 4 3
|
||||
(p)artial
|
||||
.IP 5 3
|
||||
Allocation policy: (c)ontiguous, c(l)ing, (n)ormal, (a)nywhere, (i)nherited
|
||||
.IP 6 3
|
||||
(c)lustered
|
||||
.RE
|
||||
.TP
|
||||
.I \-O, \-\-sort
|
||||
Comma-separated ordered list of columns to sort by. Replaces the default
|
||||
|
||||
5619
po/lvm2.po
5619
po/lvm2.po
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -147,7 +147,10 @@ myecho "Gathering /etc/lvm info..."
|
||||
log "$CP -a /etc/lvm $dir/lvm 2>> $log"
|
||||
|
||||
myecho "Gathering /dev listing..."
|
||||
log "$LS -la /dev > $dir/dev_listing 2>> $log"
|
||||
log "$LS -laR /dev > $dir/dev_listing 2>> $log"
|
||||
|
||||
myecho "Gathering /sys/block listing..."
|
||||
log "$LS -laR /sys/block > $dir/sysblock_listing"
|
||||
|
||||
if (( $metadata )); then
|
||||
myecho "Gathering LVM metadata from Physical Volumes..."
|
||||
|
||||
@@ -38,6 +38,7 @@ SOURCES =\
|
||||
lvscan.c \
|
||||
polldaemon.c \
|
||||
pvchange.c \
|
||||
pvck.c \
|
||||
pvcreate.c \
|
||||
pvdisplay.c \
|
||||
pvmove.c \
|
||||
|
||||
@@ -407,6 +407,18 @@ xx(pvresize,
|
||||
|
||||
physicalvolumesize_ARG, test_ARG)
|
||||
|
||||
xx(pvck,
|
||||
"Check the consistency of physical volume(s)",
|
||||
"pvck "
|
||||
"\t[-d|--debug]\n"
|
||||
"\t[-h|--help]\n"
|
||||
"\t[--labelsector sector] " "\n"
|
||||
"\t[-v|--verbose]\n"
|
||||
"\t[--version]" "\n"
|
||||
"\tPhysicalVolume [PhysicalVolume...]\n",
|
||||
|
||||
labelsector_ARG)
|
||||
|
||||
xx(pvcreate,
|
||||
"Initialize physical volume(s) for use by LVM",
|
||||
"pvcreate " "\n"
|
||||
|
||||
109
tools/dmsetup.c
109
tools/dmsetup.c
@@ -19,7 +19,7 @@
|
||||
#define _GNU_SOURCE
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
|
||||
#include <configure.h>
|
||||
#include "configure.h"
|
||||
|
||||
#include "libdevmapper.h"
|
||||
#include "log.h"
|
||||
@@ -749,7 +749,7 @@ static int _error_device(int argc __attribute((unused)), char **argv __attribute
|
||||
if (!_set_task_device(dmt, name, 0))
|
||||
goto error;
|
||||
|
||||
if (!dm_task_add_target(dmt, 0, size, "error", ""))
|
||||
if (!dm_task_add_target(dmt, UINT64_C(0), size, "error", ""))
|
||||
goto error;
|
||||
|
||||
if (_switches[READ_ONLY] && !dm_task_set_ro(dmt))
|
||||
@@ -962,17 +962,18 @@ static int _status(int argc, char **argv, void *data)
|
||||
if (data && !_switches[VERBOSE_ARG])
|
||||
printf("%s: ", name);
|
||||
if (target_type) {
|
||||
|
||||
/* Suppress encryption key */
|
||||
if (!_switches[SHOWKEYS_ARG] &&
|
||||
!strcmp(target_type, "crypt")) {
|
||||
c = params;
|
||||
while (*c && *c != ' ')
|
||||
c++;
|
||||
c++;
|
||||
while (*c && *c != ' ')
|
||||
*c++ = '0';
|
||||
}
|
||||
/* Suppress encryption key */
|
||||
if (!_switches[SHOWKEYS_ARG] &&
|
||||
cmd == DM_DEVICE_TABLE &&
|
||||
!strcmp(target_type, "crypt")) {
|
||||
c = params;
|
||||
while (*c && *c != ' ')
|
||||
c++;
|
||||
if (*c)
|
||||
c++;
|
||||
while (*c && *c != ' ')
|
||||
*c++ = '0';
|
||||
}
|
||||
printf("%" PRIu64 " %" PRIu64 " %s %s",
|
||||
start, length, target_type, params);
|
||||
}
|
||||
@@ -1261,10 +1262,10 @@ static void _out_char(const unsigned c)
|
||||
}
|
||||
}
|
||||
|
||||
static void _out_string(const unsigned char *str)
|
||||
static void _out_string(const char *str)
|
||||
{
|
||||
while (*str)
|
||||
_out_char(*str++);
|
||||
_out_char((unsigned char) *str++);
|
||||
}
|
||||
|
||||
/* non-negative integers only */
|
||||
@@ -1502,7 +1503,7 @@ static int _dm_name_disp(struct dm_report *rh,
|
||||
struct dm_report_field *field, const void *data,
|
||||
void *private __attribute((unused)))
|
||||
{
|
||||
const char *name = dm_task_get_name((struct dm_task *) data);
|
||||
const char *name = dm_task_get_name((const struct dm_task *) data);
|
||||
|
||||
return dm_report_field_string(rh, field, &name);
|
||||
}
|
||||
@@ -1512,7 +1513,7 @@ static int _dm_uuid_disp(struct dm_report *rh,
|
||||
struct dm_report_field *field,
|
||||
const void *data, void *private __attribute((unused)))
|
||||
{
|
||||
const char *uuid = dm_task_get_uuid((struct dm_task *) data);
|
||||
const char *uuid = dm_task_get_uuid((const struct dm_task *) data);
|
||||
|
||||
if (!uuid || !*uuid)
|
||||
uuid = "";
|
||||
@@ -1527,7 +1528,7 @@ static int _dm_info_status_disp(struct dm_report *rh,
|
||||
{
|
||||
char buf[5];
|
||||
const char *s = buf;
|
||||
struct dm_info *info = (struct dm_info *) data;
|
||||
const struct dm_info *info = data;
|
||||
|
||||
buf[0] = info->live_table ? 'L' : '-';
|
||||
buf[1] = info->inactive_table ? 'I' : '-';
|
||||
@@ -1561,20 +1562,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 +1584,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 +1626,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 +1674,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 +1714,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 +1736,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;
|
||||
@@ -1743,7 +1768,7 @@ static int _process_tree_options(const char *options)
|
||||
{
|
||||
const char *s, *end;
|
||||
struct winsize winsz;
|
||||
int len;
|
||||
size_t len;
|
||||
|
||||
/* Symbol set default */
|
||||
if (!strcmp(nl_langinfo(CODESET), "UTF-8"))
|
||||
@@ -1799,7 +1824,7 @@ static int _process_tree_options(const char *options)
|
||||
|
||||
/* Truncation doesn't work well with vt100 drawing char */
|
||||
if (_tsym != &_tsym_vt100)
|
||||
if (ioctl(1, TIOCGWINSZ, &winsz) >= 0 && winsz.ws_col > 3)
|
||||
if (ioctl(1, (unsigned long) TIOCGWINSZ, &winsz) >= 0 && winsz.ws_col > 3)
|
||||
_termwidth = winsz.ws_col - 3;
|
||||
|
||||
return 1;
|
||||
@@ -1836,13 +1861,13 @@ static char *parse_loop_device_name(char *dev)
|
||||
if (strncmp(device, DEV_PATH, strlen(DEV_PATH)))
|
||||
goto error;
|
||||
|
||||
strncpy(buf, strrchr(device, '/') + 1, PATH_MAX);
|
||||
strncpy(buf, strrchr(device, '/') + 1, (size_t) PATH_MAX);
|
||||
dm_free(device);
|
||||
|
||||
} else {
|
||||
/* check for device number */
|
||||
if (!strncmp(dev, "loop", strlen("loop")))
|
||||
strncpy(buf, dev, PATH_MAX);
|
||||
strncpy(buf, dev, (size_t) PATH_MAX);
|
||||
else
|
||||
goto error;
|
||||
}
|
||||
@@ -1885,8 +1910,9 @@ static int _loop_table(char *table, size_t tlen, char *file,
|
||||
sectors = size >> SECTOR_SHIFT;
|
||||
|
||||
if (_switches[VERBOSE_ARG])
|
||||
fprintf(stderr, "losetup: set loop size to %llukB (%llu sectors)\n",
|
||||
sectors >> 1, sectors);
|
||||
fprintf(stderr, "losetup: set loop size to %llukB "
|
||||
"(%llu sectors)\n", (long long unsigned) sectors >> 1,
|
||||
(long long unsigned) sectors);
|
||||
|
||||
#ifdef HAVE_SYS_STATVFS_H
|
||||
if (fstatvfs(fd, &fsbuf))
|
||||
@@ -1995,6 +2021,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,13 +2030,15 @@ 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;
|
||||
}
|
||||
|
||||
/* FIXME Missing free */
|
||||
_table = dm_malloc(LOOP_TABLE_SIZE);
|
||||
if (!_loop_table(_table, LOOP_TABLE_SIZE, loop_file, device_name, offset)) {
|
||||
if (!_loop_table(_table, (size_t) 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 +2125,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;
|
||||
|
||||
@@ -307,7 +307,7 @@ static int lvconvert_mirrors(struct cmd_context * cmd, struct logical_volume * l
|
||||
if (!(log_lv = create_mirror_log(cmd, lv->vg, ah,
|
||||
lp->alloc, lv->name,
|
||||
(sync_percent >= 100.0) ?
|
||||
1 : 0))) {
|
||||
1 : 0, &lv->tags))) {
|
||||
log_error("Failed to create mirror log.");
|
||||
return 0;
|
||||
}
|
||||
@@ -385,7 +385,7 @@ static int lvconvert_mirrors(struct cmd_context * cmd, struct logical_volume * l
|
||||
if (!arg_count(cmd, corelog_ARG) &&
|
||||
!(log_lv = create_mirror_log(cmd, lv->vg, ah,
|
||||
lp->alloc,
|
||||
lv->name, 0))) {
|
||||
lv->name, 0, &lv->tags))) {
|
||||
log_error("Failed to create mirror log.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -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)");
|
||||
@@ -476,8 +476,8 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
|
||||
uint64_t tmp_size;
|
||||
struct volume_group *vg;
|
||||
struct logical_volume *lv, *org = NULL, *log_lv = NULL;
|
||||
struct list *pvh;
|
||||
const char *tag;
|
||||
struct list *pvh, tags;
|
||||
const char *tag = NULL;
|
||||
int consistent = 1;
|
||||
struct alloc_handle *ah = NULL;
|
||||
char lv_name_buf[128];
|
||||
@@ -675,6 +675,19 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
|
||||
lv_name = &lv_name_buf[0];
|
||||
}
|
||||
|
||||
if (arg_count(cmd, addtag_ARG)) {
|
||||
if (!(tag = arg_str_value(cmd, addtag_ARG, NULL))) {
|
||||
log_error("Failed to get tag");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(vg->fid->fmt->features & FMT_TAGS)) {
|
||||
log_error("Volume group %s does not support tags",
|
||||
vg->name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (lp->mirrors > 1) {
|
||||
/* FIXME Calculate how many extents needed for the log */
|
||||
|
||||
@@ -698,9 +711,13 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
|
||||
status |= MIRROR_NOTSYNCED;
|
||||
}
|
||||
|
||||
list_init(&tags);
|
||||
if (tag)
|
||||
str_list_add(cmd->mem, &tags, tag);
|
||||
|
||||
if (!lp->corelog &&
|
||||
!(log_lv = create_mirror_log(cmd, vg, ah, lp->alloc,
|
||||
lv_name, lp->nosync))) {
|
||||
lv_name, lp->nosync, &tags))) {
|
||||
log_error("Failed to create mirror log.");
|
||||
return 0;
|
||||
}
|
||||
@@ -725,23 +742,10 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
|
||||
lv->minor);
|
||||
}
|
||||
|
||||
if (arg_count(cmd, addtag_ARG)) {
|
||||
if (!(tag = arg_str_value(cmd, addtag_ARG, NULL))) {
|
||||
log_error("Failed to get tag");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!(lv->vg->fid->fmt->features & FMT_TAGS)) {
|
||||
log_error("Volume group %s does not support tags",
|
||||
lv->vg->name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!str_list_add(cmd->mem, &lv->tags, tag)) {
|
||||
log_error("Failed to add tag %s to %s/%s",
|
||||
tag, lv->vg->name, lv->name);
|
||||
goto error;
|
||||
}
|
||||
if (tag && !str_list_add(cmd->mem, &lv->tags, tag)) {
|
||||
log_error("Failed to add tag %s to %s/%s",
|
||||
tag, lv->vg->name, lv->name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (lp->mirrors > 1) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
224
tools/lvm.c
224
tools/lvm.c
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -841,30 +827,30 @@ static char *_copy_command_line(struct cmd_context *cmd, int argc, char **argv)
|
||||
* description for backups.
|
||||
*/
|
||||
if (!dm_pool_begin_object(cmd->mem, 128))
|
||||
goto bad;
|
||||
goto_bad;
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
space = strchr(argv[i], ' ') ? 1 : 0;
|
||||
|
||||
if (space && !dm_pool_grow_object(cmd->mem, "'", 1))
|
||||
goto bad;
|
||||
goto_bad;
|
||||
|
||||
if (!dm_pool_grow_object(cmd->mem, argv[i], strlen(argv[i])))
|
||||
goto bad;
|
||||
goto_bad;
|
||||
|
||||
if (space && !dm_pool_grow_object(cmd->mem, "'", 1))
|
||||
goto bad;
|
||||
goto_bad;
|
||||
|
||||
if (i < (argc - 1))
|
||||
if (!dm_pool_grow_object(cmd->mem, " ", 1))
|
||||
goto bad;
|
||||
goto_bad;
|
||||
}
|
||||
|
||||
/*
|
||||
* Terminate.
|
||||
*/
|
||||
if (!dm_pool_grow_object(cmd->mem, "\0", 1))
|
||||
goto bad;
|
||||
goto_bad;
|
||||
|
||||
return dm_pool_end_object(cmd->mem);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -112,7 +112,7 @@ int lvmdiskscan(struct cmd_context *cmd, int argc __attribute((unused)),
|
||||
/* Do scan */
|
||||
for (dev = dev_iter_get(iter); dev; dev = dev_iter_get(iter)) {
|
||||
/* Try if it is a PV first */
|
||||
if ((label_read(dev, &label))) {
|
||||
if ((label_read(dev, &label, UINT64_C(0)))) {
|
||||
if (!dev_get_size(dev, &size)) {
|
||||
log_error("Couldn't get size of \"%s\"",
|
||||
dev_name(dev));
|
||||
|
||||
@@ -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, '/') &&
|
||||
|
||||
40
tools/pvck.c
Normal file
40
tools/pvck.c
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2007 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU General Public License v.2.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "tools.h"
|
||||
|
||||
int pvck(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* FIXME: validate cmdline options */
|
||||
/* FIXME: what does the cmdline look like? */
|
||||
/*
|
||||
* Use what's on the cmdline directly, and avoid calling into
|
||||
* some of the other infrastructure functions, so as to avoid
|
||||
* hitting some of the lvmcache behavior, scanning other devices,
|
||||
* etc.
|
||||
*/
|
||||
for (i = 0; i < argc; i++) {
|
||||
/* FIXME: warning and/or check if in use? */
|
||||
log_verbose("Scanning %s", argv[i]);
|
||||
|
||||
pv_analyze(cmd, argv[i],
|
||||
arg_int64_value(cmd, labelsector_ARG,
|
||||
UINT64_C(0)));
|
||||
}
|
||||
|
||||
return ECMD_PROCESSED;
|
||||
}
|
||||
@@ -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, '/')) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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: "
|
||||
@@ -1288,11 +1310,13 @@ struct logical_volume *create_mirror_log(struct cmd_context *cmd,
|
||||
struct alloc_handle *ah,
|
||||
alloc_policy_t alloc,
|
||||
const char *lv_name,
|
||||
int in_sync)
|
||||
int in_sync,
|
||||
struct list *tags)
|
||||
{
|
||||
struct logical_volume *log_lv;
|
||||
char *log_name;
|
||||
size_t len;
|
||||
struct str_list *sl;
|
||||
|
||||
len = strlen(lv_name) + 32;
|
||||
if (!(log_name = alloca(len)) ||
|
||||
@@ -1314,6 +1338,13 @@ struct logical_volume *create_mirror_log(struct cmd_context *cmd,
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Temporary tag mirror log */
|
||||
list_iterate_items(sl, tags)
|
||||
if (!str_list_add(cmd->mem, &log_lv->tags, sl->str)) {
|
||||
log_error("Aborting. Unable to tag mirror log.");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* store mirror log on disk(s) */
|
||||
if (!vg_write(vg)) {
|
||||
stack;
|
||||
@@ -1339,6 +1370,11 @@ struct logical_volume *create_mirror_log(struct cmd_context *cmd,
|
||||
goto error;
|
||||
}
|
||||
|
||||
list_iterate_items(sl, tags)
|
||||
if (!str_list_del(&log_lv->tags, sl->str))
|
||||
log_error("Failed to remove tag %s from mirror log.",
|
||||
sl->str);
|
||||
|
||||
if (activation() && !set_lv(cmd, log_lv, log_lv->size,
|
||||
in_sync ? -1 : 0)) {
|
||||
log_error("Aborting. Failed to wipe mirror log. "
|
||||
|
||||
@@ -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
|
||||
@@ -99,7 +100,8 @@ struct logical_volume *create_mirror_log(struct cmd_context *cmd,
|
||||
struct alloc_handle *ah,
|
||||
alloc_policy_t alloc,
|
||||
const char *lv_name,
|
||||
int in_sync);
|
||||
int in_sync,
|
||||
struct list *tags);
|
||||
|
||||
int set_lv(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
uint64_t sectors, int value);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user