[DRBD-cvs] svn commit by phil - r2371 - trunk/user - The begin of
the new netlink based drbdstup...
drbd-cvs at lists.linbit.com
drbd-cvs at lists.linbit.com
Mon Aug 14 17:18:27 CEST 2006
Author: phil
Date: 2006-08-14 17:18:26 +0200 (Mon, 14 Aug 2006)
New Revision: 2371
Added:
trunk/user/drbd_nl.h
trunk/user/drbd_tag_magic.h
trunk/user/drbdsetup_nl.c
Log:
The begin of the new netlink based drbdstup...
Added: trunk/user/drbd_nl.h
===================================================================
--- trunk/user/drbd_nl.h 2006-08-14 07:03:59 UTC (rev 2370)
+++ trunk/user/drbd_nl.h 2006-08-14 15:18:26 UTC (rev 2371)
@@ -0,0 +1,59 @@
+/*
+ PAKET( name,
+ TYPE ( pn, pr, member )
+ ...
+ )
+
+ You may never reissue one of the pn arguments
+*/
+
+#if !defined(PACKET) || !defined(STRING) || !defined(INTEGER) || !defined(BIT) || !defined(INT64)
+#error "The macros PACKET, STRING, INTEGER, INT64 and BIT needs to be defined"
+#endif
+
+PACKET(primary,
+ BIT( 1, T_MAY_IGNORE, overwrite_peer)
+)
+
+PACKET(secondary, )
+
+PACKET(disk_conf,
+ INT64( 2, T_MAY_IGNORE, disk_size)
+ INTEGER( 3, T_MANDATORY, backing_dev)
+ INTEGER( 4, T_MANDATORY, meta_dev)
+ INTEGER( 5, T_MANDATORY, meta_dev_idx)
+ INTEGER( 6, T_MAY_IGNORE, on_io_error)
+ INTEGER( 7, T_MAY_IGNORE, fencing)
+)
+
+PACKET(detach, )
+
+PACKET(net_conf,
+ STRING( 8, T_MANDATORY, my_addr, 128)
+ STRING( 9, T_MANDATORY, peer_addr, 128)
+ STRING( 10, T_MAY_IGNORE, shared_secret, 128)
+ STRING( 11, T_MAY_IGNORE, cram_hmac_alg, 128)
+ INTEGER( 12, T_MANDATORY, my_addr_len)
+ INTEGER( 13, T_MANDATORY, peer_addr_len)
+ INTEGER( 14, T_MAY_IGNORE, timeout)
+ INTEGER( 15, T_MANDATORY, wire_protocol)
+ INTEGER( 16, T_MAY_IGNORE, try_connect_int)
+ INTEGER( 17, T_MAY_IGNORE, ping_int)
+ INTEGER( 18, T_MAY_IGNORE, max_epoch_size)
+ INTEGER( 19, T_MAY_IGNORE, max_buffers)
+ INTEGER( 20, T_MAY_IGNORE, unplug_watermark)
+ INTEGER( 21, T_MAY_IGNORE, sndbuf_size)
+ INTEGER( 22, T_MAY_IGNORE, ko_count)
+ INTEGER( 24, T_MAY_IGNORE, after_sb_0p)
+ INTEGER( 25, T_MAY_IGNORE, after_sb_1p)
+ INTEGER( 26, T_MAY_IGNORE, after_sb_2p)
+ BIT( 27, T_MAY_IGNORE, want_lose)
+ BIT( 28, T_MAY_IGNORE, two_primaries)
+)
+
+#undef PACKET
+#undef INTEGER
+#undef INT64
+#undef BIT
+#undef STRING
+
Added: trunk/user/drbd_tag_magic.h
===================================================================
--- trunk/user/drbd_tag_magic.h 2006-08-14 07:03:59 UTC (rev 2370)
+++ trunk/user/drbd_tag_magic.h 2006-08-14 15:18:26 UTC (rev 2371)
@@ -0,0 +1,72 @@
+#ifndef DRBD_TAG_MAGIC_H
+#define DRBD_TAG_MAGIC_H
+
+#define TT_END 0
+
+// declare packet_type enums
+enum packet_types {
+#define PACKET(name, fields) P_ ## name,
+#define INTEGER(pn,pr,member)
+#define INT64(pn,pr,member)
+#define BIT(pn,pr,member)
+#define STRING(pn,pr,member,len)
+#include "drbd_nl.h"
+};
+
+// declate structs
+#define PACKET(name, fields) struct name { fields };
+#define INTEGER(pn,pr,member) int member;
+#define INT64(pn,pr,member) __u64 member;
+#define BIT(pn,pr,member) unsigned member : 1;
+#define STRING(pn,pr,member,len) unsigned char member[len];
+#include "drbd_nl.h"
+
+// declate tag-list-sizes
+#define PACKET(name,fields) const int name ## _tag_size = 2 fields ;
+#define INTEGER(pn,pr,member) +4+4
+#define INT64(pn,pr,member) +4+8
+#define BIT(pn,pr,member) +4+1
+#define STRING(pn,pr,member,len) +4+len
+#include "drbd_nl.h"
+
+/* The two highest bits are used for the tag type */
+#define TT_MASK 0xC000
+#define TT_INTEGER 0x0000
+#define TT_INT64 0x4000
+#define TT_BIT 0x8000
+#define TT_STRING 0xC000
+/* The next bit indicates if processing of the tag is mandatory */
+#define T_MANDATORY 0x2000
+#define T_MAY_IGNORE 0x0000
+#define TN_MASK 0x1fff
+/* The remaining 13 bits are used to enumerate the tags */
+
+#define tag_type(T) ((T) & TT_MASK)
+#define tag_number(T) ((T) & TN_MASK)
+
+// declare tag enums
+#define PACKET(name, fields) fields
+enum drbd_tags {
+#define INTEGER(pn,pr,member) T_ ## member = pn | TT_INTEGER | pr ,
+#define INT64(pn,pr,member) T_ ## member = pn | TT_INT64 | pr ,
+#define BIT(pn,pr,member) T_ ## member = pn | TT_BIT | pr ,
+#define STRING(pn,pr,member,len) T_ ## member = pn | TT_STRING | pr ,
+#include "drbd_nl.h"
+};
+
+struct tag {
+ const char* name;
+ int type_n_flags;
+};
+
+// declare tag names
+#define PACKET(name, fields) fields
+const struct tag tag_descriptions[] = {
+#define INTEGER(pn,pr,member) [ pn ] = { #member, TT_INTEGER | pr },
+#define INT64(pn,pr,member) [ pn ] = { #member, TT_INT64 | pr },
+#define BIT(pn,pr,member) [ pn ] = { #member, TT_BIT | pr },
+#define STRING(pn,pr,member,len) [ pn ] = { #member, TT_STRING | pr },
+#include "drbd_nl.h"
+};
+
+#endif
Added: trunk/user/drbdsetup_nl.c
===================================================================
--- trunk/user/drbdsetup_nl.c 2006-08-14 07:03:59 UTC (rev 2370)
+++ trunk/user/drbdsetup_nl.c 2006-08-14 15:18:26 UTC (rev 2371)
@@ -0,0 +1,643 @@
+/*
+ drbdsetup.c
+
+ This file is part of drbd by Philipp Reisner.
+
+ Copyright (C) 1999-2006, Philipp Reisner <philipp.reisner at linbit.com>.
+ Copyright (C) 2002-2006, Lars Ellenberg <lars.ellenberg at linbit.com>.
+ Copyright (C) 2001-2006, LINBIT Information Technologies GmbH.
+
+ Copyright (C) 2000, Fábio Olivé Leite <olive at conectiva.com.br>.
+ Added sanity checks before using the device.
+
+ drbd is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ drbd is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with drbd; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ */
+
+#define _GNU_SOURCE
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <linux/drbd.h>
+#include <linux/drbd_config.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <mntent.h>
+#include "drbdtool_common.h"
+#include "drbd_limits.h"
+#include "drbd_tag_magic.h"
+
+struct drbd_tag_list {
+ unsigned short *tag_list_start;
+ unsigned short *tag_list_cpos;
+ int tag_size;
+};
+
+struct drbd_argument {
+ const char* name;
+ const enum drbd_tags tag;
+ int (*convert_function)(struct drbd_argument *,
+ struct drbd_tag_list *,
+ char *);
+};
+
+struct drbd_option {
+ const char* name;
+ const char short_name;
+ const enum drbd_tags tag;
+ int (*convert_function)(struct drbd_option *,
+ struct drbd_tag_list *,
+ char *);
+ union {
+ struct {
+ const unsigned long long min;
+ const unsigned long long max;
+ const unsigned long long def;
+ const unsigned char default_unit;
+ } numeric_param;
+ struct {
+ const char** handler_names;
+ const int number_of_handlers;
+ } handler_param;
+ };
+};
+
+struct drbd_cmd {
+ const char* cmd;
+ const int packet_id;
+ int (*function)(struct drbd_cmd *, int, char **);
+ struct drbd_argument *args;
+ struct drbd_option *options;
+};
+
+
+const char *on_error[] = {
+ [PassOn] = "pass_on",
+ [Panic] = "panic",
+ [Detach] = "detach",
+};
+
+const char *fencing_n[] = {
+ [DontCare] = "dont-care",
+ [Resource] = "resource-only",
+ [Stonith] = "resource-and-stonith",
+};
+
+const char *asb0p_n[] = {
+ [Disconnect] = "disconnect",
+ [DiscardYoungerPri] = "discard-younger-primary",
+ [DiscardOlderPri] = "discard-older-primary",
+ [DiscardLeastChg] = "discard-least-changes",
+ [DiscardLocal] = "discard-local",
+ [DiscardRemote] = "discard-remote"
+};
+
+const char *asb1p_n[] = {
+ [Disconnect] = "disconnect",
+ [Consensus] = "consensus",
+ [DiscardSecondary] = "discard-secondary",
+ [PanicPrimary] = "panic-primary"
+};
+
+const char *asb2p_n[] = {
+ [Disconnect] = "disconnect",
+ [PanicPrimary] = "panic"
+};
+
+// other functions
+void print_command_usage(int i, const char *addinfo);
+// command functions
+int generic_config_cmd(struct drbd_cmd *cm, int argc, char **argv);
+// convert functions for arguments
+int conv_block_dev(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg);
+int conv_md_idx(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg);
+int conv_address(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg);
+int conv_protocol(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg);
+// convert functions for options
+int conv_numeric(struct drbd_option *od, struct drbd_tag_list *tl, char* arg);
+int conv_handler(struct drbd_option *od, struct drbd_tag_list *tl, char* arg);
+int conv_bit(struct drbd_option *od, struct drbd_tag_list *tl, char* arg);
+
+#define EN(N) \
+ conv_numeric, { .numeric_param = { N ## _min, N ## _max, N ## _default } }
+#define EN0 conv_numeric, { .numeric_param = { 0, -1, 0, 0 } }
+#define EH(N) \
+ conv_handler, { .handler_param = { N, ARRY_SIZE(N) } }
+#define EB conv_bit, { }
+
+
+
+
+struct drbd_cmd commands[] = {
+ {"primary", P_primary, generic_config_cmd, NULL,
+ (struct drbd_option[]) {
+ { "overwrite-data-of-peer",'o',T_disk_size, EB },
+ { NULL,0,0,NULL, { } }, }, },
+
+ {"secondary", P_secondary, generic_config_cmd, NULL, NULL },
+
+ {"disk", P_disk_conf, generic_config_cmd,
+ (struct drbd_argument[]) {
+ { "lower_dev", T_backing_dev, conv_block_dev },
+ { "meta_data_dev", T_meta_dev, conv_block_dev },
+ { "meta_data_index", T_meta_dev_idx, conv_md_idx },
+ { NULL, 0, NULL}, },
+ (struct drbd_option[]) {
+ { "size",'d', T_disk_size, EN0 },
+ { "on-io-error",'e', T_on_io_error, EH(on_error) },
+ { "fencing",'f', T_fencing, EH(fencing_n) },
+ { NULL,0,0,NULL, { } }, }, },
+
+ {"detach", P_detach, generic_config_cmd, NULL, NULL },
+
+ {"net", P_net_conf, generic_config_cmd,
+ (struct drbd_argument[]) {
+ { "local_addr", T_my_addr, conv_address },
+ { "remote_addr", T_peer_addr, conv_address },
+ { "protocol", T_wire_protocol,conv_protocol },
+ { NULL, 0, NULL}, },
+ (struct drbd_option[]) {
+ { "timeout",'t', T_timeout, EN0 },
+ { "max-epoch-size",'e',T_max_epoch_size,EN0 },
+ { "max-buffers",'b', T_max_buffers, EN0 },
+ { "unplug-watermark",'u',T_unplug_watermark, EN0 },
+ { "connect-int",'c', T_try_connect_int, EN0 },
+ { "ping-int",'i', T_ping_int, EN0 },
+ { "sndbuf-size",'S', T_sndbuf_size, EN0 },
+ { "ko-count",'k', T_ko_count, EN0 },
+ { "allow-two-primaries",'m',T_two_primaries, EN0 },
+ { "cram-hmac-alg",'a', T_cram_hmac_alg, EN0 },
+ { "shared-secret",'x', T_shared_secret, EN0 },
+ { "after-sb-0pri",'A', T_after_sb_0p, EH(asb0p_n) },
+ { "after-sb-1pri",'B', T_after_sb_1p, EH(asb1p_n) },
+ { "after-sb-2pri",'C', T_after_sb_2p, EH(asb2p_n) },
+ { "discard-my-data",'D', T_want_lose, EB },
+ { NULL,0,0,NULL, { } }, }, },
+};
+
+char* cmdname = 0;
+
+void dump_tag_list(struct drbd_tag_list *tl)
+{
+ unsigned short *tlc = tl->tag_list_start;
+ enum drbd_tags tag;
+ int len;
+ int integer;
+ char bit;
+ __u64 int64;
+ char* string;
+
+ while(*tlc != TT_END) {
+ tag = tag_number(*tlc++);
+ printf("(%d) %s = ",tag,tag_descriptions[tag].name);
+ len = *tlc++;
+ switch(tag_type(tag)) {
+ case TT_INTEGER:
+ integer = *(int*)tlc;
+ printf("%d",integer);
+ break;
+ case TT_INT64:
+ int64 = *(__u64*)tlc;
+ printf("%lld",(long long)int64);
+ break;
+ case TT_BIT:
+ bit = *(char*)tlc;
+ printf( bit ? "on" : "off");
+ break;
+ case TT_STRING:
+ string = (char*)tlc;
+ printf("%s",string);
+ break;
+ }
+ printf(" (len: %u)\n",len);
+ tlc = (unsigned short*)((char*)tlc + len);
+ }
+}
+
+struct drbd_tag_list *create_tag_list(int size)
+{
+ struct drbd_tag_list *tl;
+
+ tl = malloc(sizeof(struct drbd_tag_list));
+ tl->tag_list_start = malloc(size);
+ tl->tag_list_cpos = tl->tag_list_start;
+ tl->tag_size = size;
+
+ return tl;
+}
+
+void add_tag(struct drbd_tag_list *tl, int tag, void *data, int data_len)
+{
+ if( (tl->tag_list_cpos - tl->tag_list_start) + data_len
+ > tl->tag_size ) {
+ fprintf(stderr, "Tag list size exceeded!\n");
+ exit(20);
+ }
+ *tl->tag_list_cpos++ = tag;
+ *tl->tag_list_cpos++ = data_len;
+ memcpy(tl->tag_list_cpos,data,data_len);
+ tl->tag_list_cpos = (unsigned short*)((char*)tl->tag_list_cpos + data_len);
+}
+
+void free_tag_list(struct drbd_tag_list *tl)
+{
+ free(tl->tag_list_start);
+ free(tl);
+}
+
+int conv_block_dev(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg)
+{
+ struct stat sb;
+ int device_fd;
+ int err;
+
+ if ((device_fd = open(arg,O_RDWR))==-1) {
+ PERROR("Can not open device '%s'", arg);
+ return 20;
+ }
+
+ if ( (err=fstat(device_fd, &sb)) ) {
+ PERROR("fstat(%s) failed", arg);
+ return 20;
+ }
+
+ if(!S_ISBLK(sb.st_mode)) {
+ fprintf(stderr, "%s is not a block device!\n", arg);
+ return 20;
+ }
+
+ add_tag(tl,ad->tag,&device_fd,sizeof(device_fd));
+
+ return 0;
+}
+
+int conv_md_idx(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg)
+{
+ int idx;
+
+ if(!strcmp(arg,"internal")) idx = DRBD_MD_INDEX_FLEX_INT;
+ else if(!strcmp(arg,"flex")) idx = DRBD_MD_INDEX_FLEX_EXT;
+ else idx = m_strtoll(arg,1);
+
+ add_tag(tl,ad->tag,&idx,sizeof(idx));
+
+ return 0;
+}
+
+const char* addr_part(const char* s)
+{
+ static char buffer[200];
+ char *b;
+
+ b=strchr(s,':');
+ if(b) {
+ strncpy(buffer,s,b-s);
+ buffer[b-s]=0;
+ return buffer;
+ }
+ return s;
+}
+
+int port_part(const char* s)
+{
+ char *b;
+
+ b=strchr(s,':');
+
+ // m_strtoll_range(b+1,1, "port", DRBD_PORT_MIN, DRBD_PORT_MAX);
+ if(b) return m_strtoll(b+1,1);
+ return 7788;
+}
+
+unsigned long resolv(const char* name)
+{
+ unsigned long retval;
+
+ if((retval = inet_addr(name)) == INADDR_NONE ) {
+ struct hostent *he;
+ he = gethostbyname(name);
+ if (!he) {
+ PERROR("can not resolv the hostname");
+ exit(20);
+ }
+ retval = ((struct in_addr *)(he->h_addr_list[0]))->s_addr;
+ }
+ return retval;
+}
+
+int conv_address(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg)
+{
+ struct sockaddr_in addr;
+ int addr_len = sizeof(struct sockaddr_in);
+
+ addr.sin_port = htons(port_part(arg));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = resolv(addr_part(arg));
+
+ switch(ad->tag) {
+ case T_my_addr:
+ add_tag(tl,T_my_addr,&addr,addr_len);
+ add_tag(tl,T_my_addr_len,&addr_len,sizeof(addr_len));
+ break;
+ case T_peer_addr:
+ add_tag(tl,T_peer_addr,&addr,addr_len);
+ add_tag(tl,T_peer_addr_len,&addr_len,sizeof(addr_len));
+ break;
+ default:
+ fprintf(stderr, "internal error in conv_address()\n");
+ }
+
+ return 0;
+}
+
+int conv_protocol(struct drbd_argument *ad, struct drbd_tag_list *tl, char* arg)
+{
+ int prot;
+
+ if(!strcmp(arg,"A") || !strcmp(arg,"a")) {
+ prot=DRBD_PROT_A;
+ } else if (!strcmp(arg,"B") || !strcmp(arg,"b")) {
+ prot=DRBD_PROT_B;
+ } else if (!strcmp(arg,"C") || !strcmp(arg,"c")) {
+ prot=DRBD_PROT_C;
+ } else {
+ fprintf(stderr, "'%s' is no valid protocol.\n", arg);
+ return 20;
+ }
+
+ add_tag(tl,ad->tag,&prot,sizeof(prot));
+
+ return 0;
+}
+
+int conv_bit(struct drbd_option *od, struct drbd_tag_list *tl, char* arg)
+{
+ char bit=1;
+
+ add_tag(tl,od->tag,&bit,sizeof(bit));
+
+ return 0;
+}
+
+int conv_numeric(struct drbd_option *od, struct drbd_tag_list *tl, char* arg)
+{
+ const unsigned long long min = od->numeric_param.min;
+ const unsigned long long max = od->numeric_param.max;
+ const unsigned char default_unit = od->numeric_param.default_unit;
+ unsigned long long l;
+ int i;
+ char unit[] = {0,0};
+
+
+ l = m_strtoll(arg, default_unit);
+
+ if (min > l || l > max) {
+ unit[0] = default_unit > 1 ? default_unit : 0;
+ fprintf(stderr,"%s %s => %llu%s out of range [%llu..%llu]%s\n",
+ od->name, arg, l, unit, min, max, unit);
+ return(20);
+ }
+
+ switch(tag_type(od->tag)) {
+ case TT_INT64:
+ add_tag(tl,od->tag,&l,sizeof(l));
+ break;
+ case TT_INTEGER:
+ i=l;
+ add_tag(tl,od->tag,&i,sizeof(i));
+ break;
+ default:
+ fprintf(stderr, "internal error in conv_numeric()\n");
+ }
+ return 0;
+
+}
+
+int conv_handler(struct drbd_option *od, struct drbd_tag_list *tl, char* arg)
+{
+ const char** handler_names = od->handler_param.handler_names;
+ const int number_of_handlers = od->handler_param.number_of_handlers;
+ int i,nr;
+
+ for(i=0;i<number_of_handlers;i++) {
+ if(strcmp(arg,handler_names[i])==0) {
+ nr = i;
+ break;
+ }
+ }
+
+ add_tag(tl,od->tag,&nr,sizeof(nr));
+
+ return 0;
+}
+
+struct option * make_longoptions(struct drbd_option* od)
+{
+ static struct option buffer[20];
+ int i=0;
+
+ while(od->name) {
+ buffer[i].name = od->name;
+ buffer[i].has_arg = tag_type(od->tag) == TT_BIT ?
+ no_argument : required_argument ;
+ buffer[i].flag = NULL;
+ buffer[i].val = od->short_name;
+ if(i++ == 20) {
+ fprintf(stderr,"buffer in make_longoptions to small.\n");
+ }
+ od++;
+ }
+ buffer[i].name = NULL;
+ buffer[i].has_arg = 0;
+ buffer[i].flag = NULL;
+ buffer[i].val = 0;
+
+ return buffer;
+}
+
+struct drbd_option *find_opt_by_short_name(struct drbd_option *od, int c)
+{
+ while(od->name) {
+ if(od->short_name == c) return od;
+ od++;
+ }
+
+ return NULL;
+}
+
+int generic_config_cmd(struct drbd_cmd *cm, int argc, char **argv)
+{
+ struct drbd_argument *ad = cm->args;
+ struct drbd_option *od;
+ static struct option *lo;
+ struct drbd_tag_list *tl;
+ int c,i=0,rv=0;
+
+ tl = create_tag_list(4096);
+
+ while(ad->name) {
+ if(argc < i+1) {
+ fprintf(stderr,"Missing argument '%s'\n", ad->name);
+ print_command_usage(cm-commands, "");
+ rv=20;
+ break;
+ }
+ rv |= ad->convert_function(ad,tl,argv[i++]);
+ if(rv) break;
+ ad++;
+ }
+
+ lo = make_longoptions(cm->options);
+ while( (c=getopt_long(argc,argv,make_optstring(lo,0),lo,0)) != -1 ) {
+ od = find_opt_by_short_name(cm->options,c);
+ if(od) rv |= od->convert_function(od,tl,optarg);
+ else {
+ fprintf(stderr,"opt for short '%c' (%d) not found\n",
+ c,c);
+ rv=20;
+ }
+ if(rv) break;
+ }
+
+ if(rv == 0) dump_tag_list(tl);
+ free_tag_list(tl);
+
+ return rv;
+}
+
+
+void print_command_usage(int i, const char *addinfo)
+ // CAUTION no range check for i
+{
+ struct drbd_argument *args;
+ struct drbd_option *options;
+#define maxcol 70 // plus initial tab ...
+ static char line[maxcol+1];
+ int col,prevcol;
+
+ prevcol=col=0;
+
+ col += snprintf(line+col, maxcol-col, " %s", commands[i].cmd);
+ if ((args = commands[i].args)) {
+ while (args->name) {
+ col += snprintf(line+col, maxcol-col, " %s", args->name);
+ args++;
+ }
+
+ }
+ if (col > maxcol) {
+ printf("%s\n\t",line);
+ col=0;
+ }
+ prevcol=col;
+ if ((options = commands[i].options)) {
+ while (options->name) {
+ if (tag_type(options->tag) == TT_BIT) {
+ col += snprintf(line+col, maxcol-col,
+ " [{--%s|-%c}]",
+ options->name, options->short_name);
+ } else {
+ col += snprintf(line+col, maxcol-col,
+ " [{--%s|-%c} val]",
+ options->name, options->short_name);
+ }
+ if (col >= maxcol) {
+ line[prevcol]=0;
+ printf("%s\n\t",line);
+ prevcol=col=0;
+ } else {
+ prevcol=col;
+ options++;
+ }
+ }
+ }
+ line[col]=0;
+ printf("%s\n",line);
+ if (addinfo) {
+ printf("%s\n",addinfo);
+ exit(20);
+ }
+}
+
+
+void print_usage(const char* addinfo)
+{
+ size_t i;
+
+ printf("\nUSAGE: %s device command arguments options\n\n"
+ "Device is usually /dev/drbdX or /dev/drbd/X.\n"
+ "Commands, arguments and options are:\n",cmdname);
+
+
+ for (i = 0; i < ARRY_SIZE(commands); i++)
+ print_command_usage(i, 0);
+
+ printf("\nAvailable on-io-error handlers:");
+ for(i=0;i<ARRY_SIZE(on_error);i++) {
+ printf(" %s",on_error[i]);
+ if(i < ARRY_SIZE(on_error)-1) printf(",");
+ }
+
+ printf("\nAvailable fencing policies:");
+ for(i=0;i<ARRY_SIZE(fencing_n);i++) {
+ printf(" %s",fencing_n[i]);
+ if(i < ARRY_SIZE(fencing_n)-1) printf(",");
+ }
+ /*
+ printf("\n\nVersion: "REL_VERSION" (api:%d)\n%s\n",
+ API_VERSION, drbd_buildtag());
+ */
+ if (addinfo)
+ printf("\n%s\n",addinfo);
+
+ exit(20);
+}
+
+int main(int argc, char** argv)
+{
+ int help = 0;
+ unsigned int i;
+
+ if ( (cmdname = strrchr(argv[0],'/')) )
+ argv[0] = ++cmdname;
+ else
+ cmdname = argv[0];
+
+ /* == '-' catches -h, --help, and similar */
+ if (argc > 1 && (!strcmp(argv[1],"help") || argv[1][0] == '-'))
+ help = 1;
+ if (argc < 3) print_usage(argc==1 ? 0 : " Insufficient arguments");
+
+ chdir("/");
+
+ for(i=0;i<ARRY_SIZE(commands);i++) {
+ if(strcmp(argv[2],commands[i].cmd)==0) {
+ commands[i].function(commands+i,argc-3,argv+3);
+ }
+ }
+
+ return 0;
+}
More information about the drbd-cvs
mailing list